aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWeblate <42@minetest.ru>2013-03-30 19:49:52 +0100
committerWeblate <42@minetest.ru>2013-03-30 19:49:52 +0100
commita0566270d9fa075afa36a7e3e68c690b1b23ba90 (patch)
tree6bc88127ee67b7bf4d6a2d6f9d0a9e5f997d1dd1
parent0d83bdc3aa9f1077836aacb833ac4ad9bbb9a4f4 (diff)
parent1aa50b13622c1e264044839ecdf0152670dae6ce (diff)
downloadminetest-a0566270d9fa075afa36a7e3e68c690b1b23ba90.tar.gz
minetest-a0566270d9fa075afa36a7e3e68c690b1b23ba90.tar.bz2
minetest-a0566270d9fa075afa36a7e3e68c690b1b23ba90.zip
Merge remote branch 'origin/master'
-rw-r--r--.gitignore9
-rw-r--r--CMakeLists.txt7
-rw-r--r--README.txt21
-rw-r--r--builtin/falling.lua8
-rw-r--r--builtin/item.lua13
-rw-r--r--builtin/item_entity.lua1
-rw-r--r--builtin/misc.lua13
-rw-r--r--client/shaders/test_shader_2/opengl_vertex.glsl4
-rw-r--r--cmake/Modules/FindJson.cmake10
-rw-r--r--cmake/Modules/FindOpenGLES2.cmake130
-rw-r--r--doc/lua_api.txt295
-rw-r--r--doc/protocol.txt36
-rw-r--r--games/minimal/mods/default/init.lua2
-rw-r--r--games/minimal/mods/default/mapgen.lua116
-rw-r--r--minetest.conf.example35
-rw-r--r--src/CMakeLists.txt21
-rw-r--r--src/activeobject.h2
-rw-r--r--src/chat.cpp20
-rw-r--r--src/chat.h14
-rw-r--r--src/client.cpp185
-rw-r--r--src/client.h49
-rw-r--r--src/clientmap.cpp55
-rw-r--r--src/clientmap.h8
-rw-r--r--src/clientobject.cpp12
-rw-r--r--src/clientobject.h5
-rw-r--r--src/clientserver.h52
-rw-r--r--src/clouds.cpp6
-rw-r--r--src/clouds.h3
-rw-r--r--src/collision.cpp72
-rw-r--r--src/collision.h6
-rw-r--r--src/connection.cpp254
-rw-r--r--src/connection.h23
-rw-r--r--src/content_abm.cpp56
-rw-r--r--src/content_cao.cpp23
-rw-r--r--src/content_mapblock.cpp271
-rw-r--r--src/content_sao.cpp60
-rw-r--r--src/content_sao.h5
-rw-r--r--src/craftdef.cpp37
-rw-r--r--src/craftdef.h4
-rw-r--r--src/debug.cpp29
-rw-r--r--src/debug.h29
-rw-r--r--src/defaultsettings.cpp34
-rw-r--r--src/defaultsettings.h1
-rw-r--r--src/dungeongen.cpp634
-rw-r--r--src/dungeongen.h128
-rw-r--r--src/emerge.cpp16
-rw-r--r--src/emerge.h3
-rw-r--r--src/environment.cpp400
-rw-r--r--src/environment.h35
-rw-r--r--src/farmesh.cpp8
-rw-r--r--src/game.cpp57
-rw-r--r--src/game.h25
-rw-r--r--src/gettime.h8
-rw-r--r--src/guiChatConsole.cpp2
-rw-r--r--src/guiFormSpecMenu.cpp122
-rw-r--r--src/guiFormSpecMenu.h10
-rw-r--r--src/guiMainMenu.cpp148
-rw-r--r--src/guiMainMenu.h10
-rw-r--r--src/inventory.cpp4
-rw-r--r--src/itemdef.cpp44
-rw-r--r--src/itemdef.h8
-rw-r--r--src/json/CMakeLists.txt4
-rw-r--r--src/keycode.cpp13
-rw-r--r--src/localplayer.cpp40
-rw-r--r--src/localplayer.h9
-rw-r--r--src/main.cpp385
-rw-r--r--src/mainmenumanager.h15
-rw-r--r--src/map.cpp452
-rw-r--r--src/map.h94
-rw-r--r--src/mapblock.cpp4
-rw-r--r--src/mapblock.h3
-rw-r--r--src/mapblock_mesh.cpp175
-rw-r--r--src/mapblock_mesh.h6
-rw-r--r--src/mapgen.cpp3000
-rw-r--r--src/mapgen.h56
-rw-r--r--src/mapgen_indev.cpp371
-rw-r--r--src/mapgen_indev.h152
-rw-r--r--src/mapgen_singlenode.cpp102
-rw-r--r--src/mapgen_singlenode.h53
-rw-r--r--src/mapgen_v6.cpp1760
-rw-r--r--src/mapgen_v6.h110
-rw-r--r--src/mapnode.cpp136
-rw-r--r--src/mapsector.cpp41
-rw-r--r--src/mapsector.h8
-rw-r--r--src/mods.cpp52
-rw-r--r--src/mods.h4
-rw-r--r--src/nodedef.cpp25
-rw-r--r--src/nodedef.h2
-rw-r--r--src/noise.h4
-rw-r--r--src/object_properties.h5
-rw-r--r--src/particles.cpp320
-rw-r--r--src/particles.h72
-rw-r--r--src/porting.h64
-rw-r--r--src/profiler.h63
-rw-r--r--src/scriptapi.cpp6824
-rw-r--r--src/scriptapi.h141
-rw-r--r--src/scriptapi_common.cpp311
-rw-r--r--src/scriptapi_common.h112
-rw-r--r--src/scriptapi_content.cpp322
-rw-r--r--src/scriptapi_content.h37
-rw-r--r--src/scriptapi_craft.cpp454
-rw-r--r--src/scriptapi_craft.h51
-rw-r--r--src/scriptapi_entity.cpp293
-rw-r--r--src/scriptapi_entity.h54
-rw-r--r--src/scriptapi_env.cpp908
-rw-r--r--src/scriptapi_env.h164
-rw-r--r--src/scriptapi_inventory.cpp726
-rw-r--r--src/scriptapi_inventory.h165
-rw-r--r--src/scriptapi_item.cpp718
-rw-r--r--src/scriptapi_item.h166
-rw-r--r--src/scriptapi_node.cpp243
-rw-r--r--src/scriptapi_node.h55
-rw-r--r--src/scriptapi_nodemeta.cpp571
-rw-r--r--src/scriptapi_nodemeta.h123
-rw-r--r--src/scriptapi_nodetimer.cpp166
-rw-r--r--src/scriptapi_nodetimer.h70
-rw-r--r--src/scriptapi_noise.cpp388
-rw-r--r--src/scriptapi_noise.h133
-rw-r--r--src/scriptapi_object.cpp945
-rw-r--r--src/scriptapi_object.h220
-rw-r--r--src/scriptapi_particles.cpp143
-rw-r--r--src/scriptapi_particles.h32
-rw-r--r--src/scriptapi_types.cpp372
-rw-r--r--src/scriptapi_types.h87
-rw-r--r--src/server.cpp655
-rw-r--r--src/server.h98
-rw-r--r--src/serverlist.cpp6
-rw-r--r--src/serverlist.h2
-rw-r--r--src/serverobject.cpp12
-rw-r--r--src/serverobject.h2
-rw-r--r--src/settings.h115
-rw-r--r--src/shader.cpp36
-rw-r--r--src/staticobject.cpp12
-rw-r--r--src/staticobject.h14
-rw-r--r--src/strfnd.h37
-rw-r--r--src/subgame.cpp21
-rw-r--r--src/subgame.h7
-rw-r--r--src/test.cpp43
-rw-r--r--src/tile.cpp78
-rw-r--r--src/tile.h4
-rw-r--r--src/tool.cpp57
-rw-r--r--src/tool.h21
-rw-r--r--src/treegen.cpp93
-rw-r--r--src/treegen.h51
-rw-r--r--src/util/container.h88
-rw-r--r--src/util/numeric.cpp2
-rw-r--r--src/util/numeric.h3
-rw-r--r--src/util/string.h16
-rw-r--r--src/util/thread.h16
-rw-r--r--src/util/timetaker.cpp11
-rw-r--r--src/util/timetaker.h7
-rw-r--r--src/voxel.cpp37
-rw-r--r--src/voxel.h12
-rw-r--r--src/voxelalgorithms.cpp12
-rw-r--r--src/voxelalgorithms.h8
-rw-r--r--textures/base/pack/logo.pngbin0 -> 13156 bytes
-rw-r--r--textures/base/pack/menufooter.pngbin0 -> 356 bytes
-rw-r--r--textures/base/pack/menuheader.pngbin0 -> 578 bytes
-rw-r--r--textures/base/pack/menulogo.pngbin498 -> 0 bytes
-rwxr-xr-xutil/buildbot/buildwin32.sh11
-rw-r--r--util/master/list.js37
-rwxr-xr-xutil/master/master.cgi5
162 files changed, 15518 insertions, 12403 deletions
diff --git a/.gitignore b/.gitignore
index 353032637..21e2371a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,13 +4,16 @@
*bak*
tags
*.vim
+*.orig
+*.rej
## Non-static Minetest directories
/bin/
/games/*
!/games/minimal/
/cache/
-/textures/
+/textures/*
+!/textures/base/
/sounds/
/mods/*
!/mods/minetest/
@@ -41,7 +44,9 @@ src/cguittfont/libcguittfont.a
src/cguittfont/cmake_install.cmake
src/cguittfont/Makefile
src/json/CMakeFiles/
-src/json/libjson.a
+src/json/libjsoncpp.a
+src/sqlite/CMakeFiles/*
+src/sqlite/libsqlite3.a
CMakeCache.txt
CPackConfig.cmake
CPackSourceConfig.cmake
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fbf46d059..437d31cf5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,7 +12,7 @@ set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
set(VERSION_MAJOR 0)
set(VERSION_MINOR 4)
-set(VERSION_PATCH 4-d1)
+set(VERSION_PATCH 5)
if(VERSION_EXTRA)
set(VERSION_PATCH ${VERSION_PATCH}-${VERSION_EXTRA})
endif()
@@ -133,6 +133,11 @@ endif()
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/builtin" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minimal" DESTINATION "${SHAREDIR}/games")
+set(COMMON_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/games/common")
+if(EXISTS ${COMMON_SOURCE} AND IS_DIRECTORY ${COMMON_SOURCE})
+ install(FILES ${COMMON_SOURCE}/README.txt DESTINATION "${SHAREDIR}/games/common/")
+ install(DIRECTORY ${COMMON_SOURCE}/mods DESTINATION "${SHAREDIR}/games/common")
+endif()
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/")
diff --git a/README.txt b/README.txt
index 20917d772..74940a147 100644
--- a/README.txt
+++ b/README.txt
@@ -9,9 +9,10 @@ and contributors (see source file comments and the version control log)
In case you downloaded the source code:
---------------------------------------
If you downloaded the Minetest Engine source code in which this file is
-contained, you probably want to download the minetest_game project too:
+contained, you probably want to download these projects too:
+ https://github.com/minetest/common/
https://github.com/minetest/minetest_game/
-See the README.txt in it.
+See the README.txt in them.
Further documentation
----------------------
@@ -80,17 +81,24 @@ Compiling on GNU/Linux:
-----------------------
Install dependencies. Here's an example for Debian/Ubuntu:
-$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev
+$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev
Download source, extract (this is the URL to the latest of source repository, which might not work at all times):
$ wget https://github.com/minetest/minetest/tarball/master -O master.tar.gz
$ tar xf master.tar.gz
$ cd minetest-minetest-286edd4 (or similar)
+Download common (needed for minetest_game and some others)
+$ cd games/
+$ wget https://github.com/minetest/common/tarball/master -O common.tar.gz
+$ tar xf common.tar.gz
+$ mv minetest-common-* common
+$ cd ..
+
Download minetest_game (otherwise only the "Minimal development test" game is available)
$ cd games/
-$ wget https://github.com/minetest/minetest_game/tarball/master -O master.tar.gz
-$ tar xf master.tar.gz
+$ wget https://github.com/minetest/minetest_game/tarball/master -O minetest_game.tar.gz
+$ tar xf minetest_game.tar.gz
$ mv minetest-minetest_game-* minetest_game
$ cd ..
@@ -107,11 +115,12 @@ $ ./minetest
- You can build a bare server or a bare client by specifying -DBUILD_CLIENT=0 or -DBUILD_SERVER=0
- You can select between Release and Debug build by -DCMAKE_BUILD_TYPE=<Debug or Release>
- Debug build is slower, but gives much more useful output in a debugger
+- If you build a bare server, you don't need to have Irrlicht installed. In that case use -DIRRLICHT_SOURCE_DIR=/the/irrlicht/source
Compiling on Windows:
---------------------
- This section is outdated. In addition to what is described here:
- - In addition to minetest, you need to download minetest_game.
+ - In addition to minetest, you need to download common and minetest_game.
- If you wish to have sound support, you need libogg, libvorbis and libopenal
- You need:
diff --git a/builtin/falling.lua b/builtin/falling.lua
index d3af36f29..1c09f9856 100644
--- a/builtin/falling.lua
+++ b/builtin/falling.lua
@@ -57,6 +57,10 @@ minetest.register_entity("__builtin:falling_node", {
-- Note: walkable is in the node definition, not in item groups
if minetest.registered_nodes[bcn.name] and
minetest.registered_nodes[bcn.name].walkable then
+ if minetest.registered_nodes[bcn.name].buildable_to then
+ minetest.env:remove_node(bcp)
+ return
+ end
local np = {x=bcp.x, y=bcp.y+1, z=bcp.z}
-- Check what's here
local n2 = minetest.env:get_node(np)
@@ -80,6 +84,7 @@ minetest.register_entity("__builtin:falling_node", {
-- Create node and remove entity
minetest.env:add_node(np, {name=self.nodename})
self.object:remove()
+ nodeupdate(np)
else
-- Do nothing
end
@@ -144,7 +149,8 @@ function nodeupdate_single(p)
n_bottom = minetest.env:get_node(p_bottom)
-- Note: walkable is in the node definition, not in item groups
if minetest.registered_nodes[n_bottom.name] and
- not minetest.registered_nodes[n_bottom.name].walkable then
+ (not minetest.registered_nodes[n_bottom.name].walkable or
+ minetest.registered_nodes[n_bottom.name].buildable_to) then
minetest.env:remove_node(p)
spawn_falling_node(p, n.name)
nodeupdate(p)
diff --git a/builtin/item.lua b/builtin/item.lua
index 1349fdf63..8e2f75a1a 100644
--- a/builtin/item.lua
+++ b/builtin/item.lua
@@ -129,11 +129,18 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
end
local under = pointed_thing.under
- local oldnode_under = minetest.env:get_node(under)
+ local oldnode_under = minetest.env:get_node_or_nil(under)
+ local above = pointed_thing.above
+ local oldnode_above = minetest.env:get_node_or_nil(above)
+
+ if not oldnode_under or not oldnode_above then
+ minetest.log("info", placer:get_player_name() .. " tried to place"
+ .. " node in unloaded position " .. minetest.pos_to_string(above))
+ return itemstack
+ end
+
local olddef_under = ItemStack({name=oldnode_under.name}):get_definition()
olddef_under = olddef_under or minetest.nodedef_default
- local above = pointed_thing.above
- local oldnode_above = minetest.env:get_node(above)
local olddef_above = ItemStack({name=oldnode_above.name}):get_definition()
olddef_above = olddef_above or minetest.nodedef_default
diff --git a/builtin/item_entity.lua b/builtin/item_entity.lua
index 1699cb03c..50ce7eafe 100644
--- a/builtin/item_entity.lua
+++ b/builtin/item_entity.lua
@@ -111,6 +111,7 @@ minetest.register_entity("__builtin:item", {
if self.itemstring ~= '' then
local left = hitter:get_inventory():add_item("main", self.itemstring)
if not left:is_empty() then
+ self.itemstring = left:to_string()
return
end
end
diff --git a/builtin/misc.lua b/builtin/misc.lua
index e018aff85..8308b3d6b 100644
--- a/builtin/misc.lua
+++ b/builtin/misc.lua
@@ -14,14 +14,14 @@ minetest.register_globalstep(function(dtime)
for index, timer in ipairs(minetest.timers) do
timer.time = timer.time - dtime
if timer.time <= 0 then
- timer.func(timer.param)
+ timer.func(unpack(timer.args or {}))
table.remove(minetest.timers,index)
end
end
end)
-function minetest.after(time, func, param)
- table.insert(minetest.timers_to_add, {time=time, func=func, param=param})
+function minetest.after(time, func, ...)
+ table.insert(minetest.timers_to_add, {time=time, func=func, args={...}})
end
function minetest.check_player_privs(name, privs)
@@ -99,3 +99,10 @@ function minetest.setting_get_pos(name)
return minetest.string_to_pos(value)
end
+function minetest.formspec_escape(str)
+ str = string.gsub(str, "\\", "\\\\")
+ str = string.gsub(str, "%[", "\\[")
+ str = string.gsub(str, "%]", "\\]")
+ return str
+end
+
diff --git a/client/shaders/test_shader_2/opengl_vertex.glsl b/client/shaders/test_shader_2/opengl_vertex.glsl
index 80fd6d427..2881bad21 100644
--- a/client/shaders/test_shader_2/opengl_vertex.glsl
+++ b/client/shaders/test_shader_2/opengl_vertex.glsl
@@ -8,9 +8,7 @@ varying vec3 vPosition;
void main(void)
{
- vec4 pos = gl_Vertex;
- pos.y -= 2.0;
- gl_Position = mWorldViewProj * pos;
+ gl_Position = mWorldViewProj * gl_Vertex;
vPosition = (mWorldViewProj * gl_Vertex).xyz;
diff --git a/cmake/Modules/FindJson.cmake b/cmake/Modules/FindJson.cmake
index bc4e71a29..a9178a225 100644
--- a/cmake/Modules/FindJson.cmake
+++ b/cmake/Modules/FindJson.cmake
@@ -2,17 +2,17 @@
#FIND_PATH(JSON_INCLUDE_DIR json.h)
-#FIND_LIBRARY(JSON_LIBRARY NAMES json)
+#FIND_LIBRARY(JSON_LIBRARY NAMES jsoncpp)
#IF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
# SET( JSON_FOUND TRUE )
#ENDIF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
#IF(JSON_FOUND)
-# MESSAGE(STATUS "Found system json header file in ${JSON_INCLUDE_DIR}")
-# MESSAGE(STATUS "Found system json library ${JSON_LIBRARY}")
+# MESSAGE(STATUS "Found system jsoncpp header file in ${JSON_INCLUDE_DIR}")
+# MESSAGE(STATUS "Found system jsoncpp library ${JSON_LIBRARY}")
#ELSE(JSON_FOUND)
SET(JSON_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/json)
- SET(JSON_LIBRARY json)
- MESSAGE(STATUS "Using project json library")
+ SET(JSON_LIBRARY jsoncpp)
+ MESSAGE(STATUS "Using project jsoncpp library")
#ENDIF(JSON_FOUND)
diff --git a/cmake/Modules/FindOpenGLES2.cmake b/cmake/Modules/FindOpenGLES2.cmake
new file mode 100644
index 000000000..42d31c898
--- /dev/null
+++ b/cmake/Modules/FindOpenGLES2.cmake
@@ -0,0 +1,130 @@
+#-------------------------------------------------------------------
+# This file is stolen from part of the CMake build system for OGRE (Object-oriented Graphics Rendering Engine) http://www.ogre3d.org/
+#
+# The contents of this file are placed in the public domain. Feel
+# free to make use of it in any way you like.
+#-------------------------------------------------------------------
+
+# - Try to find OpenGLES and EGL
+# Once done this will define
+#
+# OPENGLES2_FOUND - system has OpenGLES
+# OPENGLES2_INCLUDE_DIR - the GL include directory
+# OPENGLES2_LIBRARIES - Link these to use OpenGLES
+#
+# EGL_FOUND - system has EGL
+# EGL_INCLUDE_DIR - the EGL include directory
+# EGL_LIBRARIES - Link these to use EGL
+
+# win32, apple, android NOT TESED
+# linux tested and works
+
+IF (WIN32)
+ IF (CYGWIN)
+
+ FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h )
+
+ FIND_LIBRARY(OPENGLES2_gl_LIBRARY libGLESv2 )
+
+ ELSE (CYGWIN)
+
+ IF(BORLAND)
+ SET (OPENGLES2_gl_LIBRARY import32 CACHE STRING "OpenGL ES 2.x library for win32")
+ ELSE(BORLAND)
+ # todo
+ # SET (OPENGLES_gl_LIBRARY ${SOURCE_DIR}/Dependencies/lib/release/libGLESv2.lib CACHE STRING "OpenGL ES 2.x library for win32"
+ ENDIF(BORLAND)
+
+ ENDIF (CYGWIN)
+
+ELSE (WIN32)
+
+ IF (APPLE)
+
+ create_search_paths(/Developer/Platforms)
+ findpkg_framework(OpenGLES2)
+ set(OPENGLES2_gl_LIBRARY "-framework OpenGLES")
+
+ ELSE(APPLE)
+
+ FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h
+ /usr/openwin/share/include
+ /opt/graphics/OpenGL/include /usr/X11R6/include
+ /usr/include
+ )
+
+ FIND_LIBRARY(OPENGLES2_gl_LIBRARY
+ NAMES GLESv2
+ PATHS /opt/graphics/OpenGL/lib
+ /usr/openwin/lib
+ /usr/shlib /usr/X11R6/lib
+ /usr/lib
+ )
+
+ IF (NOT BUILD_ANDROID)
+ FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h
+ /usr/openwin/share/include
+ /opt/graphics/OpenGL/include /usr/X11R6/include
+ /usr/include
+ )
+
+ FIND_LIBRARY(EGL_egl_LIBRARY
+ NAMES EGL
+ PATHS /opt/graphics/OpenGL/lib
+ /usr/openwin/lib
+ /usr/shlib /usr/X11R6/lib
+ /usr/lib
+ )
+
+ # On Unix OpenGL most certainly always requires X11.
+ # Feel free to tighten up these conditions if you don't
+ # think this is always true.
+ # It's not true on OSX.
+
+ IF (OPENGLES2_gl_LIBRARY)
+ IF(NOT X11_FOUND)
+ INCLUDE(FindX11)
+ ENDIF(NOT X11_FOUND)
+ IF (X11_FOUND)
+ IF (NOT APPLE)
+ SET (OPENGLES2_LIBRARIES ${X11_LIBRARIES})
+ ENDIF (NOT APPLE)
+ ENDIF (X11_FOUND)
+ ENDIF (OPENGLES2_gl_LIBRARY)
+ ENDIF ()
+
+ ENDIF(APPLE)
+ENDIF (WIN32)
+
+#SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
+
+IF (BUILD_ANDROID)
+ IF(OPENGLES2_gl_LIBRARY)
+ SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
+ SET( EGL_LIBRARIES)
+ SET( OPENGLES2_FOUND "YES" )
+ ENDIF(OPENGLES2_gl_LIBRARY)
+ELSE ()
+
+ SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
+
+ IF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY)
+ SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
+ SET( EGL_LIBRARIES ${EGL_egl_LIBRARY} ${EGL_LIBRARIES})
+ SET( OPENGLES2_FOUND "YES" )
+ ENDIF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY)
+
+ENDIF ()
+
+MARK_AS_ADVANCED(
+ OPENGLES2_INCLUDE_DIR
+ OPENGLES2_gl_LIBRARY
+ EGL_INCLUDE_DIR
+ EGL_egl_LIBRARY
+)
+
+IF(OPENGLES2_FOUND)
+ MESSAGE(STATUS "Found system opengles2 library ${OPENGLES2_LIBRARIES}")
+ELSE ()
+ SET(OPENGLES2_LIBRARIES "")
+ENDIF ()
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 005d7c010..beb70db15 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -1,4 +1,4 @@
-Minetest Lua Modding API Reference 0.4.4
+Minetest Lua Modding API Reference 0.4.5
==========================================
More information at http://c55.me/minetest/
@@ -27,6 +27,39 @@ Startup
Mods are loaded during server startup from the mod load paths by running
the init.lua scripts in a shared environment.
+Paths
+-----
+RUN_IN_PLACE=1: (Windows release, local build)
+ $path_user: Linux: <build directory>
+ Windows: <build directory>
+ $path_share: Linux: <build directory>
+ Windows: <build directory>
+
+RUN_IN_PLACE=0: (Linux release)
+ $path_share: Linux: /usr/share/minetest
+ Windows: <install directory>/minetest-0.4.x
+ $path_user: Linux: ~/.minetest
+ Windows: C:/users/<user>/AppData/minetest (maybe)
+
+Games
+-----
+Games are looked up from:
+ $path_share/games/gameid/
+ $path_user/games/gameid/
+where gameid is unique to each game.
+
+The game directory contains the file game.conf, which contains these fields:
+ name = <Human-readable full name of the game>
+ common_mods = <Comma-separated list of common mods>
+eg.
+ name = Minetest
+ common_mods = bucket, default, doors, fire, stairs
+
+Common mods are loaded from the pseudo-game "common".
+
+The game directory can contain the file minetest.conf, which will be used
+to set default settings when running the particular game.
+
Mod load path
-------------
Generic:
@@ -170,18 +203,18 @@ from the available ones of the following files:
Examples of sound parameter tables:
-- Play locationless on all clients
{
- gain = 1.0, -- default
+ gain = 1.0, -- default
}
-- Play locationless to a player
{
- to_player = name,
- gain = 1.0, -- default
+ to_player = name,
+ gain = 1.0, -- default
}
-- Play in a location
{
- pos = {x=1,y=2,z=3},
- gain = 1.0, -- default
- max_hear_distance = 32, -- default
+ pos = {x=1,y=2,z=3},
+ gain = 1.0, -- default
+ max_hear_distance = 32, -- default
}
-- Play connected to an object, looped
{
@@ -233,11 +266,11 @@ local drawtype = get_nodedef_field(nodename, "drawtype")
Example: minetest.get_item_group(name, group) has been implemented as:
function minetest.get_item_group(name, group)
- if not minetest.registered_items[name] or not
- minetest.registered_items[name].groups[group] then
- return 0
- end
- return minetest.registered_items[name].groups[group]
+ if not minetest.registered_items[name] or not
+ minetest.registered_items[name].groups[group] then
+ return 0
+ end
+ return minetest.registered_items[name].groups[group]
end
Nodes
@@ -277,6 +310,10 @@ param2 is reserved for the engine when any of these are used:
paramtype2 == "facedir"
^ The rotation of the node is stored in param2. Furnaces and chests are
rotated this way. Can be made by using minetest.dir_to_facedir().
+ Values range 0 - 23
+ facedir modulo 4 = axisdir
+ 0 = y+ 1 = z+ 2 = z- 3 = x+ 4 = x- 5 = y-
+ facedir's two less significant bits are rotation around the axis
Nodes can also contain extra data. See "Node Metadata".
@@ -335,6 +372,28 @@ A box is defined as:
A box of a regular node would look like:
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
+Ore types
+---------------
+These tell in what manner the ore is generated.
+All default ores are of the uniformly-distributed scatter type.
+
+- scatter
+ Randomly chooses a location and generates a cluster of ore.
+ If noise_params is specified, the ore will be placed if the 3d perlin noise at
+ that point is greater than the noise_threshhold, giving the ability to create a non-equal
+ distribution of ore.
+- sheet
+ Creates a sheet of ore in a blob shape according to the 2d perlin noise described by noise_params.
+ The relative height of the sheet can be controlled by the same perlin noise as well, by specifying
+ a non-zero 'scale' parameter in noise_params. IMPORTANT: The noise is not transformed by offset or
+ scale when comparing against the noise threshhold, but scale is used to determine relative height.
+ The height of the blob is randomly scattered, with a maximum height of clust_size.
+ clust_scarcity and clust_num_ores are ignored.
+ This is essentially an improved version of the so-called "stratus" ore seen in some unofficial mods.
+- claylike - NOT YET IMPLEMENTED
+ Places ore if there are no more than clust_scarcity number of specified nodes within a Von Neumann
+ neighborhood of clust_size radius.
+
Representations of simple things
--------------------------------
Position/vector:
@@ -412,9 +471,11 @@ a node is destroyable and how long it takes to destroy by a tool.
Groups of entities
-------------------
For entities, groups are, as of now, used only for calculating damage.
+The rating is the percentage of damage caused by tools with this damage group.
+See "Entity damage mechanism".
-object.get_armor_groups() -> a group-rating table (eg. {fleshy=3})
-object.set_armor_groups({level=2, fleshy=2, cracky=2})
+object.get_armor_groups() -> a group-rating table (eg. {fleshy=100})
+object.set_armor_groups({fleshy=30, cracky=80})
Groups of tools
----------------
@@ -435,7 +496,7 @@ An example: Make meat soup from any meat, any water and any bowl
}
An another example: Make red wool from white wool and red dye
{
- type = 'shapeless',
+ type = 'shapeless',
output = 'wool:red',
recipe = {'wool:white', 'group:dye,basecolor_red'},
}
@@ -446,7 +507,7 @@ Special groups
- level: Can be used to give an additional sense of progression in the game.
- A larger level will cause eg. a weapon of a lower level make much less
damage, and get weared out much faster, or not be able to get drops
- from destroyed nodes.
+ from destroyed nodes.
- 0 is something that is directly accessible at the start of gameplay
- There is no upper limit
- dig_immediate: (player can always pick up node without tool wear)
@@ -463,7 +524,6 @@ Special groups
Known damage and digging time defining groups
----------------------------------------------
-Valid ratings for these are 0, 1, 2 and 3, unless otherwise stated.
- crumbly: dirt, sand
- cracky: tough but crackable stuff like stone.
- snappy: something that can be cut using fine tools; eg. leaves, small
@@ -516,6 +576,7 @@ groups to enable interaction with tools.
* Uses (until the tool breaks)
* Maximum level (usually 0, 1, 2 or 3)
* Digging times
+ * Damage groups
**Full punch interval**:
When used as a weapon, the tool will do full damage if this time is spent
@@ -547,17 +608,19 @@ maximum level.
result in the tool to be able to dig nodes that have a rating of 2 or 3
for this group, and unable to dig the rating 1, which is the toughest.
Unless there is a matching group that enables digging otherwise.
- * For entities, damage equals the amount of nodes dug in the time spent
- between hits, with a maximum time of ''full_punch_interval''.
+
+**Damage groups**
+List of damage for groups of entities. See "Entity damage mechanism".
Example definition of the capabilities of a tool
-------------------------------------------------
tool_capabilities = {
- full_punch_interval=1.5,
- max_drop_level=1,
- groupcaps={
- crumbly={maxlevel=2, uses=20, times={[1]=1.60, [2]=1.20, [3]=0.80}}
- }
+ full_punch_interval=1.5,
+ max_drop_level=1,
+ groupcaps={
+ crumbly={maxlevel=2, uses=20, times={[1]=1.60, [2]=1.20, [3]=0.80}}
+ }
+ damage_groups = {fleshy=2},
}
This makes the tool be able to dig nodes that fullfill both of these:
@@ -588,10 +651,12 @@ Notes:
Entity damage mechanism
------------------------
Damage calculation:
-- Take the time spent after the last hit
-- Limit time to full_punch_interval
-- Take the damage groups and imagine a bunch of nodes that have them
-- Damage in HP is the amount of nodes destroyed in this time.
+damage = 0
+foreach group in cap.damage_groups:
+ damage += cap.damage_groups[group] * limit(actual_interval / cap.full_punch_interval, 0.0, 1.0)
+ * (object.armor_groups[group] / 100.0)
+ -- Where object.armor_groups[group] is 0 for inexisting values
+return damage
Client predicts damage based on damage groups. Because of this, it is able to
give an immediate response when an entity is damaged or dies; the response is
@@ -717,7 +782,7 @@ field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
^ default is the default value of the field
^ default may contain variable references such as '${text}' which
will fill the value from the metadata value 'text'
- ^ Note: no extra text or more than a single variable is supported ATM.
+ ^ Note: no extra text or more than a single variable is supported ATM.
field[<name>;<label>;<default>]
^ as above but without position/size units
@@ -778,6 +843,9 @@ string:trim()
minetest.pos_to_string({x=X,y=Y,z=Z}) -> "(X,Y,Z)"
^ Convert position to a printable string
minetest.string_to_pos(string) -> position
+^ Same but in reverse
+minetest.formspec_escape(string) -> string
+^ escapes characters like [, ], and \ that can not be used in formspecs
minetest namespace reference
-----------------------------
@@ -804,6 +872,7 @@ minetest.register_tool(name, item definition)
minetest.register_craftitem(name, item definition)
minetest.register_alias(name, convert_to)
minetest.register_craft(recipe)
+minetest.register_ore(ore definition)
Global callback registration functions: (Call these only at load time)
minetest.register_globalstep(func(dtime))
@@ -919,12 +988,17 @@ minetest.get_craft_result(input) -> output, decremented_input
^ output.time = number, if unsuccessful: 0
^ decremented_input = like input
minetest.get_craft_recipe(output) -> input
+^ returns last registered recipe for output item (node)
^ output is a node or item type such as 'default:torch'
^ input.method = 'normal' or 'cooking' or 'fuel'
^ input.width = for example 3
^ input.items = for example { stack 1, stack 2, stack 3, stack 4,
stack 5, stack 6, stack 7, stack 8, stack 9 }
^ input.items = nil if no recipe found
+minetest.get_all_craft_recipes(output) -> table or nil
+^ returns table with all registered recipes for output item (node)
+^ returns nil if no recipe was found
+^ table entries have same format as minetest.get_craft_recipe
minetest.handle_node_drops(pos, drops, digger)
^ drops: list of itemstrings
^ Handles drops from nodes after digging: Default action is to put them into
@@ -969,9 +1043,9 @@ minetest.sound_play(spec, parameters) -> handle
minetest.sound_stop(handle)
Timing:
-minetest.after(time, func, param)
+minetest.after(time, func, ...)
^ Call function after time seconds
-^ param is optional; to pass multiple parameters, pass a table.
+^ Optional: Variable number of arguments that are passed to func
Server:
minetest.request_shutdown() -> request for server shutdown
@@ -983,6 +1057,37 @@ minetest.get_ban_description(ip_or_name) -> ban description (string)
minetest.ban_player(name) -> ban a player
minetest.unban_player_or_ip(name) -> unban player or IP address
+Particles:
+minetest.add_particle(pos, velocity, acceleration, expirationtime,
+ size, collisiondetection, texture, playername)
+^ Spawn particle at pos with velocity and acceleration
+^ Disappears after expirationtime seconds
+^ collisiondetection: if true collides with physical objects
+^ Uses texture (string)
+^ Playername is optional, if specified spawns particle only on the player's client
+
+minetest.add_particlespawner(amount, time,
+ minpos, maxpos,
+ minvel, maxvel,
+ minacc, maxacc,
+ minexptime, maxexptime,
+ minsize, maxsize,
+ collisiondetection, texture, playername)
+^ Add a particlespawner, an object that spawns an amount of particles over time seconds
+^ The particle's properties are random values in between the boundings:
+^ minpos/maxpos, minvel/maxvel (velocity), minacc/maxacc (acceleration),
+^ minsize/maxsize, minexptime/maxexptime (expirationtime)
+^ collisiondetection: if true uses collisiondetection
+^ Uses texture (string)
+^ Playername is optional, if specified spawns particle only on the player's client
+^ If time is 0 has infinite lifespan and spawns the amount on a per-second base
+^ Returns and id
+
+minetest.delete_particlespawner(id, player)
+^ Delete ParticleSpawner with id (return value from add_particlespawner)
+^ If playername is specified, only deletes on the player's client,
+^ otherwise on all clients
+
Random:
minetest.get_connected_players() -> list of ObjectRefs
minetest.hash_node_position({x=,y=,z=}) -> 48-bit integer
@@ -1196,9 +1301,15 @@ methods:
- set_wielded_item(item): replaces the wielded item, returns true if successful
- set_armor_groups({group1=rating, group2=rating, ...})
- set_animation({x=1,y=1}, frame_speed=15, frame_blend=0)
-- set_attach(parent, "", {x=0,y=0,z=0}, {x=0,y=0,z=0})
+- set_attach(parent, bone, position, rotation)
+ ^ bone = string
+ ^ position = {x=num, y=num, z=num} (relative)
+ ^ rotation = {x=num, y=num, z=num}
- set_detach()
-- set_bone_position("", {x=0,y=0,z=0}, {x=0,y=0,z=0})
+- set_bone_position(bone, position, rotation)
+ ^ bone = string
+ ^ position = {x=num, y=num, z=num} (relative)
+ ^ rotation = {x=num, y=num, z=num}
- set_properties(object property table)
LuaEntitySAO-only: (no-op for other objects)
- setvelocity({x=num, y=num, z=num})
@@ -1220,15 +1331,17 @@ Player-only: (no-op for other objects)
- get_look_dir(): get camera direction as a unit vector
- get_look_pitch(): pitch in radians
- get_look_yaw(): yaw in radians (wraps around pretty randomly as of now)
+- set_look_pitch(radians): sets look pitch
+- set_look_yaw(radians): sets look yaw
- set_inventory_formspec(formspec)
^ Redefine player's inventory form
^ Should usually be called in on_joinplayer
- get_inventory_formspec() -> formspec string
- get_player_control(): returns table with player pressed keys
- {jump=bool,right=bool,left=bool,LMB=bool,RMB=bool,sneak=bool,aux1=bool,down=bool,up=bool}
+ {jump=bool,right=bool,left=bool,LMB=bool,RMB=bool,sneak=bool,aux1=bool,down=bool,up=bool}
- get_player_control_bits(): returns integer with bit packed player pressed keys
- bit nr/meaning: 0/up ,1/down ,2/left ,3/right ,4/jump ,5/aux1 ,6/sneak ,7/LMB ,8/RMB
-
+ bit nr/meaning: 0/up ,1/down ,2/left ,3/right ,4/jump ,5/aux1 ,6/sneak ,7/LMB ,8/RMB
+
InvRef: Reference to an inventory
methods:
- is_empty(listname): return true if list is empty
@@ -1313,8 +1426,8 @@ Registered entities
^ puncher: ObjectRef (can be nil)
^ time_from_last_punch: Meant for disallowing spamming of clicks (can be nil)
^ tool_capabilities: capability table of used tool (can be nil)
- ^ dir: unit vector of direction of punch. Always defined. Points from
- the puncher to the punched.
+ ^ dir: unit vector of direction of punch. Always defined. Points from
+ the puncher to the punched.
- on_rightclick(self, clicker)
- get_staticdata(self)
^ Should return a string that will be passed to on_activate when
@@ -1389,10 +1502,10 @@ Item definition (register_node, register_craftitem, register_tool)
max_drop_level=0,
groupcaps={
-- For example:
- fleshy={times={[2]=0.80, [3]=0.40}, maxwear=0.05, maxlevel=1},
snappy={times={[2]=0.80, [3]=0.40}, maxwear=0.05, maxlevel=1},
choppy={times={[3]=0.90}, maxwear=0.05, maxlevel=0}
- }
+ },
+ damage_groups = {groupname=damage},
}
node_placement_prediction = nil,
^ If nil and item is node, prediction is made automatically
@@ -1401,6 +1514,9 @@ Item definition (register_node, register_craftitem, register_tool)
^ Otherwise should be name of node which the client immediately places
on ground when the player places the item. Server will always update
actual result to client in a short moment.
+ sound = {
+ place = <SimpleSoundSpec>,
+ }
on_place = func(itemstack, placer, pointed_thing),
^ Shall place item and return the leftover itemstack
@@ -1435,10 +1551,10 @@ Node definition (register_node)
drawtype = "normal", -- See "Node drawtypes"
visual_scale = 1.0,
tiles = {tile definition 1, def2, def3, def4, def5, def6},
- ^ Textures of node; +Y, -Y, +X, -X, +Z, -Z (old field name: tile_images)
+ ^ Textures of node; +Y, -Y, +X, -X, +Z, -Z (old field name: tile_images)
^ List can be shortened to needed length
special_tiles = {tile definition 1, Tile definition 2},
- ^ Special textures of node; used rarely (old field name: special_materials)
+ ^ Special textures of node; used rarely (old field name: special_materials)
^ List can be shortened to needed length
alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0}, -- If player is inside node
@@ -1468,6 +1584,7 @@ Node definition (register_node)
footstep = <SimpleSoundSpec>,
dig = <SimpleSoundSpec>, -- "__group" = group-based sound (default)
dug = <SimpleSoundSpec>,
+ place = <SimpleSoundSpec>,
},
on_construct = func(pos),
@@ -1494,7 +1611,7 @@ Node definition (register_node)
can_dig = function(pos,player)
^ returns true if node can be dug, or false if not
^ default: nil
-
+
on_punch = func(pos, node, puncher),
^ default: minetest.node_punch
^ By default: does nothing
@@ -1517,32 +1634,32 @@ Node definition (register_node)
^ Called when an UI form (eg. sign text input) returns data
^ default: nil
- allow_metadata_inventory_move = func(pos, from_list, from_index,
- to_list, to_index, count, player),
- ^ Called when a player wants to move items inside the inventory
- ^ Return value: number of items allowed to move
-
- allow_metadata_inventory_put = func(pos, listname, index, stack, player),
- ^ Called when a player wants to put something into the inventory
- ^ Return value: number of items allowed to put
- ^ Return value: -1: Allow and don't modify item count in inventory
+ allow_metadata_inventory_move = func(pos, from_list, from_index,
+ to_list, to_index, count, player),
+ ^ Called when a player wants to move items inside the inventory
+ ^ Return value: number of items allowed to move
+
+ allow_metadata_inventory_put = func(pos, listname, index, stack, player),
+ ^ Called when a player wants to put something into the inventory
+ ^ Return value: number of items allowed to put
+ ^ Return value: -1: Allow and don't modify item count in inventory
- allow_metadata_inventory_take = func(pos, listname, index, stack, player),
- ^ Called when a player wants to take something out of the inventory
- ^ Return value: number of items allowed to take
- ^ Return value: -1: Allow and don't modify item count in inventory
-
- on_metadata_inventory_move = func(pos, from_list, from_index,
- to_list, to_index, count, player),
- on_metadata_inventory_put = func(pos, listname, index, stack, player),
- on_metadata_inventory_take = func(pos, listname, index, stack, player),
- ^ Called after the actual action has happened, according to what was allowed.
- ^ No return value
+ allow_metadata_inventory_take = func(pos, listname, index, stack, player),
+ ^ Called when a player wants to take something out of the inventory
+ ^ Return value: number of items allowed to take
+ ^ Return value: -1: Allow and don't modify item count in inventory
+
+ on_metadata_inventory_move = func(pos, from_list, from_index,
+ to_list, to_index, count, player),
+ on_metadata_inventory_put = func(pos, listname, index, stack, player),
+ on_metadata_inventory_take = func(pos, listname, index, stack, player),
+ ^ Called after the actual action has happened, according to what was allowed.
+ ^ No return value
- on_blast = func(pos, intensity),
- ^ intensity: 1.0 = mid range of regular TNT
- ^ If defined, called when an explosion touches the node, instead of
- removing the node
+ on_blast = func(pos, intensity),
+ ^ intensity: 1.0 = mid range of regular TNT
+ ^ If defined, called when an explosion touches the node, instead of
+ removing the node
}
Recipe for register_craft: (shaped)
@@ -1591,6 +1708,28 @@ Recipe for register_craft (furnace fuel)
burntime = 1,
}
+Ore definition (register_ore)
+{
+ ore_type = "scatter" -- See "Ore types"
+ ore = "default:stone_with_coal",
+ wherein = "default:stone",
+ clust_scarcity = 8*8*8,
+ ^ Ore has a 1 out of clust_scarcity chance of spawning in a node
+ ^ This value should be *MUCH* higher than your intuition might tell you!
+ clust_num_ores = 8,
+ ^ Number of ores in a cluster
+ clust_size = 3,
+ ^ Size of the bounding box of the cluster
+ ^ In this example, there is a 3x3x3 cluster where 8 out of the 27 nodes are coal ore
+ height_min = -31000,
+ height_max = 64,
+ noise_threshhold = 0.5,
+ ^ If noise is above this threshhold, ore is placed. Not needed for a uniform distribution
+ noise_params = {offset=0, scale=1, spread={x=100, y=100, z=100}, seed=23, octaves=3, persist=0.70}
+ ^ NoiseParams structure describing the perlin noise used for ore distribution.
+ ^ Needed for sheet ore_type. Omit from scatter ore_type for a uniform ore distribution
+}
+
Chatcommand definition (register_chatcommand)
{
params = "<name> <privilege>", -- short parameter description
@@ -1601,24 +1740,24 @@ Chatcommand definition (register_chatcommand)
Detached inventory callbacks
{
- allow_move = func(inv, from_list, from_index, to_list, to_index, count, player),
+ allow_move = func(inv, from_list, from_index, to_list, to_index, count, player),
^ Called when a player wants to move items inside the inventory
- ^ Return value: number of items allowed to move
-
+ ^ Return value: number of items allowed to move
+
allow_put = func(inv, listname, index, stack, player),
^ Called when a player wants to put something into the inventory
- ^ Return value: number of items allowed to put
- ^ Return value: -1: Allow and don't modify item count in inventory
+ ^ Return value: number of items allowed to put
+ ^ Return value: -1: Allow and don't modify item count in inventory
allow_take = func(inv, listname, index, stack, player),
^ Called when a player wants to take something out of the inventory
- ^ Return value: number of items allowed to take
- ^ Return value: -1: Allow and don't modify item count in inventory
-
- on_move = func(inv, from_list, from_index, to_list, to_index, count, player),
+ ^ Return value: number of items allowed to take
+ ^ Return value: -1: Allow and don't modify item count in inventory
+
+ on_move = func(inv, from_list, from_index, to_list, to_index, count, player),
on_put = func(inv, listname, index, stack, player),
on_take = func(inv, listname, index, stack, player),
- ^ Called after the actual action has happened, according to what was allowed.
- ^ No return value
+ ^ Called after the actual action has happened, according to what was allowed.
+ ^ No return value
}
diff --git a/doc/protocol.txt b/doc/protocol.txt
index 160f15226..b151f88d8 100644
--- a/doc/protocol.txt
+++ b/doc/protocol.txt
@@ -70,3 +70,39 @@ function check_if_minetestserver_up($host, $port)
return false;
}
+- Here's a Python script for checking if a minetest server is up, confirmed working
+#!/usr/bin/env python
+import sys, time, socket
+address = ""
+port = 30000
+if len(sys.argv) <= 1:
+ print("Usage: %s <address>" % sys.argv[0])
+ exit()
+if ':' in sys.argv[1]:
+ address = sys.argv[1].split(':')[0]
+ try:
+ port = int(sys.argv[1].split(':')[1])
+ except ValueError:
+ print("Please specify a valid port")
+ exit()
+else:
+ address = sys.argv[1]
+
+try:
+ start = time.time()
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.settimeout(2.0)
+ buf = "\x4f\x45\x74\x03\x00\x00\x00\x01"
+ sock.sendto(buf, (address, port))
+ data, addr = sock.recvfrom(1000)
+ if data:
+ peer_id = data[12:14]
+ buf = "\x4f\x45\x74\x03" + peer_id + "\x00\x00\x03"
+ sock.sendto(buf, (address, port))
+ sock.close()
+ end = time.time()
+ print("%s is up (%0.5fms)" % (sys.argv[1],end-start))
+ else:
+ print("%s seems to be down " % sys.argv[1])
+except:
+ print("%s seems to be down " % sys.argv[1])
diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua
index fbb481a0c..163998883 100644
--- a/games/minimal/mods/default/init.lua
+++ b/games/minimal/mods/default/init.lua
@@ -659,6 +659,8 @@ function default.node_sound_dirt_defaults(table)
{name="", gain=0.5}
--table.dug = table.dug or
-- {name="default_dirt_break", gain=0.5}
+ table.place = table.place or
+ {name="default_grass_footstep", gain=0.5}
default.node_sound_defaults(table)
return table
end
diff --git a/games/minimal/mods/default/mapgen.lua b/games/minimal/mods/default/mapgen.lua
index 115bb1458..478567d0a 100644
--- a/games/minimal/mods/default/mapgen.lua
+++ b/games/minimal/mods/default/mapgen.lua
@@ -27,52 +27,74 @@ minetest.register_alias("mapgen_mese", "default:mese")
-- Ore generation
--
-local function generate_ore(name, wherein, minp, maxp, seed, chunks_per_volume, ore_per_chunk, height_min, height_max, param2)
- if maxp.y < height_min or minp.y > height_max then
- return
- end
- local y_min = math.max(minp.y, height_min)
- local y_max = math.min(maxp.y, height_max)
- local volume = (maxp.x-minp.x+1)*(y_max-y_min+1)*(maxp.z-minp.z+1)
- local pr = PseudoRandom(seed)
- local num_chunks = math.floor(chunks_per_volume * volume)
- local chunk_size = 3
- if ore_per_chunk <= 4 then
- chunk_size = 2
- end
- local inverse_chance = math.floor(chunk_size*chunk_size*chunk_size / ore_per_chunk)
- --print("generate_ore num_chunks: "..dump(num_chunks))
- for i=1,num_chunks do
- local y0 = pr:next(y_min, y_max-chunk_size+1)
- if y0 >= height_min and y0 <= height_max then
- local x0 = pr:next(minp.x, maxp.x-chunk_size+1)
- local z0 = pr:next(minp.z, maxp.z-chunk_size+1)
- local p0 = {x=x0, y=y0, z=z0}
- for x1=0,chunk_size-1 do
- for y1=0,chunk_size-1 do
- for z1=0,chunk_size-1 do
- if pr:next(1,inverse_chance) == 1 then
- local x2 = x0+x1
- local y2 = y0+y1
- local z2 = z0+z1
- local p2 = {x=x2, y=y2, z=z2}
- if minetest.env:get_node(p2).name == wherein then
- minetest.env:set_node(p2, {name=name, param2=param2})
- end
- end
- end
- end
- end
- end
- end
- --print("generate_ore done")
-end
+minetest.register_ore({
+ ore_type = "scatter",
+ ore = "default:stone_with_coal",
+ wherein = "default:stone",
+ clust_scarcity = 8*8*8,
+ clust_num_ores = 5,
+ clust_size = 3,
+ height_min = -31000,
+ height_max = 64,
+})
+
+minetest.register_ore({
+ ore_type = "scatter",
+ ore = "default:stone_with_iron",
+ wherein = "default:stone",
+ clust_scarcity = 16*16*16,
+ clust_num_ores = 5,
+ clust_size = 3,
+ height_min = -5,
+ height_max = 7,
+})
+
+minetest.register_ore({
+ ore_type = "scatter",
+ ore = "default:stone_with_iron",
+ wherein = "default:stone",
+ clust_scarcity = 12*12*12,
+ clust_num_ores = 5,
+ clust_size = 3,
+ height_min = -16,
+ height_max = -5,
+})
+
+minetest.register_ore({
+ ore_type = "scatter",
+ ore = "default:stone_with_iron",
+ wherein = "default:stone",
+ clust_scarcity = 9*9*9,
+ clust_num_ores = 5,
+ clust_size = 3,
+ height_min = -31000,
+ height_max = -17,
+})
+
+-- for float islands and far scaled
+minetest.register_ore({
+ ore_type = "scatter",
+ ore = "default:stone_with_coal",
+ wherein = "default:stone",
+ clust_scarcity = 8*8*8,
+ clust_num_ores = 5,
+ clust_size = 3,
+ height_min = 200,
+ height_max = 31000,
+})
+
+minetest.register_ore({
+ ore_type = "scatter",
+ ore = "default:stone_with_iron",
+ wherein = "default:stone",
+ clust_scarcity = 9*9*9,
+ clust_num_ores = 5,
+ clust_size = 3,
+ height_min = 200,
+ height_max = 31000,
+})
minetest.register_on_generated(function(minp, maxp, seed)
- generate_ore("default:stone_with_coal", "default:stone", minp, maxp, seed, 1/8/8/8, 5, -31000, 64)
- generate_ore("default:stone_with_iron", "default:stone", minp, maxp, seed+1, 1/16/16/16, 5, -5, 7)
- generate_ore("default:stone_with_iron", "default:stone", minp, maxp, seed+2, 1/12/12/12, 5, -16, -5)
- generate_ore("default:stone_with_iron", "default:stone", minp, maxp, seed+3, 1/9/9/9, 5, -31000, -17)
-- Generate clay
if maxp.y >= 2 and minp.y <= 0 then
-- Assume X and Z lengths are equal
@@ -110,11 +132,5 @@ minetest.register_on_generated(function(minp, maxp, seed)
end
end
end
- if minetest.setting_get("liquid_finite") then
- generate_ore("default:water_source", "default:stone", minp, maxp, seed+42, 1/24/24/24, 4, -100, -10, 128)
- generate_ore("default:water_source", "default:stone", minp, maxp, seed+42, 1/28/28/28, 3, -10000, -101, 128)
- generate_ore("default:lava_source", "default:stone", minp, maxp, seed+43, 1/38/38/38, 2, -500, -100, 128)
- generate_ore("default:lava_source", "default:stone", minp, maxp, seed+43, 1/30/30/30, 4, -31000, -501, 128)
- end
end)
diff --git a/minetest.conf.example b/minetest.conf.example
index 1f2a764f2..838987c33 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -80,6 +80,7 @@
# when set to higher number than 0
#fsaa = 0
#vsync = false
+#fov = 72
# Address to connect to (#blank = start local server)
#address =
# Enable random user input, for testing
@@ -95,9 +96,11 @@
# Update liquids every .. recommend for finite: 0.2
#liquid_update = 1.0
# When finite liquid: relax flowing blocks to source if level near max and N nearby source blocks, more realistic, but not true constant. values: 0,1,2,3,4 : 0 - disable, 1 - most aggresive
-#liquid_relax = 1
-# optimization: faster cave flood (and not true constant)
+#liquid_relax = 2
+# Optimization: faster cave flood (and not true constant)
#liquid_fast_flood = 1
+# Underground water and lava springs, its infnity sources if liquid_finite enabled
+#underground_springs = 1
# Enable nice leaves; disable for speed
#new_style_leaves = true
# Enable smooth lighting with simple ambient occlusion;
@@ -125,6 +128,10 @@
#farmesh_distance = 40
# Enable/disable clouds
#enable_clouds = true
+#cloud_height = 120
+#enable_3d_clouds = true
+# Use a cloud animation for the main menu background
+#menu_clouds = true
# Path for screenshots
#screenshot_path = .
# Amount of view bobbing (0 = no view bobbing, 1.0 = normal, 2.0 = double)
@@ -304,29 +311,45 @@
# Mapgen stuff
#
-# Name of map generator to be used. Currently only v6 is supported.
+# Name of map generator to be used. Currently v6, indev and singlenode are supported.
#mg_name = v6
# Water level of map.
#water_level = 1
# Size of chunks to be generated.
#chunksize = 5
-# Map generation attributes. Currently supported: trees, caves, flat, v6_biome_blend
+# Map generation attributes. Currently supported: trees, caves, flat, v6_biome_blend, v6_jungles, dungeons
#mg_flags = trees, caves, v6_biome_blend
# How large deserts and beaches are
#mgv6_freq_desert = 0.45
#mgv6_freq_beach = 0.15
# Perlin noise attributes for different map generation parameters
# Offset, scale, spread factor, seed offset, number of octaves, persistence
-#mgv6_np_terrain_base = -4, 20, (250.0, 250, 250), 82341, 5, 0.6
+#mgv6_np_terrain_base = -4, 20, (250, 250, 250), 82341, 5, 0.6
#mgv6_np_terrain_higher = 20, 16, (500, 500, 500), 85039, 5, 0.6
#mgv6_np_steepness = 0.85, 0.5, (125, 125, 125), -932, 5, 0.7
#mgv6_np_height_select = 0.5, 1, (250, 250, 250), 4213, 5, 0.69
-#mgv6_np_trees = 0, 1, (125, 125, 125), 2, 4, 0.66
#mgv6_np_mud = 4, 2, (200, 200, 200), 91013, 3, 0.55
#mgv6_np_beach = 0, 1, (250, 250, 250), 59420, 3, 0.50
#mgv6_np_biome = 0, 1, (250, 250, 250), 9130, 3, 0.50
#mgv6_np_cave = 6, 6, (250, 250, 250), 34329, 3, 0.50
+#mgv6_np_humidity = 0.5, 0.5, (500, 500, 500), 72384, 4, 0.66
+#mgv6_np_trees = 0, 1, (125, 125, 125), 2, 4, 0.66
+#mgv6_np_apple_trees = 0, 1, (100, 100, 100), 342902, 3, 0.45
+
#mgv7_np_terrain = 10, 12, (350, 350, 350), 82341, 5, 0.6
#mgv7_np_bgroup = 0.5, 0.3125, (350, 350, 350), 5923, 2, 0.6
#mgv7_np_heat = 25, 50, (500, 500, 500), 35293, 1, 0
#mgv7_np_humidity = 50, 31.25, (750, 750, 750), 12094, 2, 0.6
+
+# Offset, scale, spread factor, seed offset, number of octaves, persistence, farscale, farspread
+#mgindev_np_terrain_base = -4, 20, (250, 250, 250), 82341, 5, 0.6, 10, 10
+#mgindev_np_terrain_higher = 20, 16, (500, 500, 500), 85039, 5, 0.6, 10, 10
+#mgindev_np_steepness = 0.85, 0.5, (125, 125, 125), -932, 5, 0.7, 2, 10
+#mgindev_np_mud = 4, 2, (200, 200, 200), 91013, 3, 0.55, 1, 1
+#mgindev_np_float_islands1 = 0, 1, (64, 64, 64 ), 3683, 5, 0.5, 1, 1.5
+#mgindev_np_float_islands2 = 0, 1, (8, 8, 8 ), 9292, 2, 0.5, 1, 1.5
+#mgindev_np_float_islands3 = 0, 1, (256, 256, 256), 6412, 2, 0.5, 1, 0.5
+#mgindev_np_biome = 0, 1, (250, 250, 250), 9130, 3, 0.50, 1, 10
+
+# Float islands starts from height, 0 to disable
+#mgindev_float_islands = 500
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d2f080c90..d6182861f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -161,7 +161,7 @@ else()
endif(APPLE)
endif(BUILD_CLIENT)
find_package(ZLIB REQUIRED)
- set(PLATFORM_LIBS -lpthread ${CMAKE_DL_LIBS})
+ set(PLATFORM_LIBS -lpthread -lrt ${CMAKE_DL_LIBS})
#set(CLIENT_PLATFORM_LIBS -lXxf86vm)
# This way Xxf86vm is found on OpenBSD too
find_library(XXF86VM_LIBRARY Xxf86vm)
@@ -172,6 +172,7 @@ endif()
find_package(Jthread REQUIRED)
find_package(Sqlite3 REQUIRED)
find_package(Json REQUIRED)
+find_package(OpenGLES2)
if(USE_FREETYPE)
find_package(Freetype REQUIRED)
@@ -205,6 +206,20 @@ set(common_SRCS
itemdef.cpp
nodedef.cpp
object_properties.cpp
+ scriptapi_types.cpp
+ scriptapi_common.cpp
+ scriptapi_content.cpp
+ scriptapi_craft.cpp
+ scriptapi_node.cpp
+ scriptapi_item.cpp
+ scriptapi_env.cpp
+ scriptapi_nodetimer.cpp
+ scriptapi_noise.cpp
+ scriptapi_entity.cpp
+ scriptapi_object.cpp
+ scriptapi_nodemeta.cpp
+ scriptapi_inventory.cpp
+ scriptapi_particles.cpp
scriptapi.cpp
script.cpp
log.cpp
@@ -212,7 +227,10 @@ set(common_SRCS
emerge.cpp
mapgen.cpp
mapgen_v6.cpp
+ mapgen_indev.cpp
+ mapgen_singlenode.cpp
treegen.cpp
+ dungeongen.cpp
content_nodemeta.cpp
content_mapnode.cpp
collision.cpp
@@ -371,6 +389,7 @@ if(BUILD_CLIENT)
${SQLITE3_LIBRARY}
${LUA_LIBRARY}
${JSON_LIBRARY}
+ ${OPENGLES2_LIBRARIES}
${PLATFORM_LIBS}
${CLIENT_PLATFORM_LIBS}
)
diff --git a/src/activeobject.h b/src/activeobject.h
index e454f2c8c..1a75fba2e 100644
--- a/src/activeobject.h
+++ b/src/activeobject.h
@@ -61,7 +61,7 @@ public:
}
virtual u8 getType() const = 0;
-
+ virtual bool getCollisionBox(aabb3f *toset) = 0;
protected:
u16 m_id; // 0 is invalid, "no id"
};
diff --git a/src/chat.cpp b/src/chat.cpp
index c3509ae49..1135ccdf7 100644
--- a/src/chat.cpp
+++ b/src/chat.cpp
@@ -117,8 +117,8 @@ void ChatBuffer::deleteOldest(u32 count)
--count;
}
- m_unformatted.erase(0, del_unformatted);
- m_formatted.erase(0, del_formatted);
+ m_unformatted.erase(m_unformatted.begin(), m_unformatted.begin() + del_unformatted);
+ m_formatted.erase(m_formatted.begin(), m_formatted.begin() + del_formatted);
}
void ChatBuffer::deleteByAge(f32 maxAge)
@@ -232,10 +232,10 @@ void ChatBuffer::scrollTop()
}
u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
- core::array<ChatFormattedLine>& destination) const
+ std::vector<ChatFormattedLine>& destination) const
{
u32 num_added = 0;
- core::array<ChatFormattedFragment> next_frags;
+ std::vector<ChatFormattedFragment> next_frags;
ChatFormattedLine next_line;
ChatFormattedFragment temp_frag;
u32 out_column = 0;
@@ -292,7 +292,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
frag.column = out_column;
next_line.fragments.push_back(frag);
out_column += frag.text.size();
- next_frags.erase(0, 1);
+ next_frags.erase(next_frags.begin());
}
else
{
@@ -414,7 +414,7 @@ std::wstring ChatPrompt::submit()
if (!line.empty())
m_history.push_back(line);
if (m_history.size() > m_history_limit)
- m_history.erase(0);
+ m_history.erase(m_history.begin());
m_history_index = m_history.size();
m_view = 0;
m_cursor = 0;
@@ -464,7 +464,7 @@ void ChatPrompt::historyNext()
}
}
-void ChatPrompt::nickCompletion(const core::list<std::wstring>& names, bool backwards)
+void ChatPrompt::nickCompletion(const std::list<std::wstring>& names, bool backwards)
{
// Two cases:
// (a) m_nick_completion_start == m_nick_completion_end == 0
@@ -492,10 +492,10 @@ void ChatPrompt::nickCompletion(const core::list<std::wstring>& names, bool back
std::wstring prefix = m_line.substr(prefix_start, prefix_end - prefix_start);
// find all names that start with the selected prefix
- core::array<std::wstring> completions;
- for (core::list<std::wstring>::ConstIterator
+ std::vector<std::wstring> completions;
+ for (std::list<std::wstring>::const_iterator
i = names.begin();
- i != names.end(); i++)
+ i != names.end(); ++i)
{
if (str_starts_with(*i, prefix, true))
{
diff --git a/src/chat.h b/src/chat.h
index 27863922c..8a40c7ccf 100644
--- a/src/chat.h
+++ b/src/chat.h
@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h"
#include <string>
+#include <vector>
+#include <list>
// Chat console related classes, only used by the client
@@ -55,7 +57,7 @@ struct ChatFormattedFragment
struct ChatFormattedLine
{
// Array of text fragments
- core::array<ChatFormattedFragment> fragments;
+ std::vector<ChatFormattedFragment> fragments;
// true if first line of one formatted ChatLine
bool first;
};
@@ -110,7 +112,7 @@ public:
// Appends the formatted lines to the destination array and
// returns the number of formatted lines.
u32 formatChatLine(const ChatLine& line, u32 cols,
- core::array<ChatFormattedLine>& destination) const;
+ std::vector<ChatFormattedLine>& destination) const;
protected:
s32 getTopScrollPos() const;
@@ -120,7 +122,7 @@ private:
// Scrollback size
u32 m_scrollback;
// Array of unformatted chat lines
- core::array<ChatLine> m_unformatted;
+ std::vector<ChatLine> m_unformatted;
// Number of character columns in console
u32 m_cols;
@@ -129,7 +131,7 @@ private:
// Scroll position (console's top line index into m_formatted)
s32 m_scroll;
// Array of formatted lines
- core::array<ChatFormattedLine> m_formatted;
+ std::vector<ChatFormattedLine> m_formatted;
// Empty formatted line, for error returns
ChatFormattedLine m_empty_formatted_line;
};
@@ -158,7 +160,7 @@ public:
void historyNext();
// Nick completion
- void nickCompletion(const core::list<std::wstring>& names, bool backwards);
+ void nickCompletion(const std::list<std::wstring>& names, bool backwards);
// Update console size and reformat the visible portion of the prompt
void reformat(u32 cols);
@@ -209,7 +211,7 @@ private:
// Currently edited line
std::wstring m_line;
// History buffer
- core::array<std::wstring> m_history;
+ std::vector<std::wstring> m_history;
// History index (0 <= m_history_index <= m_history.size())
u32 m_history_index;
// Maximum number of history entries
diff --git a/src/client.cpp b/src/client.cpp
index be35db5de..f27f95d98 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -232,8 +232,8 @@ void * MediaFetchThread::Thread()
#if USE_CURL
CURL *curl;
CURLcode res;
- for (core::list<MediaRequest>::Iterator i = m_file_requests.begin();
- i != m_file_requests.end(); i++) {
+ for (std::list<MediaRequest>::iterator i = m_file_requests.begin();
+ i != m_file_requests.end(); ++i) {
curl = curl_easy_init();
assert(curl);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
@@ -360,8 +360,8 @@ Client::~Client()
}
}
- for (core::list<MediaFetchThread*>::Iterator i = m_media_fetch_threads.begin();
- i != m_media_fetch_threads.end(); i++)
+ for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
+ i != m_media_fetch_threads.end(); ++i)
delete *i;
}
@@ -585,7 +585,7 @@ void Client::step(float dtime)
if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
{
ScopeProfiler sp(g_profiler, "Client: map timer and unload");
- core::list<v3s16> deleted_blocks;
+ std::list<v3s16> deleted_blocks;
m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
g_settings->getFloat("client_unload_unused_data_timeout"),
&deleted_blocks);
@@ -599,8 +599,8 @@ void Client::step(float dtime)
NOTE: This loop is intentionally iterated the way it is.
*/
- core::list<v3s16>::Iterator i = deleted_blocks.begin();
- core::list<v3s16> sendlist;
+ std::list<v3s16>::iterator i = deleted_blocks.begin();
+ std::list<v3s16> sendlist;
for(;;)
{
if(sendlist.size() == 255 || i == deleted_blocks.end())
@@ -619,9 +619,9 @@ void Client::step(float dtime)
writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
reply[2] = sendlist.size();
u32 k = 0;
- for(core::list<v3s16>::Iterator
+ for(std::list<v3s16>::iterator
j = sendlist.begin();
- j != sendlist.end(); j++)
+ j != sendlist.end(); ++j)
{
writeV3S16(&reply[2+1+6*k], *j);
k++;
@@ -635,7 +635,7 @@ void Client::step(float dtime)
}
sendlist.push_back(*i);
- i++;
+ ++i;
}
}
@@ -727,7 +727,7 @@ void Client::step(float dtime)
<<std::endl;*/
int num_processed_meshes = 0;
- while(m_mesh_update_thread.m_queue_out.size() > 0)
+ while(!m_mesh_update_thread.m_queue_out.empty())
{
num_processed_meshes++;
MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
@@ -779,10 +779,10 @@ void Client::step(float dtime)
*/
if (m_media_receive_started) {
bool all_stopped = true;
- for (core::list<MediaFetchThread*>::Iterator thread = m_media_fetch_threads.begin();
- thread != m_media_fetch_threads.end(); thread++) {
+ for (std::list<MediaFetchThread*>::iterator thread = m_media_fetch_threads.begin();
+ thread != m_media_fetch_threads.end(); ++thread) {
all_stopped &= !(*thread)->IsRunning();
- while ((*thread)->m_file_data.size() > 0) {
+ while (!(*thread)->m_file_data.empty()) {
std::pair <std::string, std::string> out = (*thread)->m_file_data.pop_front();
++m_media_received_count;
@@ -803,9 +803,9 @@ void Client::step(float dtime)
}
{
- core::map<std::string, std::string>::Node *n;
+ std::map<std::string, std::string>::iterator n;
n = m_media_name_sha1_map.find(out.first);
- if(n == NULL)
+ if(n == m_media_name_sha1_map.end())
errorstream<<"The server sent a file that has not "
<<"been announced."<<std::endl;
else
@@ -814,11 +814,11 @@ void Client::step(float dtime)
}
}
if (all_stopped) {
- core::list<MediaRequest> fetch_failed;
- for (core::list<MediaFetchThread*>::Iterator thread = m_media_fetch_threads.begin();
- thread != m_media_fetch_threads.end(); thread++) {
- for (core::list<MediaRequest>::Iterator request = (*thread)->m_failed.begin();
- request != (*thread)->m_failed.end(); request++)
+ std::list<MediaRequest> fetch_failed;
+ for (std::list<MediaFetchThread*>::iterator thread = m_media_fetch_threads.begin();
+ thread != m_media_fetch_threads.end(); ++thread) {
+ for (std::list<MediaRequest>::iterator request = (*thread)->m_failed.begin();
+ request != (*thread)->m_failed.end(); ++request)
fetch_failed.push_back(*request);
(*thread)->m_failed.clear();
}
@@ -1015,14 +1015,14 @@ void Client::deletingPeer(con::Peer *peer, bool timeout)
string name
}
*/
-void Client::request_media(const core::list<MediaRequest> &file_requests)
+void Client::request_media(const std::list<MediaRequest> &file_requests)
{
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOSERVER_REQUEST_MEDIA);
writeU16(os, file_requests.size());
- for(core::list<MediaRequest>::ConstIterator i = file_requests.begin();
- i != file_requests.end(); i++) {
+ for(std::list<MediaRequest>::const_iterator i = file_requests.begin();
+ i != file_requests.end(); ++i) {
os<<serializeString(i->name);
}
@@ -1622,7 +1622,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
infostream<<"Client: Received media announcement: packet size: "
<<datasize<<std::endl;
- core::list<MediaRequest> file_requests;
+ std::list<MediaRequest> file_requests;
for(int i=0; i<num_files; i++)
{
@@ -1641,7 +1641,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::string sha1_hex = hex_encode(sha1_raw);
std::ostringstream tmp_os(std::ios_base::binary);
bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os);
- m_media_name_sha1_map.set(name, sha1_raw);
+ m_media_name_sha1_map[name] = sha1_raw;
// If found in cache, try to load it from there
if(found_in_cache)
@@ -1677,16 +1677,16 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
request_media(file_requests);
} else {
#if USE_CURL
- core::list<MediaFetchThread*>::Iterator cur = m_media_fetch_threads.begin();
- for(core::list<MediaRequest>::Iterator i = file_requests.begin();
- i != file_requests.end(); i++) {
+ std::list<MediaFetchThread*>::iterator cur = m_media_fetch_threads.begin();
+ for(std::list<MediaRequest>::iterator i = file_requests.begin();
+ i != file_requests.end(); ++i) {
(*cur)->m_file_requests.push_back(*i);
cur++;
if (cur == m_media_fetch_threads.end())
cur = m_media_fetch_threads.begin();
}
- for (core::list<MediaFetchThread*>::Iterator i = m_media_fetch_threads.begin();
- i != m_media_fetch_threads.end(); i++) {
+ for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
+ i != m_media_fetch_threads.end(); ++i) {
(*i)->m_remote_url = remote_media;
(*i)->Start();
}
@@ -1762,9 +1762,9 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
{
- core::map<std::string, std::string>::Node *n;
+ std::map<std::string, std::string>::iterator n;
n = m_media_name_sha1_map.find(name);
- if(n == NULL)
+ if(n == m_media_name_sha1_map.end())
errorstream<<"The server sent a file that has not "
<<"been announced."<<std::endl;
else
@@ -1936,6 +1936,89 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
event.show_formspec.formname = new std::string(formname);
m_client_event_queue.push_back(event);
}
+ else if(command == TOCLIENT_SPAWN_PARTICLE)
+ {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ v3f pos = readV3F1000(is);
+ v3f vel = readV3F1000(is);
+ v3f acc = readV3F1000(is);
+ float expirationtime = readF1000(is);
+ float size = readF1000(is);
+ bool collisiondetection = readU8(is);
+ std::string texture = deSerializeLongString(is);
+
+ ClientEvent event;
+ event.type = CE_SPAWN_PARTICLE;
+ event.spawn_particle.pos = new v3f (pos);
+ event.spawn_particle.vel = new v3f (vel);
+ event.spawn_particle.acc = new v3f (acc);
+
+ event.spawn_particle.expirationtime = expirationtime;
+ event.spawn_particle.size = size;
+ event.add_particlespawner.collisiondetection =
+ collisiondetection;
+ event.spawn_particle.texture = new std::string(texture);
+
+ m_client_event_queue.push_back(event);
+ }
+ else if(command == TOCLIENT_ADD_PARTICLESPAWNER)
+ {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ u16 amount = readU16(is);
+ float spawntime = readF1000(is);
+ v3f minpos = readV3F1000(is);
+ v3f maxpos = readV3F1000(is);
+ v3f minvel = readV3F1000(is);
+ v3f maxvel = readV3F1000(is);
+ v3f minacc = readV3F1000(is);
+ v3f maxacc = readV3F1000(is);
+ float minexptime = readF1000(is);
+ float maxexptime = readF1000(is);
+ float minsize = readF1000(is);
+ float maxsize = readF1000(is);
+ bool collisiondetection = readU8(is);
+ std::string texture = deSerializeLongString(is);
+ u32 id = readU32(is);
+
+ ClientEvent event;
+ event.type = CE_ADD_PARTICLESPAWNER;
+ event.add_particlespawner.amount = amount;
+ event.add_particlespawner.spawntime = spawntime;
+
+ event.add_particlespawner.minpos = new v3f (minpos);
+ event.add_particlespawner.maxpos = new v3f (maxpos);
+ event.add_particlespawner.minvel = new v3f (minvel);
+ event.add_particlespawner.maxvel = new v3f (maxvel);
+ event.add_particlespawner.minacc = new v3f (minacc);
+ event.add_particlespawner.maxacc = new v3f (maxacc);
+
+ event.add_particlespawner.minexptime = minexptime;
+ event.add_particlespawner.maxexptime = maxexptime;
+ event.add_particlespawner.minsize = minsize;
+ event.add_particlespawner.maxsize = maxsize;
+ event.add_particlespawner.collisiondetection = collisiondetection;
+ event.add_particlespawner.texture = new std::string(texture);
+ event.add_particlespawner.id = id;
+
+ m_client_event_queue.push_back(event);
+ }
+ else if(command == TOCLIENT_DELETE_PARTICLESPAWNER)
+ {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ u32 id = readU16(is);
+
+ ClientEvent event;
+ event.type = CE_DELETE_PARTICLESPAWNER;
+ event.delete_particlespawner.id = id;
+
+ m_client_event_queue.push_back(event);
+ }
else
{
infostream<<"Client: Ignoring unknown command "
@@ -2231,7 +2314,7 @@ void Client::sendPlayerItem(u16 item)
void Client::removeNode(v3s16 p)
{
- core::map<v3s16, MapBlock*> modified_blocks;
+ std::map<v3s16, MapBlock*> modified_blocks;
try
{
@@ -2245,12 +2328,11 @@ void Client::removeNode(v3s16 p)
// add urgent task to update the modified node
addUpdateMeshTaskForNode(p, false, true);
- for(core::map<v3s16, MapBlock * >::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock * >::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
- addUpdateMeshTaskWithEdge(p);
+ addUpdateMeshTaskWithEdge(i->first);
}
}
@@ -2258,7 +2340,7 @@ void Client::addNode(v3s16 p, MapNode n)
{
TimeTaker timer1("Client::addNode()");
- core::map<v3s16, MapBlock*> modified_blocks;
+ std::map<v3s16, MapBlock*> modified_blocks;
try
{
@@ -2268,12 +2350,11 @@ void Client::addNode(v3s16 p, MapNode n)
catch(InvalidPositionException &e)
{}
- for(core::map<v3s16, MapBlock * >::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock * >::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
- addUpdateMeshTaskWithEdge(p);
+ addUpdateMeshTaskWithEdge(i->first);
}
}
@@ -2373,7 +2454,7 @@ ClientActiveObject * Client::getSelectedActiveObject(
core::line3d<f32> shootline_on_map
)
{
- core::array<DistanceSortedActiveObject> objects;
+ std::vector<DistanceSortedActiveObject> objects;
m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
@@ -2381,7 +2462,7 @@ ClientActiveObject * Client::getSelectedActiveObject(
// Sort them.
// After this, the closest object is the first in the array.
- objects.sort();
+ std::sort(objects.begin(), objects.end());
for(u32 i=0; i<objects.size(); i++)
{
@@ -2420,13 +2501,13 @@ void Client::printDebugInfo(std::ostream &os)
<<std::endl;*/
}
-core::list<std::wstring> Client::getConnectedPlayerNames()
+std::list<std::wstring> Client::getConnectedPlayerNames()
{
- core::list<Player*> players = m_env.getPlayers(true);
- core::list<std::wstring> playerNames;
- for(core::list<Player*>::Iterator
+ std::list<Player*> players = m_env.getPlayers(true);
+ std::list<std::wstring> playerNames;
+ for(std::list<Player*>::iterator
i = players.begin();
- i != players.end(); i++)
+ i != players.end(); ++i)
{
Player *player = *i;
playerNames.push_back(narrow_to_wide(player->getName()));
diff --git a/src/client.h b/src/client.h
index 809e98b81..d476a1d51 100644
--- a/src/client.h
+++ b/src/client.h
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "particles.h"
#include "util/pointedthing.h"
+#include <algorithm>
struct MeshMakeData;
class MapBlockMesh;
@@ -142,9 +143,9 @@ public:
void * Thread();
- core::list<MediaRequest> m_file_requests;
+ std::list<MediaRequest> m_file_requests;
MutexedQueue<std::pair<std::string, std::string> > m_file_data;
- core::list<MediaRequest> m_failed;
+ std::list<MediaRequest> m_failed;
std::string m_remote_url;
IGameDef *m_gamedef;
};
@@ -156,7 +157,10 @@ enum ClientEventType
CE_PLAYER_FORCE_MOVE,
CE_DEATHSCREEN,
CE_TEXTURES_UPDATED,
- CE_SHOW_FORMSPEC
+ CE_SHOW_FORMSPEC,
+ CE_SPAWN_PARTICLE,
+ CE_ADD_PARTICLESPAWNER,
+ CE_DELETE_PARTICLESPAWNER
};
struct ClientEvent
@@ -184,6 +188,35 @@ struct ClientEvent
} show_formspec;
struct{
} textures_updated;
+ struct{
+ v3f *pos;
+ v3f *vel;
+ v3f *acc;
+ f32 expirationtime;
+ f32 size;
+ bool collisiondetection;
+ std::string *texture;
+ } spawn_particle;
+ struct{
+ u16 amount;
+ f32 spawntime;
+ v3f *minpos;
+ v3f *maxpos;
+ v3f *minvel;
+ v3f *maxvel;
+ v3f *minacc;
+ v3f *maxacc;
+ f32 minexptime;
+ f32 maxexptime;
+ f32 minsize;
+ f32 maxsize;
+ bool collisiondetection;
+ std::string *texture;
+ u32 id;
+ } add_particlespawner;
+ struct{
+ u32 id;
+ } delete_particlespawner;
};
};
@@ -282,7 +315,7 @@ public:
// Prints a line or two of info
void printDebugInfo(std::ostream &os);
- core::list<std::wstring> getConnectedPlayerNames();
+ std::list<std::wstring> getConnectedPlayerNames();
float getAnimationTime();
@@ -347,7 +380,7 @@ private:
// Insert a media file appropriately into the appropriate manager
bool loadMedia(const std::string &data, const std::string &filename);
- void request_media(const core::list<MediaRequest> &file_requests);
+ void request_media(const std::list<MediaRequest> &file_requests);
// Virtual methods from con::PeerHandler
void peerAdded(con::Peer *peer);
@@ -377,7 +410,7 @@ private:
MtEventManager *m_event;
MeshUpdateThread m_mesh_update_thread;
- core::list<MediaFetchThread*> m_media_fetch_threads;
+ std::list<MediaFetchThread*> m_media_fetch_threads;
ClientEnvironment m_env;
con::Connection m_con;
IrrlichtDevice *m_device;
@@ -387,7 +420,7 @@ private:
bool m_inventory_updated;
Inventory *m_inventory_from_server;
float m_inventory_from_server_age;
- core::map<v3s16, bool> m_active_blocks;
+ std::set<v3s16> m_active_blocks;
PacketCounter m_packetcounter;
// Block mesh animation parameters
float m_animation_time;
@@ -405,7 +438,7 @@ private:
Queue<ClientEvent> m_client_event_queue;
FileCache m_media_cache;
// Mapping from media file name to SHA1 checksum
- core::map<std::string, std::string> m_media_name_sha1_map;
+ std::map<std::string, std::string> m_media_name_sha1_map;
bool m_media_receive_started;
u32 m_media_count;
u32 m_media_received_count;
diff --git a/src/clientmap.cpp b/src/clientmap.cpp
index aa92dfdee..c08068367 100644
--- a/src/clientmap.cpp
+++ b/src/clientmap.cpp
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "profiler.h"
#include "settings.h"
#include "util/mathconstants.h"
+#include <algorithm>
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@@ -83,7 +84,7 @@ MapSector * ClientMap::emergeSector(v2s16 p2d)
{
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
- m_sectors.insert(p2d, sector);
+ m_sectors[p2d] = sector;
}
return sector;
@@ -164,11 +165,11 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
INodeDefManager *nodemgr = m_gamedef->ndef();
- for(core::map<v3s16, MapBlock*>::Iterator
- i = m_drawlist.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = m_drawlist.begin();
+ i != m_drawlist.end(); ++i)
{
- MapBlock *block = i.getNode()->getValue();
+ MapBlock *block = i->second;
block->refDrop();
}
m_drawlist.clear();
@@ -215,11 +216,11 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
// Blocks from which stuff was actually drawn
//u32 blocks_without_stuff = 0;
- for(core::map<v2s16, MapSector*>::Iterator
- si = m_sectors.getIterator();
- si.atEnd() == false; si++)
+ for(std::map<v2s16, MapSector*>::iterator
+ si = m_sectors.begin();
+ si != m_sectors.end(); ++si)
{
- MapSector *sector = si.getNode()->getValue();
+ MapSector *sector = si->second;
v2s16 sp = sector->getPos();
if(m_control.range_all == false)
@@ -231,7 +232,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
continue;
}
- core::list< MapBlock * > sectorblocks;
+ std::list< MapBlock * > sectorblocks;
sector->getBlocks(sectorblocks);
/*
@@ -240,7 +241,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
u32 sector_blocks_drawn = 0;
- core::list< MapBlock * >::Iterator i;
+ std::list< MapBlock * >::iterator i;
for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
{
MapBlock *block = *i;
@@ -350,7 +351,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
} // foreach sectorblocks
if(sector_blocks_drawn != 0)
- m_last_drawn_sectors[sp] = true;
+ m_last_drawn_sectors.insert(sp);
}
m_control.blocks_would_have_drawn = blocks_would_have_drawn;
@@ -368,12 +369,12 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
struct MeshBufList
{
video::SMaterial m;
- core::list<scene::IMeshBuffer*> bufs;
+ std::list<scene::IMeshBuffer*> bufs;
};
struct MeshBufListList
{
- core::list<MeshBufList> lists;
+ std::list<MeshBufList> lists;
void clear()
{
@@ -382,8 +383,8 @@ struct MeshBufListList
void add(scene::IMeshBuffer *buf)
{
- for(core::list<MeshBufList>::Iterator i = lists.begin();
- i != lists.end(); i++){
+ for(std::list<MeshBufList>::iterator i = lists.begin();
+ i != lists.end(); ++i){
MeshBufList &l = *i;
if(l.m == buf->getMaterial()){
l.bufs.push_back(buf);
@@ -487,11 +488,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
MeshBufListList drawbufs;
- for(core::map<v3s16, MapBlock*>::Iterator
- i = m_drawlist.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = m_drawlist.begin();
+ i != m_drawlist.end(); ++i)
{
- MapBlock *block = i.getNode()->getValue();
+ MapBlock *block = i->second;
// If the mesh of the block happened to get deleted, ignore it
if(block->mesh == NULL)
@@ -569,11 +570,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
}
}
- core::list<MeshBufList> &lists = drawbufs.lists;
+ std::list<MeshBufList> &lists = drawbufs.lists;
int timecheck_counter = 0;
- for(core::list<MeshBufList>::Iterator i = lists.begin();
- i != lists.end(); i++)
+ for(std::list<MeshBufList>::iterator i = lists.begin();
+ i != lists.end(); ++i)
{
{
timecheck_counter++;
@@ -595,8 +596,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
driver->setMaterial(list.m);
- for(core::list<scene::IMeshBuffer*>::Iterator j = list.bufs.begin();
- j != list.bufs.end(); j++)
+ for(std::list<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
+ j != list.bufs.end(); ++j)
{
scene::IMeshBuffer *buf = *j;
driver->drawMeshBuffer(buf);
@@ -769,7 +770,7 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
float sunlight_min_d = max_d*0.8;
if(sunlight_min_d > 35*BS)
sunlight_min_d = 35*BS;
- core::array<int> values;
+ std::vector<int> values;
for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
v3f z_dir = z_directions[i];
z_dir.normalize();
@@ -798,7 +799,7 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
}
int brightness_sum = 0;
int brightness_count = 0;
- values.sort();
+ std::sort(values.begin(), values.end());
u32 num_values_to_use = values.size();
if(num_values_to_use >= 10)
num_values_to_use -= num_values_to_use/2;
diff --git a/src/clientmap.h b/src/clientmap.h
index 786f35b77..7f63704d3 100644
--- a/src/clientmap.h
+++ b/src/clientmap.h
@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "map.h"
+#include <set>
+#include <map>
struct MapDrawControl
{
@@ -128,7 +130,7 @@ public:
// Check if sector was drawn on last render()
bool sectorWasDrawn(v2s16 p)
{
- return (m_last_drawn_sectors.find(p) != NULL);
+ return (m_last_drawn_sectors.find(p) != m_last_drawn_sectors.end());
}
private:
@@ -143,9 +145,9 @@ private:
f32 m_camera_fov;
JMutex m_camera_mutex;
- core::map<v3s16, MapBlock*> m_drawlist;
+ std::map<v3s16, MapBlock*> m_drawlist;
- core::map<v2s16, bool> m_last_drawn_sectors;
+ std::set<v2s16> m_last_drawn_sectors;
};
#endif
diff --git a/src/clientobject.cpp b/src/clientobject.cpp
index e7c735dac..37f693c5e 100644
--- a/src/clientobject.cpp
+++ b/src/clientobject.cpp
@@ -43,9 +43,9 @@ ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
ClientEnvironment *env)
{
// Find factory function
- core::map<u16, Factory>::Node *n;
+ std::map<u16, Factory>::iterator n;
n = m_types.find(type);
- if(n == NULL)
+ if(n == m_types.end())
{
// If factory is not found, just return.
dstream<<"WARNING: ClientActiveObject: No factory for type="
@@ -53,18 +53,18 @@ ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
return NULL;
}
- Factory f = n->getValue();
+ Factory f = n->second;
ClientActiveObject *object = (*f)(gamedef, env);
return object;
}
void ClientActiveObject::registerType(u16 type, Factory f)
{
- core::map<u16, Factory>::Node *n;
+ std::map<u16, Factory>::iterator n;
n = m_types.find(type);
- if(n)
+ if(n != m_types.end())
return;
- m_types.insert(type, f);
+ m_types[type] = f;
}
diff --git a/src/clientobject.h b/src/clientobject.h
index d1ee366cf..8cbf3d60b 100644
--- a/src/clientobject.h
+++ b/src/clientobject.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "activeobject.h"
+#include <map>
/*
@@ -96,7 +97,7 @@ protected:
ClientEnvironment *m_env;
private:
// Used for creating objects based on type
- static core::map<u16, Factory> m_types;
+ static std::map<u16, Factory> m_types;
};
struct DistanceSortedActiveObject
@@ -110,7 +111,7 @@ struct DistanceSortedActiveObject
d = a_d;
}
- bool operator < (DistanceSortedActiveObject &other)
+ bool operator < (const DistanceSortedActiveObject &other) const
{
return d < other.d;
}
diff --git a/src/clientserver.h b/src/clientserver.h
index 769272a68..28b579971 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -79,9 +79,18 @@ SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
Serialization format changes
PROTOCOL_VERSION 16:
TOCLIENT_SHOW_FORMSPEC
+ PROTOCOL_VERSION 17:
+ Serialization format change: include backface_culling flag in TileDef
+ Added rightclickable field in nodedef
+ TOCLIENT_SPAWN_PARTICLE
+ TOCLIENT_ADD_PARTICLESPAWNER
+ TOCLIENT_DELETE_PARTICLESPAWNER
+ PROTOCOL_VERSION 18:
+ damageGroups added to ToolCapabilities
+ sound_place added to ItemDefinition
*/
-#define LATEST_PROTOCOL_VERSION 16
+#define LATEST_PROTOCOL_VERSION 18
// Server's supported network protocol range
#define SERVER_PROTOCOL_VERSION_MIN 13
@@ -356,6 +365,7 @@ enum ToClientCommand
u8[len] name
[2] serialized inventory
*/
+
TOCLIENT_SHOW_FORMSPEC = 0x44,
/*
[0] u16 command
@@ -381,6 +391,46 @@ enum ToClientCommand
f1000 movement_liquid_sink
f1000 movement_gravity
*/
+
+ TOCLIENT_SPAWN_PARTICLE = 0x46,
+ /*
+ u16 command
+ v3f1000 pos
+ v3f1000 velocity
+ v3f1000 acceleration
+ f1000 expirationtime
+ f1000 size
+ u8 bool collisiondetection
+ u32 len
+ u8[len] texture
+ */
+
+ TOCLIENT_ADD_PARTICLESPAWNER = 0x47,
+ /*
+ u16 command
+ u16 amount
+ f1000 spawntime
+ v3f1000 minpos
+ v3f1000 maxpos
+ v3f1000 minvel
+ v3f1000 maxvel
+ v3f1000 minacc
+ v3f1000 maxacc
+ f1000 minexptime
+ f1000 maxexptime
+ f1000 minsize
+ f1000 maxsize
+ u8 bool collisiondetection
+ u32 len
+ u8[len] texture
+ u32 id
+ */
+
+ TOCLIENT_DELETE_PARTICLESPAWNER = 0x48,
+ /*
+ u16 command
+ u32 id
+ */
};
enum ToServerCommand
diff --git a/src/clouds.cpp b/src/clouds.cpp
index 9f0bc06d8..55ec8965a 100644
--- a/src/clouds.cpp
+++ b/src/clouds.cpp
@@ -29,7 +29,8 @@ Clouds::Clouds(
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id,
- u32 seed
+ u32 seed,
+ s16 cloudheight
):
scene::ISceneNode(parent, mgr, id),
m_seed(seed),
@@ -45,7 +46,8 @@ Clouds::Clouds(
//m_material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
- m_cloud_y = BS * g_settings->getS16("cloud_height");
+ m_cloud_y = BS * (cloudheight ? cloudheight :
+ g_settings->getS16("cloud_height"));
m_box = core::aabbox3d<f32>(-BS*1000000,m_cloud_y-BS,-BS*1000000,
BS*1000000,m_cloud_y+BS,BS*1000000);
diff --git a/src/clouds.h b/src/clouds.h
index 72923c2c5..8f8b19faf 100644
--- a/src/clouds.h
+++ b/src/clouds.h
@@ -30,7 +30,8 @@ public:
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id,
- u32 seed
+ u32 seed,
+ s16 cloudheight=0
);
~Clouds();
diff --git a/src/collision.cpp b/src/collision.cpp
index 58517b779..806a3b720 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -23,7 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "gamedef.h"
#include "log.h"
+#include "environment.h"
+#include "serverobject.h"
#include <vector>
+#include <set>
#include "util/timetaker.h"
#include "main.h" // g_profiler
#include "profiler.h"
@@ -186,11 +189,12 @@ bool wouldCollideWithCeiling(
}
-collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
+collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f)
{
+ Map *map = &env->getMap();
//TimeTaker tt("collisionMoveSimple");
ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG);
@@ -215,6 +219,7 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
std::vector<aabb3f> cboxes;
std::vector<bool> is_unloaded;
std::vector<bool> is_step_up;
+ std::vector<bool> is_object;
std::vector<int> bouncy_values;
std::vector<v3s16> node_positions;
{
@@ -256,6 +261,7 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
is_step_up.push_back(false);
bouncy_values.push_back(n_bouncy_value);
node_positions.push_back(p);
+ is_object.push_back(false);
}
}
catch(InvalidPositionException &e)
@@ -267,14 +273,72 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
is_step_up.push_back(false);
bouncy_values.push_back(0);
node_positions.push_back(p);
+ is_object.push_back(false);
}
}
} // tt2
+ {
+ ScopeProfiler sp(g_profiler, "collisionMoveSimple objects avg", SPT_AVG);
+ //TimeTaker tt3("collisionMoveSimple collect object boxes");
+
+ /* add object boxes to cboxes */
+
+
+ std::list<ActiveObject*> objects;
+#ifndef SERVER
+ ClientEnvironment *c_env = dynamic_cast<ClientEnvironment*>(env);
+ if (c_env != 0)
+ {
+ f32 distance = speed_f.getLength();
+ std::vector<DistanceSortedActiveObject> clientobjects;
+ c_env->getActiveObjects(pos_f,distance * 1.5,clientobjects);
+ for (int i=0; i < clientobjects.size(); i++)
+ {
+ objects.push_back((ActiveObject*)clientobjects[i].obj);
+ }
+ }
+ else
+#endif
+ {
+ ServerEnvironment *s_env = dynamic_cast<ServerEnvironment*>(env);
+ if (s_env != 0)
+ {
+ f32 distance = speed_f.getLength();
+ std::set<u16> s_objects = s_env->getObjectsInsideRadius(pos_f,distance * 1.5);
+ for (std::set<u16>::iterator iter = s_objects.begin(); iter != s_objects.end(); iter++)
+ {
+ ServerActiveObject *current = s_env->getActiveObject(*iter);
+ objects.push_back((ActiveObject*)current);
+ }
+ }
+ }
+
+ for (std::list<ActiveObject*>::const_iterator iter = objects.begin();iter != objects.end(); ++iter)
+ {
+ ActiveObject *object = *iter;
+
+ if (object != NULL)
+ {
+ aabb3f object_collisionbox;
+ if (object->getCollisionBox(&object_collisionbox))
+ {
+ cboxes.push_back(object_collisionbox);
+ is_unloaded.push_back(false);
+ is_step_up.push_back(false);
+ bouncy_values.push_back(0);
+ node_positions.push_back(v3s16(0,0,0));
+ is_object.push_back(true);
+ }
+ }
+ }
+ } //tt3
+
assert(cboxes.size() == is_unloaded.size());
assert(cboxes.size() == is_step_up.size());
assert(cboxes.size() == bouncy_values.size());
assert(cboxes.size() == node_positions.size());
+ assert(cboxes.size() == is_object.size());
/*
Collision detection
@@ -386,7 +450,11 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
is_collision = false;
CollisionInfo info;
- info.type = COLLISION_NODE;
+ if (is_object[nearest_boxindex]) {
+ info.type = COLLISION_OBJECT;
+ }
+ else
+ info.type = COLLISION_NODE;
info.node_p = node_positions[nearest_boxindex];
info.bouncy = bouncy;
info.old_speed = speed_f;
diff --git a/src/collision.h b/src/collision.h
index 38cc3efb3..117818456 100644
--- a/src/collision.h
+++ b/src/collision.h
@@ -25,10 +25,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map;
class IGameDef;
+class Environment;
enum CollisionType
{
- COLLISION_NODE
+ COLLISION_NODE,
+ COLLISION_OBJECT,
};
struct CollisionInfo
@@ -65,7 +67,7 @@ struct collisionMoveResult
};
// Moves using a single iteration; speed should not exceed pos_max_d/dtime
-collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
+collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f);
diff --git a/src/connection.cpp b/src/connection.cpp
index 7a3018bfd..7bff5b113 100644
--- a/src/connection.cpp
+++ b/src/connection.cpp
@@ -76,19 +76,20 @@ SharedBuffer<u8> makeOriginalPacket(
return b;
}
-core::list<SharedBuffer<u8> > makeSplitPacket(
+std::list<SharedBuffer<u8> > makeSplitPacket(
SharedBuffer<u8> data,
u32 chunksize_max,
u16 seqnum)
{
// Chunk packets, containing the TYPE_SPLIT header
- core::list<SharedBuffer<u8> > chunks;
+ std::list<SharedBuffer<u8> > chunks;
u32 chunk_header_size = 7;
u32 maximum_data_size = chunksize_max - chunk_header_size;
u32 start = 0;
u32 end = 0;
u32 chunk_num = 0;
+ u16 chunk_count = 0;
do{
end = start + maximum_data_size - 1;
if(end > data.getSize() - 1)
@@ -106,16 +107,15 @@ core::list<SharedBuffer<u8> > makeSplitPacket(
memcpy(&chunk[chunk_header_size], &data[start], payload_size);
chunks.push_back(chunk);
+ chunk_count++;
start = end + 1;
chunk_num++;
}
while(end != data.getSize() - 1);
- u16 chunk_count = chunks.getSize();
-
- core::list<SharedBuffer<u8> >::Iterator i = chunks.begin();
- for(; i != chunks.end(); i++)
+ for(std::list<SharedBuffer<u8> >::iterator i = chunks.begin();
+ i != chunks.end(); ++i)
{
// Write chunk_count
writeU16(&((*i)[3]), chunk_count);
@@ -124,13 +124,13 @@ core::list<SharedBuffer<u8> > makeSplitPacket(
return chunks;
}
-core::list<SharedBuffer<u8> > makeAutoSplitPacket(
+std::list<SharedBuffer<u8> > makeAutoSplitPacket(
SharedBuffer<u8> data,
u32 chunksize_max,
u16 &split_seqnum)
{
u32 original_header_size = 1;
- core::list<SharedBuffer<u8> > list;
+ std::list<SharedBuffer<u8> > list;
if(data.getSize() + original_header_size > chunksize_max)
{
list = makeSplitPacket(data, chunksize_max, split_seqnum);
@@ -170,11 +170,13 @@ SharedBuffer<u8> makeReliablePacket(
ReliablePacketBuffer
*/
+ReliablePacketBuffer::ReliablePacketBuffer(): m_list_size(0) {}
+
void ReliablePacketBuffer::print()
{
- core::list<BufferedPacket>::Iterator i;
- i = m_list.begin();
- for(; i != m_list.end(); i++)
+ for(std::list<BufferedPacket>::iterator i = m_list.begin();
+ i != m_list.end();
+ ++i)
{
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
dout_con<<s<<" ";
@@ -186,13 +188,12 @@ bool ReliablePacketBuffer::empty()
}
u32 ReliablePacketBuffer::size()
{
- return m_list.getSize();
+ return m_list_size;
}
RPBSearchResult ReliablePacketBuffer::findPacket(u16 seqnum)
{
- core::list<BufferedPacket>::Iterator i;
- i = m_list.begin();
- for(; i != m_list.end(); i++)
+ std::list<BufferedPacket>::iterator i = m_list.begin();
+ for(; i != m_list.end(); ++i)
{
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
/*dout_con<<"findPacket(): finding seqnum="<<seqnum
@@ -218,8 +219,8 @@ BufferedPacket ReliablePacketBuffer::popFirst()
if(empty())
throw NotFoundException("Buffer is empty");
BufferedPacket p = *m_list.begin();
- core::list<BufferedPacket>::Iterator i = m_list.begin();
- m_list.erase(i);
+ m_list.erase(m_list.begin());
+ --m_list_size;
return p;
}
BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
@@ -231,6 +232,7 @@ BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
}
BufferedPacket p = *r;
m_list.erase(r);
+ --m_list_size;
return p;
}
void ReliablePacketBuffer::insert(BufferedPacket &p)
@@ -240,6 +242,7 @@ void ReliablePacketBuffer::insert(BufferedPacket &p)
assert(type == TYPE_RELIABLE);
u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE+1]);
+ ++m_list_size;
// Find the right place for the packet and insert it there
// If list is empty, just add it
@@ -250,12 +253,12 @@ void ReliablePacketBuffer::insert(BufferedPacket &p)
return;
}
// Otherwise find the right place
- core::list<BufferedPacket>::Iterator i;
- i = m_list.begin();
+ std::list<BufferedPacket>::iterator i = m_list.begin();
// Find the first packet in the list which has a higher seqnum
- for(; i != m_list.end(); i++){
+ for(; i != m_list.end(); ++i){
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
if(s == seqnum){
+ --m_list_size;
throw AlreadyExistsException("Same seqnum in list");
}
if(seqnum_higher(s, seqnum)){
@@ -271,14 +274,14 @@ void ReliablePacketBuffer::insert(BufferedPacket &p)
return;
}
// Insert before i
- m_list.insert_before(i, p);
+ m_list.insert(i, p);
}
void ReliablePacketBuffer::incrementTimeouts(float dtime)
{
- core::list<BufferedPacket>::Iterator i;
- i = m_list.begin();
- for(; i != m_list.end(); i++){
+ for(std::list<BufferedPacket>::iterator i = m_list.begin();
+ i != m_list.end(); ++i)
+ {
i->time += dtime;
i->totaltime += dtime;
}
@@ -286,9 +289,9 @@ void ReliablePacketBuffer::incrementTimeouts(float dtime)
void ReliablePacketBuffer::resetTimedOuts(float timeout)
{
- core::list<BufferedPacket>::Iterator i;
- i = m_list.begin();
- for(; i != m_list.end(); i++){
+ for(std::list<BufferedPacket>::iterator i = m_list.begin();
+ i != m_list.end(); ++i)
+ {
if(i->time >= timeout)
i->time = 0.0;
}
@@ -296,21 +299,20 @@ void ReliablePacketBuffer::resetTimedOuts(float timeout)
bool ReliablePacketBuffer::anyTotaltimeReached(float timeout)
{
- core::list<BufferedPacket>::Iterator i;
- i = m_list.begin();
- for(; i != m_list.end(); i++){
+ for(std::list<BufferedPacket>::iterator i = m_list.begin();
+ i != m_list.end(); ++i)
+ {
if(i->totaltime >= timeout)
return true;
}
return false;
}
-core::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout)
+std::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout)
{
- core::list<BufferedPacket> timed_outs;
- core::list<BufferedPacket>::Iterator i;
- i = m_list.begin();
- for(; i != m_list.end(); i++)
+ std::list<BufferedPacket> timed_outs;
+ for(std::list<BufferedPacket>::iterator i = m_list.begin();
+ i != m_list.end(); ++i)
{
if(i->time >= timeout)
timed_outs.push_back(*i);
@@ -324,11 +326,10 @@ core::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout)
IncomingSplitBuffer::~IncomingSplitBuffer()
{
- core::map<u16, IncomingSplitPacket*>::Iterator i;
- i = m_buf.getIterator();
- for(; i.atEnd() == false; i++)
+ for(std::map<u16, IncomingSplitPacket*>::iterator i = m_buf.begin();
+ i != m_buf.end(); ++i)
{
- delete i.getNode()->getValue();
+ delete i->second;
}
}
/*
@@ -346,7 +347,7 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
u16 chunk_num = readU16(&p.data[BASE_HEADER_SIZE+5]);
// Add if doesn't exist
- if(m_buf.find(seqnum) == NULL)
+ if(m_buf.find(seqnum) == m_buf.end())
{
IncomingSplitPacket *sp = new IncomingSplitPacket();
sp->chunk_count = chunk_count;
@@ -369,7 +370,7 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
// If chunk already exists, ignore it.
// Sometimes two identical packets may arrive when there is network
// lag and the server re-sends stuff.
- if(sp->chunks.find(chunk_num) != NULL)
+ if(sp->chunks.find(chunk_num) != sp->chunks.end())
return SharedBuffer<u8>();
// Cut chunk data out of packet
@@ -386,11 +387,10 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
// Calculate total size
u32 totalsize = 0;
- core::map<u16, SharedBuffer<u8> >::Iterator i;
- i = sp->chunks.getIterator();
- for(; i.atEnd() == false; i++)
+ for(std::map<u16, SharedBuffer<u8> >::iterator i = sp->chunks.begin();
+ i != sp->chunks.end(); ++i)
{
- totalsize += i.getNode()->getValue().getSize();
+ totalsize += i->second.getSize();
}
SharedBuffer<u8> fulldata(totalsize);
@@ -407,34 +407,32 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
}
// Remove sp from buffer
- m_buf.remove(seqnum);
+ m_buf.erase(seqnum);
delete sp;
return fulldata;
}
void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout)
{
- core::list<u16> remove_queue;
- core::map<u16, IncomingSplitPacket*>::Iterator i;
- i = m_buf.getIterator();
- for(; i.atEnd() == false; i++)
+ std::list<u16> remove_queue;
+ for(std::map<u16, IncomingSplitPacket*>::iterator i = m_buf.begin();
+ i != m_buf.end(); ++i)
{
- IncomingSplitPacket *p = i.getNode()->getValue();
+ IncomingSplitPacket *p = i->second;
// Reliable ones are not removed by timeout
if(p->reliable == true)
continue;
p->time += dtime;
if(p->time >= timeout)
- remove_queue.push_back(i.getNode()->getKey());
+ remove_queue.push_back(i->first);
}
- core::list<u16>::Iterator j;
- j = remove_queue.begin();
- for(; j != remove_queue.end(); j++)
+ for(std::list<u16>::iterator j = remove_queue.begin();
+ j != remove_queue.end(); ++j)
{
dout_con<<"NOTE: Removing timed out unreliable split packet"
<<std::endl;
delete m_buf[*j];
- m_buf.remove(*j);
+ m_buf.erase(*j);
}
}
@@ -556,12 +554,11 @@ Connection::~Connection()
{
stop();
// Delete peers
- for(core::map<u16, Peer*>::Iterator
- j = m_peers.getIterator();
- j.atEnd() == false; j++)
+ for(std::map<u16, Peer*>::iterator
+ j = m_peers.begin();
+ j != m_peers.end(); ++j)
{
- Peer *peer = j.getNode()->getValue();
- delete peer;
+ delete j->second;
}
}
@@ -591,7 +588,7 @@ void * Connection::Thread()
runTimeouts(dtime);
- while(m_command_queue.size() != 0){
+ while(!m_command_queue.empty()){
ConnectionCommand c = m_command_queue.pop_front();
processCommand(c);
}
@@ -648,18 +645,18 @@ void Connection::processCommand(ConnectionCommand &c)
void Connection::send(float dtime)
{
- for(core::map<u16, Peer*>::Iterator
- j = m_peers.getIterator();
- j.atEnd() == false; j++)
+ for(std::map<u16, Peer*>::iterator
+ j = m_peers.begin();
+ j != m_peers.end(); ++j)
{
- Peer *peer = j.getNode()->getValue();
+ Peer *peer = j->second;
peer->m_sendtime_accu += dtime;
peer->m_num_sent = 0;
peer->m_max_num_sent = peer->m_sendtime_accu *
peer->m_max_packets_per_second;
}
Queue<OutgoingPacket> postponed_packets;
- while(m_outgoing_queue.size() != 0){
+ while(!m_outgoing_queue.empty()){
OutgoingPacket packet = m_outgoing_queue.pop_front();
Peer *peer = getPeerNoEx(packet.peer_id);
if(!peer)
@@ -674,14 +671,14 @@ void Connection::send(float dtime)
postponed_packets.push_back(packet);
}
}
- while(postponed_packets.size() != 0){
+ while(!postponed_packets.empty()){
m_outgoing_queue.push_back(postponed_packets.pop_front());
}
- for(core::map<u16, Peer*>::Iterator
- j = m_peers.getIterator();
- j.atEnd() == false; j++)
+ for(std::map<u16, Peer*>::iterator
+ j = m_peers.begin();
+ j != m_peers.end(); ++j)
{
- Peer *peer = j.getNode()->getValue();
+ Peer *peer = j->second;
peer->m_sendtime_accu -= (float)peer->m_num_sent /
peer->m_max_packets_per_second;
if(peer->m_sendtime_accu > 10. / peer->m_max_packets_per_second)
@@ -751,11 +748,11 @@ void Connection::receive()
Allow only entries that have has_sent_with_id==false.
*/
- core::map<u16, Peer*>::Iterator j;
- j = m_peers.getIterator();
- for(; j.atEnd() == false; j++)
+ std::map<u16, Peer*>::iterator j;
+ j = m_peers.begin();
+ for(; j != m_peers.end(); ++j)
{
- Peer *peer = j.getNode()->getValue();
+ Peer *peer = j->second;
if(peer->has_sent_with_id)
continue;
if(peer->address == sender)
@@ -766,14 +763,14 @@ void Connection::receive()
If no peer was found with the same address and port,
we shall assume it is a new peer and create an entry.
*/
- if(j.atEnd())
+ if(j == m_peers.end())
{
// Pass on to adding the peer
}
// Else: A peer was found.
else
{
- Peer *peer = j.getNode()->getValue();
+ Peer *peer = j->second;
peer_id = peer->id;
PrintInfo(derr_con);
derr_con<<"WARNING: Assuming unknown peer to be "
@@ -797,7 +794,7 @@ void Connection::receive()
for(;;)
{
// Check if exists
- if(m_peers.find(peer_id_new) == NULL)
+ if(m_peers.find(peer_id_new) == m_peers.end())
break;
// Check for overflow
if(peer_id_new == 65535){
@@ -817,7 +814,7 @@ void Connection::receive()
// Create a peer
Peer *peer = new Peer(peer_id_new, sender);
- m_peers.insert(peer->id, peer);
+ m_peers[peer->id] = peer;
// Create peer addition event
ConnectionEvent e;
@@ -837,9 +834,9 @@ void Connection::receive()
// Go on and process whatever it sent
}
- core::map<u16, Peer*>::Node *node = m_peers.find(peer_id);
+ std::map<u16, Peer*>::iterator node = m_peers.find(peer_id);
- if(node == NULL)
+ if(node == m_peers.end())
{
// Peer not found
// This means that the peer id of the sender is not PEER_ID_INEXISTENT
@@ -849,7 +846,7 @@ void Connection::receive()
throw InvalidIncomingDataException("Peer not found (possible timeout)");
}
- Peer *peer = node->getValue();
+ Peer *peer = node->second;
// Validate peer address
if(peer->address != sender)
@@ -902,12 +899,11 @@ void Connection::runTimeouts(float dtime)
float congestion_control_min_rate
= g_settings->getFloat("congestion_control_min_rate");
- core::list<u16> timeouted_peers;
- core::map<u16, Peer*>::Iterator j;
- j = m_peers.getIterator();
- for(; j.atEnd() == false; j++)
+ std::list<u16> timeouted_peers;
+ for(std::map<u16, Peer*>::iterator j = m_peers.begin();
+ j != m_peers.end(); ++j)
{
- Peer *peer = j.getNode()->getValue();
+ Peer *peer = j->second;
// Update congestion control values
peer->congestion_control_aim_rtt = congestion_control_aim_rtt;
@@ -934,8 +930,7 @@ void Connection::runTimeouts(float dtime)
float resend_timeout = peer->resend_timeout;
for(u16 i=0; i<CHANNEL_COUNT; i++)
{
- core::list<BufferedPacket> timed_outs;
- core::list<BufferedPacket>::Iterator j;
+ std::list<BufferedPacket> timed_outs;
Channel *channel = &peer->channels[i];
@@ -966,8 +961,8 @@ void Connection::runTimeouts(float dtime)
channel->outgoing_reliables.resetTimedOuts(resend_timeout);
- j = timed_outs.begin();
- for(; j != timed_outs.end(); j++)
+ for(std::list<BufferedPacket>::iterator j = timed_outs.begin();
+ j != timed_outs.end(); ++j)
{
u16 peer_id = readPeerId(*(j->data));
u8 channel = readChannel(*(j->data));
@@ -1012,8 +1007,8 @@ nextpeer:
}
// Remove timed out peers
- core::list<u16>::Iterator i = timeouted_peers.begin();
- for(; i != timeouted_peers.end(); i++)
+ for(std::list<u16>::iterator i = timeouted_peers.begin();
+ i != timeouted_peers.end(); ++i)
{
PrintInfo(derr_con);
derr_con<<"RunTimeouts(): Removing peer "<<(*i)<<std::endl;
@@ -1041,13 +1036,13 @@ void Connection::connect(Address address)
dout_con<<getDesc()<<" connecting to "<<address.serializeString()
<<":"<<address.getPort()<<std::endl;
- core::map<u16, Peer*>::Node *node = m_peers.find(PEER_ID_SERVER);
- if(node != NULL){
+ std::map<u16, Peer*>::iterator node = m_peers.find(PEER_ID_SERVER);
+ if(node != m_peers.end()){
throw ConnectionException("Already connected to a server");
}
Peer *peer = new Peer(PEER_ID_SERVER, address);
- m_peers.insert(peer->id, peer);
+ m_peers[peer->id] = peer;
// Create event
ConnectionEvent e;
@@ -1072,22 +1067,20 @@ void Connection::disconnect()
writeU8(&data[1], CONTROLTYPE_DISCO);
// Send to all
- core::map<u16, Peer*>::Iterator j;
- j = m_peers.getIterator();
- for(; j.atEnd() == false; j++)
+ for(std::map<u16, Peer*>::iterator j = m_peers.begin();
+ j != m_peers.end(); ++j)
{
- Peer *peer = j.getNode()->getValue();
+ Peer *peer = j->second;
rawSendAsPacket(peer->id, 0, data, false);
}
}
void Connection::sendToAll(u8 channelnum, SharedBuffer<u8> data, bool reliable)
{
- core::map<u16, Peer*>::Iterator j;
- j = m_peers.getIterator();
- for(; j.atEnd() == false; j++)
+ for(std::map<u16, Peer*>::iterator j = m_peers.begin();
+ j != m_peers.end(); ++j)
{
- Peer *peer = j.getNode()->getValue();
+ Peer *peer = j->second;
send(peer->id, channelnum, data, reliable);
}
}
@@ -1108,13 +1101,12 @@ void Connection::send(u16 peer_id, u8 channelnum,
if(reliable)
chunksize_max -= RELIABLE_HEADER_SIZE;
- core::list<SharedBuffer<u8> > originals;
+ std::list<SharedBuffer<u8> > originals;
originals = makeAutoSplitPacket(data, chunksize_max,
channel->next_outgoing_split_seqnum);
- core::list<SharedBuffer<u8> >::Iterator i;
- i = originals.begin();
- for(; i != originals.end(); i++)
+ for(std::list<SharedBuffer<u8> >::iterator i = originals.begin();
+ i != originals.end(); ++i)
{
SharedBuffer<u8> original = *i;
@@ -1187,40 +1179,39 @@ void Connection::rawSend(const BufferedPacket &packet)
Peer* Connection::getPeer(u16 peer_id)
{
- core::map<u16, Peer*>::Node *node = m_peers.find(peer_id);
+ std::map<u16, Peer*>::iterator node = m_peers.find(peer_id);
- if(node == NULL){
+ if(node == m_peers.end()){
throw PeerNotFoundException("GetPeer: Peer not found (possible timeout)");
}
// Error checking
- assert(node->getValue()->id == peer_id);
+ assert(node->second->id == peer_id);
- return node->getValue();
+ return node->second;
}
Peer* Connection::getPeerNoEx(u16 peer_id)
{
- core::map<u16, Peer*>::Node *node = m_peers.find(peer_id);
+ std::map<u16, Peer*>::iterator node = m_peers.find(peer_id);
- if(node == NULL){
+ if(node == m_peers.end()){
return NULL;
}
// Error checking
- assert(node->getValue()->id == peer_id);
+ assert(node->second->id == peer_id);
- return node->getValue();
+ return node->second;
}
-core::list<Peer*> Connection::getPeers()
+std::list<Peer*> Connection::getPeers()
{
- core::list<Peer*> list;
- core::map<u16, Peer*>::Iterator j;
- j = m_peers.getIterator();
- for(; j.atEnd() == false; j++)
+ std::list<Peer*> list;
+ for(std::map<u16, Peer*>::iterator j = m_peers.begin();
+ j != m_peers.end(); ++j)
{
- Peer *peer = j.getNode()->getValue();
+ Peer *peer = j->second;
list.push_back(peer);
}
return list;
@@ -1228,11 +1219,10 @@ core::list<Peer*> Connection::getPeers()
bool Connection::getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst)
{
- core::map<u16, Peer*>::Iterator j;
- j = m_peers.getIterator();
- for(; j.atEnd() == false; j++)
+ for(std::map<u16, Peer*>::iterator j = m_peers.begin();
+ j != m_peers.end(); ++j)
{
- Peer *peer = j.getNode()->getValue();
+ Peer *peer = j->second;
for(u16 i=0; i<CHANNEL_COUNT; i++)
{
Channel *channel = &peer->channels[i];
@@ -1538,7 +1528,7 @@ SharedBuffer<u8> Connection::processPacket(Channel *channel,
bool Connection::deletePeer(u16 peer_id, bool timeout)
{
- if(m_peers.find(peer_id) == NULL)
+ if(m_peers.find(peer_id) == m_peers.end())
return false;
Peer *peer = m_peers[peer_id];
@@ -1549,7 +1539,7 @@ bool Connection::deletePeer(u16 peer_id, bool timeout)
putEvent(e);
delete m_peers[peer_id];
- m_peers.remove(peer_id);
+ m_peers.erase(peer_id);
return true;
}
@@ -1557,7 +1547,7 @@ bool Connection::deletePeer(u16 peer_id, bool timeout)
ConnectionEvent Connection::getEvent()
{
- if(m_event_queue.size() == 0){
+ if(m_event_queue.empty()){
ConnectionEvent e;
e.type = CONNEVENT_NONE;
return e;
@@ -1602,8 +1592,8 @@ bool Connection::Connected()
if(m_peers.size() != 1)
return false;
- core::map<u16, Peer*>::Node *node = m_peers.find(PEER_ID_SERVER);
- if(node == NULL)
+ std::map<u16, Peer*>::iterator node = m_peers.find(PEER_ID_SERVER);
+ if(node == m_peers.end())
return false;
if(m_peer_id == PEER_ID_INEXISTENT)
diff --git a/src/connection.h b/src/connection.h
index 05b1ca2e8..486cf331f 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/thread.h"
#include <iostream>
#include <fstream>
+#include <list>
+#include <map>
namespace con
{
@@ -142,14 +144,14 @@ SharedBuffer<u8> makeOriginalPacket(
SharedBuffer<u8> data);
// Split data in chunks and add TYPE_SPLIT headers to them
-core::list<SharedBuffer<u8> > makeSplitPacket(
+std::list<SharedBuffer<u8> > makeSplitPacket(
SharedBuffer<u8> data,
u32 chunksize_max,
u16 seqnum);
// Depending on size, make a TYPE_ORIGINAL or TYPE_SPLIT packet
// Increments split_seqnum if a split packet is made
-core::list<SharedBuffer<u8> > makeAutoSplitPacket(
+std::list<SharedBuffer<u8> > makeAutoSplitPacket(
SharedBuffer<u8> data,
u32 chunksize_max,
u16 &split_seqnum);
@@ -167,7 +169,7 @@ struct IncomingSplitPacket
reliable = false;
}
// Key is chunk number, value is data without headers
- core::map<u16, SharedBuffer<u8> > chunks;
+ std::map<u16, SharedBuffer<u8> > chunks;
u32 chunk_count;
float time; // Seconds from adding
bool reliable; // If true, isn't deleted on timeout
@@ -268,12 +270,12 @@ with a buffer in the receiving and transmitting end.
for fast access to the smallest one.
*/
-typedef core::list<BufferedPacket>::Iterator RPBSearchResult;
+typedef std::list<BufferedPacket>::iterator RPBSearchResult;
class ReliablePacketBuffer
{
public:
-
+ ReliablePacketBuffer();
void print();
bool empty();
u32 size();
@@ -286,10 +288,11 @@ public:
void incrementTimeouts(float dtime);
void resetTimedOuts(float timeout);
bool anyTotaltimeReached(float timeout);
- core::list<BufferedPacket> getTimedOuts(float timeout);
+ std::list<BufferedPacket> getTimedOuts(float timeout);
private:
- core::list<BufferedPacket> m_list;
+ std::list<BufferedPacket> m_list;
+ u16 m_list_size;
};
/*
@@ -310,7 +313,7 @@ public:
private:
// Key is seqnum
- core::map<u16, IncomingSplitPacket*> m_buf;
+ std::map<u16, IncomingSplitPacket*> m_buf;
};
class Connection;
@@ -589,7 +592,7 @@ private:
void rawSend(const BufferedPacket &packet);
Peer* getPeer(u16 peer_id);
Peer* getPeerNoEx(u16 peer_id);
- core::list<Peer*> getPeers();
+ std::list<Peer*> getPeers();
bool getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst);
// Returns next data from a buffer if possible
// If found, returns true; if not, false.
@@ -619,7 +622,7 @@ private:
UDPSocket m_socket;
u16 m_peer_id;
- core::map<u16, Peer*> m_peers;
+ std::map<u16, Peer*> m_peers;
JMutex m_peers_mutex;
// Backwards compatibility
diff --git a/src/content_abm.cpp b/src/content_abm.cpp
index 03fc82ed4..ccd9ca19c 100644
--- a/src/content_abm.cpp
+++ b/src/content_abm.cpp
@@ -94,11 +94,22 @@ public:
class MakeTreesFromSaplingsABM : public ActiveBlockModifier
{
private:
+ content_t c_junglesapling;
+ content_t c_dirt;
+ content_t c_dirt_with_grass;
+
public:
+ MakeTreesFromSaplingsABM(ServerEnvironment *env, INodeDefManager *nodemgr) {
+ c_junglesapling = nodemgr->getId("junglesapling");
+ c_dirt = nodemgr->getId("mapgen_dirt");
+ c_dirt_with_grass = nodemgr->getId("mapgen_dirt_with_grass");
+ }
+
virtual std::set<std::string> getTriggerContents()
{
std::set<std::string> s;
s.insert("sapling");
+ s.insert("junglesapling");
return s;
}
virtual float getTriggerInterval()
@@ -111,37 +122,46 @@ public:
INodeDefManager *ndef = env->getGameDef()->ndef();
ServerMap *map = &env->getServerMap();
- actionstream<<"A sapling grows into a tree at "
- <<PP(p)<<std::endl;
+ MapNode n_below = map->getNodeNoEx(p - v3s16(0, 1, 0));
+ if (n_below.getContent() != c_dirt &&
+ n_below.getContent() != c_dirt_with_grass)
+ return;
+
+ bool is_jungle_tree = n.getContent() == c_junglesapling;
+
+ actionstream <<"A " << (is_jungle_tree ? "jungle " : "")
+ << "sapling grows into a tree at "
+ << PP(p) << std::endl;
- core::map<v3s16, MapBlock*> modified_blocks;
+ std::map<v3s16, MapBlock*> modified_blocks;
v3s16 tree_p = p;
ManualMapVoxelManipulator vmanip(map);
v3s16 tree_blockp = getNodeBlockPos(tree_p);
vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1));
- bool is_apple_tree = myrand()%4 == 0;
- treegen::make_tree(vmanip, tree_p, is_apple_tree, ndef, myrand());
+
+ if (is_jungle_tree) {
+ treegen::make_jungletree(vmanip, tree_p, ndef, myrand());
+ } else {
+ bool is_apple_tree = myrand() % 4 == 0;
+ treegen::make_tree(vmanip, tree_p, is_apple_tree, ndef, myrand());
+ }
+
vmanip.blitBackAll(&modified_blocks);
// update lighting
- core::map<v3s16, MapBlock*> lighting_modified_blocks;
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
- {
- lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
- }
+ std::map<v3s16, MapBlock*> lighting_modified_blocks;
+ lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
map->updateLighting(lighting_modified_blocks, modified_blocks);
// Send a MEET_OTHER event
MapEditEvent event;
event.type = MEET_OTHER;
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
+// event.modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
- event.modified_blocks.insert(p, true);
+ event.modified_blocks.insert(i->first);
}
map->dispatchEvent(&event);
}
@@ -182,7 +202,7 @@ void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef)
{
env->addActiveBlockModifier(new GrowGrassABM());
env->addActiveBlockModifier(new RemoveGrassABM());
- env->addActiveBlockModifier(new MakeTreesFromSaplingsABM());
+ env->addActiveBlockModifier(new MakeTreesFromSaplingsABM(env, nodedef));
if (g_settings->getBool("liquid_finite"))
env->addActiveBlockModifier(new LiquidFlowABM(env, nodedef));
}
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index 5e5cb38ae..ee1009b6c 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -50,7 +50,7 @@ struct ToolCapabilities;
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
+std::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
/*
SmoothTranslator
@@ -174,6 +174,7 @@ public:
void processMessage(const std::string &data);
+ bool getCollisionBox(aabb3f *toset) { return false; }
private:
scene::IMeshSceneNode *m_node;
v3f m_position;
@@ -329,6 +330,7 @@ public:
std::string infoText()
{return m_infotext;}
+ bool getCollisionBox(aabb3f *toset) { return false; }
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
@@ -643,6 +645,22 @@ public:
ClientActiveObject::registerType(getType(), create);
}
+ bool getCollisionBox(aabb3f *toset) {
+ if (m_prop.physical) {
+ aabb3f retval;
+ //update collision box
+ toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
+ toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
+
+ toset->MinEdge += m_position;
+ toset->MaxEdge += m_position;
+
+ return true;
+ }
+
+ return false;
+ }
+
void initialize(const std::string &data)
{
infostream<<"GenericCAO: Got init data"<<std::endl;
@@ -1127,8 +1145,7 @@ public:
v3f p_pos = m_position;
v3f p_velocity = m_velocity;
v3f p_acceleration = m_acceleration;
- IGameDef *gamedef = env->getGameDef();
- moveresult = collisionMoveSimple(&env->getMap(), gamedef,
+ moveresult = collisionMoveSimple(env,env->getGameDef(),
pos_max_d, box, stepheight, dtime,
p_pos, p_velocity, p_acceleration);
// Apply results
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index 0d80dc173..84d5f067c 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -42,14 +42,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// (compatible with ContentFeatures). If you specified 0,0,1,1
// for each face, that would be the same as passing NULL.
void makeCuboid(MeshCollector *collector, const aabb3f &box,
- const TileSpec *tiles, int tilecount,
+ TileSpec *tiles, int tilecount,
video::SColor &c, const f32* txc)
{
assert(tilecount >= 1 && tilecount <= 6);
v3f min = box.MinEdge;
v3f max = box.MaxEdge;
-
+
+
+
if(txc == NULL)
{
static const f32 txc_default[24] = {
@@ -97,15 +99,70 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
};
- for(s32 j=0; j<24; j++)
+ v2f t;
+ for(int i = 0; i < tilecount; i++)
+ {
+ switch (tiles[i].rotation)
+ {
+ case 0:
+ break;
+ case 1: //R90
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
+ break;
+ case 2: //R180
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(180,irr::core::vector2df(0, 0));
+ break;
+ case 3: //R270
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
+ break;
+ case 4: //FXR90
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
+
+ tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
+ tiles[i].texture.size.Y *= -1;
+ break;
+ case 5: //FXR270
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
+ t=vertices[i*4].TCoords;
+ tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
+ tiles[i].texture.size.Y *= -1;
+ break;
+ case 6: //FYR90
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
+ tiles[i].texture.pos.X += tiles[i].texture.size.X;
+ tiles[i].texture.size.X *= -1;
+ break;
+ case 7: //FYR270
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
+ tiles[i].texture.pos.X += tiles[i].texture.size.X;
+ tiles[i].texture.size.X *= -1;
+ break;
+ case 8: //FX
+ tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
+ tiles[i].texture.size.Y *= -1;
+ break;
+ case 9: //FY
+ tiles[i].texture.pos.X += tiles[i].texture.size.X;
+ tiles[i].texture.size.X *= -1;
+ break;
+ default:
+ break;
+ }
+ }
+ for(s32 j=0; j<24; j++)
{
int tileindex = MYMIN(j/4, tilecount-1);
vertices[j].TCoords *= tiles[tileindex].texture.size;
vertices[j].TCoords += tiles[tileindex].texture.pos;
}
-
u16 indices[] = {0,1,2,2,3,0};
-
// Add to mesh collector
for(s32 j=0; j<24; j+=4)
{
@@ -160,18 +217,145 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
Add water sources to mesh if using new style
*/
TileSpec tile_liquid = f.special_tiles[0];
+ TileSpec tile_liquid_bfculled = getNodeTile(n, p, v3s16(0,0,0), data);
AtlasPointer &pa_liquid = tile_liquid.texture;
- bool top_is_air = false;
- MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
- if(n.getContent() == CONTENT_AIR)
- top_is_air = true;
-
- if(top_is_air == false)
- continue;
+ bool top_is_same_liquid = false;
+ MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
+ content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);
+ content_t c_source = nodedef->getId(f.liquid_alternative_source);
+ if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
+ top_is_same_liquid = true;
u16 l = getInteriorLight(n, 0, data);
video::SColor c = MapBlock_LightColor(f.alpha, l, decode_light(f.light_source));
+
+ /*
+ Generate sides
+ */
+ v3s16 side_dirs[4] = {
+ v3s16(1,0,0),
+ v3s16(-1,0,0),
+ v3s16(0,0,1),
+ v3s16(0,0,-1),
+ };
+ for(u32 i=0; i<4; i++)
+ {
+ v3s16 dir = side_dirs[i];
+
+ MapNode neighbor = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir);
+ content_t neighbor_content = neighbor.getContent();
+ const ContentFeatures &n_feat = nodedef->get(neighbor_content);
+ MapNode n_top = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir+ v3s16(0,1,0));
+ content_t n_top_c = n_top.getContent();
+
+ if(neighbor_content == CONTENT_IGNORE)
+ continue;
+
+ /*
+ If our topside is liquid and neighbor's topside
+ is liquid, don't draw side face
+ */
+ if(top_is_same_liquid && (n_top_c == c_flowing ||
+ n_top_c == c_source || n_top_c == CONTENT_IGNORE))
+ continue;
+
+ // Don't draw face if neighbor is blocking the view
+ if(n_feat.solidness == 2)
+ continue;
+
+ bool neighbor_is_same_liquid = (neighbor_content == c_source
+ || neighbor_content == c_flowing);
+
+ // Don't draw any faces if neighbor same is liquid and top is
+ // same liquid
+ if(neighbor_is_same_liquid && !top_is_same_liquid)
+ continue;
+
+ // Use backface culled material if neighbor doesn't have a
+ // solidness of 0
+ const TileSpec *current_tile = &tile_liquid;
+ if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
+ current_tile = &tile_liquid_bfculled;
+
+ video::S3DVertex vertices[4] =
+ {
+ video::S3DVertex(-BS/2,0,BS/2,0,0,0, c,
+ pa_liquid.x0(), pa_liquid.y1()),
+ video::S3DVertex(BS/2,0,BS/2,0,0,0, c,
+ pa_liquid.x1(), pa_liquid.y1()),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
+ pa_liquid.x1(), pa_liquid.y0()),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
+ pa_liquid.x0(), pa_liquid.y0()),
+ };
+
+ /*
+ If our topside is liquid, set upper border of face
+ at upper border of node
+ */
+ if(top_is_same_liquid)
+ {
+ vertices[2].Pos.Y = 0.5*BS;
+ vertices[3].Pos.Y = 0.5*BS;
+ }
+ /*
+ Otherwise upper position of face is liquid level
+ */
+ else
+ {
+ vertices[2].Pos.Y = (node_liquid_level-0.5)*BS;
+ vertices[3].Pos.Y = (node_liquid_level-0.5)*BS;
+ }
+ /*
+ If neighbor is liquid, lower border of face is liquid level
+ */
+ if(neighbor_is_same_liquid)
+ {
+ vertices[0].Pos.Y = (node_liquid_level-0.5)*BS;
+ vertices[1].Pos.Y = (node_liquid_level-0.5)*BS;
+ }
+ /*
+ If neighbor is not liquid, lower border of face is
+ lower border of node
+ */
+ else
+ {
+ vertices[0].Pos.Y = -0.5*BS;
+ vertices[1].Pos.Y = -0.5*BS;
+ }
+
+ for(s32 j=0; j<4; j++)
+ {
+ if(dir == v3s16(0,0,1))
+ vertices[j].Pos.rotateXZBy(0);
+ if(dir == v3s16(0,0,-1))
+ vertices[j].Pos.rotateXZBy(180);
+ if(dir == v3s16(-1,0,0))
+ vertices[j].Pos.rotateXZBy(90);
+ if(dir == v3s16(1,0,-0))
+ vertices[j].Pos.rotateXZBy(-90);
+
+ // Do this to not cause glitches when two liquids are
+ // side-by-side
+ /*if(neighbor_is_same_liquid == false){
+ vertices[j].Pos.X *= 0.98;
+ vertices[j].Pos.Z *= 0.98;
+ }*/
+
+ vertices[j].Pos += intToFloat(p, BS);
+ }
+
+ u16 indices[] = {0,1,2,2,3,0};
+ // Add to mesh collector
+ collector.append(*current_tile, vertices, 4, indices, 6);
+ }
+
+ /*
+ Generate top
+ */
+ if(top_is_same_liquid)
+ continue;
video::S3DVertex vertices[4] =
{
@@ -185,7 +369,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
pa_liquid.x0(), pa_liquid.y0()),
};
- v3f offset(p.X, p.Y + (-0.5+node_liquid_level)*BS, p.Z);
+ v3f offset(p.X*BS, p.Y*BS + (-0.5+node_liquid_level)*BS, p.Z*BS);
for(s32 i=0; i<4; i++)
{
vertices[i].Pos += offset;
@@ -230,9 +414,9 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Neighbor liquid levels (key = relative position)
// Includes current node
- core::map<v3s16, f32> neighbor_levels;
- core::map<v3s16, content_t> neighbor_contents;
- core::map<v3s16, u8> neighbor_flags;
+ std::map<v3s16, f32> neighbor_levels;
+ std::map<v3s16, content_t> neighbor_contents;
+ std::map<v3s16, u8> neighbor_flags;
const u8 neighborflag_top_is_same_liquid = 0x01;
v3s16 neighbor_dirs[9] = {
v3s16(0,0,0),
@@ -273,9 +457,9 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
flags |= neighborflag_top_is_same_liquid;
}
- neighbor_levels.insert(neighbor_dirs[i], level);
- neighbor_contents.insert(neighbor_dirs[i], content);
- neighbor_flags.insert(neighbor_dirs[i], flags);
+ neighbor_levels[neighbor_dirs[i]] = level;
+ neighbor_contents[neighbor_dirs[i]] = content;
+ neighbor_flags[neighbor_dirs[i]] = flags;
}
// Corner heights (average between four liquids)
@@ -324,7 +508,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
}
}
if(air_count >= 2)
- cornerlevel = -0.5*BS+0.1;
+ cornerlevel = -0.5*BS+0.2;
else if(valid_count > 0)
cornerlevel /= valid_count;
corner_levels[i] = cornerlevel;
@@ -1027,14 +1211,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
v3s16(0, 0, 1),
v3s16(0, 0, -1)
};
-
TileSpec tiles[6];
- for(int i = 0; i < 6; i++)
- {
- // Handles facedir rotation for textures
- tiles[i] = getNodeTile(n, p, tile_dirs[i], data);
- }
-
+
u16 l = getInteriorLight(n, 0, data);
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
@@ -1045,17 +1223,43 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
i = boxes.begin();
i != boxes.end(); i++)
{
+ for(int j = 0; j < 6; j++)
+ {
+ // Handles facedir rotation for textures
+ tiles[j] = getNodeTile(n, p, tile_dirs[j], data);
+ }
aabb3f box = *i;
box.MinEdge += pos;
box.MaxEdge += pos;
+
+ f32 temp;
+ if (box.MinEdge.X > box.MaxEdge.X)
+ {
+ temp=box.MinEdge.X;
+ box.MinEdge.X=box.MaxEdge.X;
+ box.MaxEdge.X=temp;
+ }
+ if (box.MinEdge.Y > box.MaxEdge.Y)
+ {
+ temp=box.MinEdge.Y;
+ box.MinEdge.Y=box.MaxEdge.Y;
+ box.MaxEdge.Y=temp;
+ }
+ if (box.MinEdge.Z > box.MaxEdge.Z)
+ {
+ temp=box.MinEdge.Z;
+ box.MinEdge.Z=box.MaxEdge.Z;
+ box.MaxEdge.Z=temp;
+ }
+ //
// Compute texture coords
- f32 tx1 = (i->MinEdge.X/BS)+0.5;
- f32 ty1 = (i->MinEdge.Y/BS)+0.5;
- f32 tz1 = (i->MinEdge.Z/BS)+0.5;
- f32 tx2 = (i->MaxEdge.X/BS)+0.5;
- f32 ty2 = (i->MaxEdge.Y/BS)+0.5;
- f32 tz2 = (i->MaxEdge.Z/BS)+0.5;
+ f32 tx1 = (box.MinEdge.X/BS)+0.5;
+ f32 ty1 = (box.MinEdge.Y/BS)+0.5;
+ f32 tz1 = (box.MinEdge.Z/BS)+0.5;
+ f32 tx2 = (box.MaxEdge.X/BS)+0.5;
+ f32 ty2 = (box.MaxEdge.Y/BS)+0.5;
+ f32 tz2 = (box.MaxEdge.Z/BS)+0.5;
f32 txc[24] = {
// up
tx1, 1-tz2, tx2, 1-tz1,
@@ -1070,7 +1274,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// front
tx1, 1-ty2, tx2, 1-ty1,
};
-
makeCuboid(&collector, box, tiles, 6, c, txc);
}
break;}
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index 718a42dff..ae08b4260 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "genericobject.h"
#include "util/serialize.h"
-core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
+std::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
/*
DummyLoadSAO
@@ -64,6 +64,10 @@ public:
infostream<<"DummyLoadSAO step"<<std::endl;
}
+ bool getCollisionBox(aabb3f *toset) {
+ return false;
+ }
+
private:
};
@@ -132,6 +136,10 @@ public:
}
}
+ bool getCollisionBox(aabb3f *toset) {
+ return false;
+ }
+
private:
float m_timer1;
float m_age;
@@ -208,8 +216,7 @@ public:
v3f pos_f_old = pos_f;
v3f accel_f = v3f(0,0,0);
f32 stepheight = 0;
- IGameDef *gamedef = m_env->getGameDef();
- moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
+ moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
pos_max_d, box, stepheight, dtime,
pos_f, m_speed_f, accel_f);
@@ -314,6 +321,10 @@ public:
return 0;
}
+ bool getCollisionBox(aabb3f *toset) {
+ return false;
+ }
+
private:
std::string m_itemstring;
@@ -370,8 +381,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
}
// Initialize something to armor groups
- m_armor_groups["fleshy"] = 3;
- m_armor_groups["snappy"] = 2;
+ m_armor_groups["fleshy"] = 100;
}
LuaEntitySAO::~LuaEntitySAO()
@@ -490,8 +500,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
v3f p_pos = m_base_position;
v3f p_velocity = m_velocity;
v3f p_acceleration = m_acceleration;
- IGameDef *gamedef = m_env->getGameDef();
- moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
+ moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
pos_max_d, box, stepheight, dtime,
p_pos, p_velocity, p_acceleration);
// Apply results
@@ -880,6 +889,22 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
m_messages_out.push_back(aom);
}
+bool LuaEntitySAO::getCollisionBox(aabb3f *toset) {
+ if (m_prop.physical)
+ {
+ //update collision box
+ toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
+ toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
+
+ toset->MinEdge += m_base_position;
+ toset->MaxEdge += m_base_position;
+
+ return true;
+ }
+
+ return false;
+}
+
/*
PlayerSAO
*/
@@ -916,8 +941,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
assert(m_peer_id != 0);
setBasePosition(m_player->getPosition());
m_inventory = &m_player->inventory;
- m_armor_groups["choppy"] = 2;
- m_armor_groups["fleshy"] = 3;
+ m_armor_groups["fleshy"] = 100;
m_prop.hp_max = PLAYER_MAX_HP;
m_prop.physical = false;
@@ -1230,6 +1254,20 @@ void PlayerSAO::moveTo(v3f pos, bool continuous)
m_moved = true;
}
+void PlayerSAO::setYaw(float yaw)
+{
+ m_player->setYaw(yaw);
+ // Force change on client
+ m_moved = true;
+}
+
+void PlayerSAO::setPitch(float pitch)
+{
+ m_player->setPitch(pitch);
+ // Force change on client
+ m_moved = true;
+}
+
int PlayerSAO::punch(v3f dir,
const ToolCapabilities *toolcap,
ServerActiveObject *puncher,
@@ -1420,3 +1458,7 @@ std::string PlayerSAO::getPropertyPacket()
return gob_cmd_set_properties(m_prop);
}
+bool PlayerSAO::getCollisionBox(aabb3f *toset) {
+ //player collision handling is already done clientside no need to do it twice
+ return false;
+}
diff --git a/src/content_sao.h b/src/content_sao.h
index 2fd1034eb..60ca8f319 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -78,6 +78,7 @@ public:
void setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch);
std::string getName();
+ bool getCollisionBox(aabb3f *toset);
private:
std::string getPropertyPacket();
void sendPosition(bool do_interpolate, bool is_movement_end);
@@ -147,6 +148,8 @@ public:
void setBasePosition(const v3f &position);
void setPos(v3f pos);
void moveTo(v3f pos, bool continuous);
+ void setYaw(float);
+ void setPitch(float);
/*
Interaction interface
@@ -233,6 +236,8 @@ public:
m_is_singleplayer = is_singleplayer;
}
+ bool getCollisionBox(aabb3f *toset);
+
private:
std::string getPropertyPacket();
diff --git a/src/craftdef.cpp b/src/craftdef.cpp
index 99e3fcc3d..c79408f99 100644
--- a/src/craftdef.cpp
+++ b/src/craftdef.cpp
@@ -987,6 +987,43 @@ public:
}
return false;
}
+ virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
+ IGameDef *gamedef) const
+ {
+ std::vector<CraftDefinition*> recipes_list;
+ CraftInput input;
+ CraftOutput tmpout;
+ tmpout.item = "";
+ tmpout.time = 0;
+
+ for(std::vector<CraftDefinition*>::const_reverse_iterator
+ i = m_craft_definitions.rbegin();
+ i != m_craft_definitions.rend(); i++)
+ {
+ CraftDefinition *def = *i;
+
+ /*infostream<<"Checking "<<input.dump()<<std::endl
+ <<" against "<<def->dump()<<std::endl;*/
+
+ try {
+ tmpout = def->getOutput(input, gamedef);
+ if(tmpout.item.substr(0,output.item.length()) == output.item)
+ {
+ // Get output, then decrement input (if requested)
+ input = def->getInput(output, gamedef);
+ recipes_list.push_back(*i);
+ }
+ }
+ catch(SerializationError &e)
+ {
+ errorstream<<"getCraftResult: ERROR: "
+ <<"Serialization error in recipe "
+ <<def->dump()<<std::endl;
+ // then go on with the next craft definition
+ }
+ }
+ return recipes_list;
+ }
virtual std::string dump() const
{
std::ostringstream os(std::ios::binary);
diff --git a/src/craftdef.h b/src/craftdef.h
index eb3cd7e39..14dc53003 100644
--- a/src/craftdef.h
+++ b/src/craftdef.h
@@ -358,6 +358,8 @@ public:
bool decrementInput, IGameDef *gamedef) const=0;
virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
IGameDef *gamedef) const=0;
+ virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
+ IGameDef *gamedef) const=0;
// Print crafting recipes for debugging
virtual std::string dump() const=0;
@@ -376,6 +378,8 @@ public:
bool decrementInput, IGameDef *gamedef) const=0;
virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
IGameDef *gamedef) const=0;
+ virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
+ IGameDef *gamedef) const=0;
// Print crafting recipes for debugging
virtual std::string dump() const=0;
diff --git a/src/debug.cpp b/src/debug.cpp
index e32cceb86..2e4992a78 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -130,7 +130,7 @@ void DebugStack::print(std::ostream &os, bool everything)
os<<"Probably overflown."<<std::endl;
}
-core::map<threadid_t, DebugStack*> g_debug_stacks;
+std::map<threadid_t, DebugStack*> g_debug_stacks;
JMutex g_debug_stacks_mutex;
void debug_stacks_init()
@@ -144,12 +144,11 @@ void debug_stacks_print_to(std::ostream &os)
os<<"Debug stacks:"<<std::endl;
- for(core::map<threadid_t, DebugStack*>::Iterator
- i = g_debug_stacks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<threadid_t, DebugStack*>::iterator
+ i = g_debug_stacks.begin();
+ i != g_debug_stacks.end(); ++i)
{
- DebugStack *stack = i.getNode()->getValue();
- stack->print(os, false);
+ i->second->print(os, false);
}
}
@@ -159,11 +158,11 @@ void debug_stacks_print()
DEBUGPRINT("Debug stacks:\n");
- for(core::map<threadid_t, DebugStack*>::Iterator
- i = g_debug_stacks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<threadid_t, DebugStack*>::iterator
+ i = g_debug_stacks.begin();
+ i != g_debug_stacks.end(); ++i)
{
- DebugStack *stack = i.getNode()->getValue();
+ DebugStack *stack = i->second;
for(int i=0; i<DEBUGSTREAM_COUNT; i++)
{
@@ -179,18 +178,18 @@ DebugStacker::DebugStacker(const char *text)
JMutexAutoLock lock(g_debug_stacks_mutex);
- core::map<threadid_t, DebugStack*>::Node *n;
+ std::map<threadid_t, DebugStack*>::iterator n;
n = g_debug_stacks.find(threadid);
- if(n != NULL)
+ if(n != g_debug_stacks.end())
{
- m_stack = n->getValue();
+ m_stack = n->second;
}
else
{
/*DEBUGPRINT("Creating new debug stack for thread %x\n",
(unsigned int)threadid);*/
m_stack = new DebugStack(threadid);
- g_debug_stacks.insert(threadid, m_stack);
+ g_debug_stacks[threadid] = m_stack;
}
if(m_stack->stack_i >= DEBUG_STACK_SIZE)
@@ -224,7 +223,7 @@ DebugStacker::~DebugStacker()
/*DEBUGPRINT("Deleting debug stack for thread %x\n",
(unsigned int)threadid);*/
delete m_stack;
- g_debug_stacks.remove(threadid);
+ g_debug_stacks.erase(threadid);
}
}
diff --git a/src/debug.h b/src/debug.h
index 56952427c..1b14c4e0a 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "threads.h"
#include "gettime.h"
#include "exceptions.h"
+#include <map>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
@@ -165,7 +166,7 @@ struct DebugStack
int stack_max_i; // Highest i that was seen
};
-extern core::map<threadid_t, DebugStack*> g_debug_stacks;
+extern std::map<threadid_t, DebugStack*> g_debug_stacks;
extern JMutex g_debug_stacks_mutex;
extern void debug_stacks_init();
@@ -205,42 +206,42 @@ public:
void add(u16 command)
{
- core::map<u16, u16>::Node *n = m_packets.find(command);
- if(n == NULL)
+ std::map<u16, u16>::iterator n = m_packets.find(command);
+ if(n == m_packets.end())
{
m_packets[command] = 1;
}
else
{
- n->setValue(n->getValue()+1);
+ n->second++;
}
}
void clear()
{
- for(core::map<u16, u16>::Iterator
- i = m_packets.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, u16>::iterator
+ i = m_packets.begin();
+ i != m_packets.end(); ++i)
{
- i.getNode()->setValue(0);
+ i->second = 0;
}
}
void print(std::ostream &o)
{
- for(core::map<u16, u16>::Iterator
- i = m_packets.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, u16>::iterator
+ i = m_packets.begin();
+ i != m_packets.end(); ++i)
{
- o<<"cmd "<<i.getNode()->getKey()
- <<" count "<<i.getNode()->getValue()
+ o<<"cmd "<<i->first
+ <<" count "<<i->second
<<std::endl;
}
}
private:
// command, count
- core::map<u16, u16> m_packets;
+ std::map<u16, u16> m_packets;
};
/*
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index a8954be72..592c6bcca 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -109,6 +109,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("view_bobbing_amount", "1.0");
settings->setDefault("enable_3d_clouds", "true");
settings->setDefault("cloud_height", "120");
+ settings->setDefault("menu_clouds", "true");
settings->setDefault("opaque_water", "false");
settings->setDefault("console_color", "(0,0,0)");
settings->setDefault("console_alpha", "200");
@@ -202,34 +203,57 @@ void set_default_settings(Settings *settings)
settings->setDefault("movement_liquid_fluidity_smooth", "0.5");
settings->setDefault("movement_liquid_sink", "10");
settings->setDefault("movement_gravity", "9.81");
-
+
//liquid stuff
settings->setDefault("liquid_finite", "false");
settings->setDefault("liquid_update", "1.0");
- settings->setDefault("liquid_relax", "1");
+ settings->setDefault("liquid_relax", "2");
settings->setDefault("liquid_fast_flood", "1");
+ settings->setDefault("underground_springs", "1");
//mapgen stuff
settings->setDefault("mg_name", "v6");
- settings->setDefault("water_level", "1");
+ settings->setDefault("water_level", "1");
settings->setDefault("chunksize", "5");
settings->setDefault("mg_flags", "trees, caves, v6_biome_blend");
settings->setDefault("mgv6_freq_desert", "0.45");
settings->setDefault("mgv6_freq_beach", "0.15");
- settings->setDefault("mgv6_np_terrain_base", "-4, 20, (250.0, 250, 250), 82341, 5, 0.6");
+ settings->setDefault("mgv6_np_terrain_base", "-4, 20, (250, 250, 250), 82341, 5, 0.6");
settings->setDefault("mgv6_np_terrain_higher", "20, 16, (500, 500, 500), 85039, 5, 0.6");
settings->setDefault("mgv6_np_steepness", "0.85, 0.5, (125, 125, 125), -932, 5, 0.7");
settings->setDefault("mgv6_np_height_select", "0.5, 1, (250, 250, 250), 4213, 5, 0.69");
- settings->setDefault("mgv6_np_trees", "0, 1, (125, 125, 125), 2, 4, 0.66");
settings->setDefault("mgv6_np_mud", "4, 2, (200, 200, 200), 91013, 3, 0.55");
settings->setDefault("mgv6_np_beach", "0, 1, (250, 250, 250), 59420, 3, 0.50");
settings->setDefault("mgv6_np_biome", "0, 1, (250, 250, 250), 9130, 3, 0.50");
settings->setDefault("mgv6_np_cave", "6, 6, (250, 250, 250), 34329, 3, 0.50");
+ settings->setDefault("mgv6_np_humidity", "0.5, 0.5, (500, 500, 500), 72384, 4, 0.66");
+ settings->setDefault("mgv6_np_trees", "0, 1, (125, 125, 125), 2, 4, 0.66");
+ settings->setDefault("mgv6_np_apple_trees", "0, 1, (100, 100, 100), 342902, 3, 0.45");
settings->setDefault("mgv7_np_terrain", "10, 12, (350, 350, 350), 82341, 5, 0.6");
settings->setDefault("mgv7_np_bgroup", "0.5, 0.3125, (350, 350, 350), 5923, 2, 0.6");
settings->setDefault("mgv7_np_heat", "25, 50, (500, 500, 500), 35293, 1, 0");
settings->setDefault("mgv7_np_humidity", "50, 31.25, (750, 750, 750), 12094, 2, 0.6");
+
+ settings->setDefault("mgindev_np_terrain_base", "-4, 20, (250, 250, 250), 82341, 5, 0.6, 10, 10");
+ settings->setDefault("mgindev_np_terrain_higher", "20, 16, (500, 500, 500), 85039, 5, 0.6, 10, 10");
+ settings->setDefault("mgindev_np_steepness", "0.85, 0.5, (125, 125, 125), -932, 5, 0.7, 2, 10");
+ settings->setDefault("mgindev_np_mud", "4, 2, (200, 200, 200), 91013, 3, 0.55, 1, 1");
+ settings->setDefault("mgindev_np_float_islands1", "0, 1, (64, 64, 64 ), 3683, 5, 0.5, 1, 1.5");
+ settings->setDefault("mgindev_np_float_islands2", "0, 1, (8, 8, 8 ), 9292, 2, 0.5, 1, 1.5");
+ settings->setDefault("mgindev_np_float_islands3", "0, 1, (256, 256, 256), 6412, 2, 0.5, 1, 0.5");
+ settings->setDefault("mgindev_np_biome", "0, 1, (250, 250, 250), 9130, 3, 0.50, 1, 10");
+ settings->setDefault("mgindev_float_islands", "500");
+
+}
+
+void override_default_settings(Settings *settings, Settings *from)
+{
+ std::vector<std::string> names = from->getNames();
+ for(size_t i=0; i<names.size(); i++){
+ const std::string &name = names[i];
+ settings->setDefault(name, from->get(name));
+ }
}
diff --git a/src/defaultsettings.h b/src/defaultsettings.h
index 37e3f717f..00aacad87 100644
--- a/src/defaultsettings.h
+++ b/src/defaultsettings.h
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Settings;
void set_default_settings(Settings *settings);
+void override_default_settings(Settings *settings, Settings *from);
#endif
diff --git a/src/dungeongen.cpp b/src/dungeongen.cpp
new file mode 100644
index 000000000..9528b4132
--- /dev/null
+++ b/src/dungeongen.cpp
@@ -0,0 +1,634 @@
+/*
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "dungeongen.h"
+#include "mapgen.h"
+#include "voxel.h"
+#include "noise.h"
+#include "mapblock.h"
+#include "mapnode.h"
+#include "map.h"
+#include "nodedef.h"
+#include "profiler.h"
+#include "settings.h" // For g_settings
+#include "main.h" // For g_profiler
+
+NoiseParams nparams_dungeon_rarity =
+ {0.0, 1.0, v3f(500.0, 500.0, 500.0), 0, 2, 0.8};
+NoiseParams nparams_dungeon_wetness =
+ {0.0, 1.0, v3f(40.0, 40.0, 40.0), 32474, 4, 1.1};
+NoiseParams nparams_dungeon_density =
+ {0.0, 1.0, v3f(2.5, 2.5, 2.5), 0, 2, 1.4};
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+
+DungeonGen::DungeonGen(INodeDefManager *ndef, u64 seed, s16 waterlevel) {
+ this->ndef = ndef;
+ this->mapseed = seed;
+ this->water_level = waterlevel;
+
+ np_rarity = &nparams_dungeon_rarity;
+ np_wetness = &nparams_dungeon_wetness;
+ np_density = &nparams_dungeon_density;
+ /*
+ cid_water_source = ndef->getId("mapgen_water_source");
+ cid_cobble = ndef->getId("mapgen_cobble");
+ cid_mossycobble = ndef->getId("mapgen_mossycobble");
+ cid_torch = ndef->getId("default:torch");
+ */
+}
+
+
+void DungeonGen::generate(ManualMapVoxelManipulator *vm, u32 bseed,
+ v3s16 nmin, v3s16 nmax) {
+ //TimeTaker t("gen dungeons");
+ int approx_groundlevel = 10 + water_level;
+
+ if ((nmin.Y + nmax.Y) / 2 >= approx_groundlevel ||
+ NoisePerlin3D(np_rarity, nmin.X, nmin.Y, nmin.Z, mapseed) < 0.2)
+ return;
+
+ this->vmanip = vm;
+ this->blockseed = bseed;
+ random.seed(bseed + 2);
+
+ cid_water_source = ndef->getId("mapgen_water_source");
+ cid_cobble = ndef->getId("mapgen_cobble");
+ cid_mossycobble = ndef->getId("mapgen_mossycobble");
+ //cid_torch = ndef->getId("default:torch");
+ cid_cobblestair = ndef->getId("stairs:stair_cobble");
+
+ // Dungeon generator doesn't modify places which have this set
+ vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE | VMANIP_FLAG_DUNGEON_PRESERVE);
+
+ // Set all air and water to be untouchable to make dungeons open
+ // to caves and open air
+ for (s16 z = nmin.Z; z <= nmax.Z; z++) {
+ for (s16 y = nmin.Y; y <= nmax.Y; y++) {
+ u32 i = vmanip->m_area.index(nmin.X, y, z);
+ for (s16 x = nmin.X; x <= nmax.X; x++) {
+ content_t c = vmanip->m_data[i].getContent();
+ if (c == CONTENT_AIR || c == cid_water_source)
+ vmanip->m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
+ i++;
+ }
+ }
+ }
+
+ // Add it
+ makeDungeon(v3s16(1,1,1) * MAP_BLOCKSIZE);
+
+ // Convert some cobble to mossy cobble
+ for (s16 z = nmin.Z; z <= nmax.Z; z++) {
+ for (s16 y = nmin.Y; y <= nmax.Y; y++) {
+ u32 i = vmanip->m_area.index(nmin.X, y, z);
+ for (s16 x = nmin.X; x <= nmax.X; x++) {
+ if (vmanip->m_data[i].getContent() == cid_cobble) {
+ float wetness = NoisePerlin3D(np_wetness, x, y, z, mapseed);
+ float density = NoisePerlin3D(np_density, x, y, z, blockseed);
+ if (density < wetness / 3.0)
+ vmanip->m_data[i].setContent(cid_mossycobble);
+ }
+ i++;
+ }
+ }
+ }
+
+ //printf("== gen dungeons: %dms\n", t.stop());
+}
+
+
+void DungeonGen::makeDungeon(v3s16 start_padding)
+{
+ v3s16 areasize = vmanip->m_area.getExtent();
+ v3s16 roomsize;
+ v3s16 roomplace;
+
+ /*
+ Find place for first room
+ */
+ bool fits = false;
+ for (u32 i = 0; i < 100; i++)
+ {
+ bool is_large_room = ((random.next() & 3) == 1);
+ roomsize = is_large_room ?
+ v3s16(random.range(8, 16),random.range(8, 16),random.range(8, 16)) :
+ v3s16(random.range(4, 8),random.range(4, 6),random.range(4, 8));
+
+ // start_padding is used to disallow starting the generation of
+ // a dungeon in a neighboring generation chunk
+ roomplace = vmanip->m_area.MinEdge + start_padding + v3s16(
+ random.range(0,areasize.X-roomsize.X-1-start_padding.X),
+ random.range(0,areasize.Y-roomsize.Y-1-start_padding.Y),
+ random.range(0,areasize.Z-roomsize.Z-1-start_padding.Z));
+
+ /*
+ Check that we're not putting the room to an unknown place,
+ otherwise it might end up floating in the air
+ */
+ fits = true;
+ for (s16 z = 1; z < roomsize.Z - 1; z++)
+ for (s16 y = 1; y < roomsize.Y - 1; y++)
+ for (s16 x = 1; x < roomsize.X - 1; x++)
+ {
+ v3s16 p = roomplace + v3s16(x, y, z);
+ u32 vi = vmanip->m_area.index(p);
+ if (vmanip->m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
+ {
+ fits = false;
+ break;
+ }
+ if (vmanip->m_data[vi].getContent() == CONTENT_IGNORE)
+ {
+ fits = false;
+ break;
+ }
+ }
+ if (fits)
+ break;
+ }
+ // No place found
+ if (fits == false)
+ return;
+
+ /*
+ Stores the center position of the last room made, so that
+ a new corridor can be started from the last room instead of
+ the new room, if chosen so.
+ */
+ v3s16 last_room_center = roomplace + v3s16(roomsize.X / 2, 1, roomsize.Z / 2);
+
+ u32 room_count = random.range(2, 16);
+ for (u32 i = 0; i < room_count; i++)
+ {
+ // Make a room to the determined place
+ makeRoom(roomsize, roomplace);
+
+ v3s16 room_center = roomplace + v3s16(roomsize.X / 2, 1, roomsize.Z / 2);
+
+ // Place torch at room center (for testing)
+ //vmanip->m_data[vmanip->m_area.index(room_center)] = MapNode(cid_torch);
+
+ // Quit if last room
+ if (i == room_count - 1)
+ break;
+
+ // Determine walker start position
+
+ bool start_in_last_room = (random.range(0, 2) != 0);
+
+ v3s16 walker_start_place;
+
+ if(start_in_last_room)
+ {
+ walker_start_place = last_room_center;
+ }
+ else
+ {
+ walker_start_place = room_center;
+ // Store center of current room as the last one
+ last_room_center = room_center;
+ }
+
+ // Create walker and find a place for a door
+ v3s16 doorplace;
+ v3s16 doordir;
+
+ m_pos = walker_start_place;
+ bool r = findPlaceForDoor(doorplace, doordir);
+ if (r == false)
+ return;
+
+ if (random.range(0,1) == 0)
+ // Make the door
+ makeDoor(doorplace, doordir);
+ else
+ // Don't actually make a door
+ doorplace -= doordir;
+
+ // Make a random corridor starting from the door
+ v3s16 corridor_end;
+ v3s16 corridor_end_dir;
+ makeCorridor(doorplace, doordir, corridor_end, corridor_end_dir);
+
+ // Find a place for a random sized room
+ roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
+ m_pos = corridor_end;
+ m_dir = corridor_end_dir;
+ r = findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
+ if (r == false)
+ return;
+
+ if (random.range(0,1) == 0)
+ // Make the door
+ makeDoor(doorplace, doordir);
+ else
+ // Don't actually make a door
+ roomplace -= doordir;
+
+ }
+}
+
+
+void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
+{
+ MapNode n_cobble(cid_cobble);
+ MapNode n_air(CONTENT_AIR);
+
+ // Make +-X walls
+ for (s16 z = 0; z < roomsize.Z; z++)
+ for (s16 y = 0; y < roomsize.Y; y++)
+ {
+ {
+ v3s16 p = roomplace + v3s16(0, y, z);
+ if (vmanip->m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip->m_area.index(p);
+ if (vmanip->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
+ continue;
+ vmanip->m_data[vi] = n_cobble;
+ }
+ {
+ v3s16 p = roomplace + v3s16(roomsize.X - 1, y, z);
+ if (vmanip->m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip->m_area.index(p);
+ if (vmanip->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
+ continue;
+ vmanip->m_data[vi] = n_cobble;
+ }
+ }
+
+ // Make +-Z walls
+ for (s16 x = 0; x < roomsize.X; x++)
+ for (s16 y = 0; y < roomsize.Y; y++)
+ {
+ {
+ v3s16 p = roomplace + v3s16(x, y, 0);
+ if (vmanip->m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip->m_area.index(p);
+ if (vmanip->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
+ continue;
+ vmanip->m_data[vi] = n_cobble;
+ }
+ {
+ v3s16 p = roomplace + v3s16(x, y, roomsize.Z - 1);
+ if (vmanip->m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip->m_area.index(p);
+ if (vmanip->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
+ continue;
+ vmanip->m_data[vi] = n_cobble;
+ }
+ }
+
+ // Make +-Y walls (floor and ceiling)
+ for (s16 z = 0; z < roomsize.Z; z++)
+ for (s16 x = 0; x < roomsize.X; x++)
+ {
+ {
+ v3s16 p = roomplace + v3s16(x, 0, z);
+ if (vmanip->m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip->m_area.index(p);
+ if (vmanip->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
+ continue;
+ vmanip->m_data[vi] = n_cobble;
+ }
+ {
+ v3s16 p = roomplace + v3s16(x,roomsize. Y - 1, z);
+ if (vmanip->m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip->m_area.index(p);
+ if (vmanip->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
+ continue;
+ vmanip->m_data[vi] = n_cobble;
+ }
+ }
+
+ // Fill with air
+ for (s16 z = 1; z < roomsize.Z - 1; z++)
+ for (s16 y = 1; y < roomsize.Y - 1; y++)
+ for (s16 x = 1; x < roomsize.X - 1; x++)
+ {
+ v3s16 p = roomplace + v3s16(x, y, z);
+ if (vmanip->m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip->m_area.index(p);
+ vmanip->m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
+ vmanip->m_data[vi] = n_air;
+ }
+}
+
+
+void DungeonGen::makeFill(v3s16 place, v3s16 size,
+ u8 avoid_flags, MapNode n, u8 or_flags)
+{
+ for (s16 z = 0; z < size.Z; z++)
+ for (s16 y = 0; y < size.Y; y++)
+ for (s16 x = 0; x < size.X; x++)
+ {
+ v3s16 p = place + v3s16(x, y, z);
+ if (vmanip->m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip->m_area.index(p);
+ if (vmanip->m_flags[vi] & avoid_flags)
+ continue;
+ vmanip->m_flags[vi] |= or_flags;
+ vmanip->m_data[vi] = n;
+ }
+}
+
+
+void DungeonGen::makeHole(v3s16 place)
+{
+ makeFill(place, v3s16(1, 2, 1), 0, MapNode(CONTENT_AIR),
+ VMANIP_FLAG_DUNGEON_INSIDE);
+}
+
+
+void DungeonGen::makeDoor(v3s16 doorplace, v3s16 doordir)
+{
+ makeHole(doorplace);
+ // Place torch (for testing)
+ //vmanip->m_data[vmanip->m_area.index(doorplace)] = MapNode(cid_torch);
+}
+
+
+void DungeonGen::makeCorridor(v3s16 doorplace,
+ v3s16 doordir, v3s16 &result_place, v3s16 &result_dir)
+{
+ makeHole(doorplace);
+ v3s16 p0 = doorplace;
+ v3s16 dir = doordir;
+ u32 length;
+ /*if (random.next() % 2)
+ length = random.range(1, 13);
+ else
+ length = random.range(1, 6);*/
+ length = random.range(1, 13);
+ u32 partlength = random.range(1, 13);
+ u32 partcount = 0;
+ s16 make_stairs = 0;
+
+ if (random.next() % 2 == 0 && partlength >= 3)
+ make_stairs = random.next() % 2 ? 1 : -1;
+
+ for (u32 i = 0; i < length; i++) {
+ v3s16 p = p0 + dir;
+ if (partcount != 0)
+ p.Y += make_stairs;
+
+ if (vmanip->m_area.contains(p) == true &&
+ vmanip->m_area.contains(p + v3s16(0, 1, 0)) == true) {
+ if (make_stairs) {
+ makeFill(p + v3s16(-1, -1, -1), v3s16(3, 5, 3),
+ VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(cid_cobble), 0);
+ makeHole(p);
+ makeHole(p - dir);
+
+ // TODO: fix stairs code so it works 100% (quite difficult)
+
+ // exclude stairs from the bottom step
+ if (((make_stairs == 1) && i != 0) ||
+ ((make_stairs == -1) && i != length - 1)) {
+ // rotate face 180 deg if making stairs backwards
+ int facedir = dir_to_facedir(dir * make_stairs);
+
+ u32 vi = vmanip->m_area.index(p.X - dir.X, p.Y - 1, p.Z - dir.Z);
+ if (vmanip->m_data[vi].getContent() == cid_cobble)
+ vmanip->m_data[vi] = MapNode(cid_cobblestair, 0, facedir);
+
+ vi = vmanip->m_area.index(p.X, p.Y, p.Z);
+ if (vmanip->m_data[vi].getContent() == cid_cobble)
+ vmanip->m_data[vi] = MapNode(cid_cobblestair, 0, facedir);
+ }
+ } else {
+ makeFill(p + v3s16(-1, -1, -1), v3s16(3, 4, 3),
+ VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(cid_cobble), 0);
+ makeHole(p);
+ }
+
+ p0 = p;
+ } else {
+ // Can't go here, turn away
+ dir = turn_xz(dir, random.range(0, 1));
+ make_stairs = -make_stairs;
+ partcount = 0;
+ partlength = random.range(1, length);
+ continue;
+ }
+
+ partcount++;
+ if (partcount >= partlength) {
+ partcount = 0;
+
+ dir = random_turn(random, dir);
+
+ partlength = random.range(1,length);
+
+ make_stairs = 0;
+ if (random.next() % 2 == 0 && partlength >= 3)
+ make_stairs = random.next() % 2 ? 1 : -1;
+ }
+ }
+ result_place = p0;
+ result_dir = dir;
+}
+
+
+bool DungeonGen::findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
+{
+ for (u32 i = 0; i < 100; i++)
+ {
+ v3s16 p = m_pos + m_dir;
+ v3s16 p1 = p + v3s16(0, 1, 0);
+ if (vmanip->m_area.contains(p) == false
+ || vmanip->m_area.contains(p1) == false
+ || i % 4 == 0)
+ {
+ randomizeDir();
+ continue;
+ }
+ if (vmanip->getNodeNoExNoEmerge(p).getContent() == cid_cobble
+ && vmanip->getNodeNoExNoEmerge(p1).getContent() == cid_cobble)
+ {
+ // Found wall, this is a good place!
+ result_place = p;
+ result_dir = m_dir;
+ // Randomize next direction
+ randomizeDir();
+ return true;
+ }
+ /*
+ Determine where to move next
+ */
+ // Jump one up if the actual space is there
+ if (vmanip->getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent() == cid_cobble
+ && vmanip->getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent() == CONTENT_AIR
+ && vmanip->getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent() == CONTENT_AIR)
+ p += v3s16(0,1,0);
+ // Jump one down if the actual space is there
+ if (vmanip->getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent() == cid_cobble
+ && vmanip->getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent() == CONTENT_AIR
+ && vmanip->getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent() == CONTENT_AIR)
+ p += v3s16(0,-1,0);
+ // Check if walking is now possible
+ if (vmanip->getNodeNoExNoEmerge(p).getContent() != CONTENT_AIR
+ || vmanip->getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent() != CONTENT_AIR)
+ {
+ // Cannot continue walking here
+ randomizeDir();
+ continue;
+ }
+ // Move there
+ m_pos = p;
+ }
+ return false;
+}
+
+
+bool DungeonGen::findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
+ v3s16 &result_doordir, v3s16 &result_roomplace)
+{
+ for (s16 trycount = 0; trycount < 30; trycount++)
+ {
+ v3s16 doorplace;
+ v3s16 doordir;
+ bool r = findPlaceForDoor(doorplace, doordir);
+ if (r == false)
+ continue;
+ v3s16 roomplace;
+ // X east, Z north, Y up
+#if 1
+ if (doordir == v3s16(1, 0, 0)) // X+
+ roomplace = doorplace +
+ v3s16(0, -1, random.range(-roomsize.Z + 2, -2));
+ if (doordir == v3s16(-1, 0, 0)) // X-
+ roomplace = doorplace +
+ v3s16(-roomsize.X + 1, -1, random.range(-roomsize.Z + 2, -2));
+ if (doordir == v3s16(0, 0, 1)) // Z+
+ roomplace = doorplace +
+ v3s16(random.range(-roomsize.X + 2, -2), -1, 0);
+ if (doordir == v3s16(0, 0, -1)) // Z-
+ roomplace = doorplace +
+ v3s16(random.range(-roomsize.X + 2, -2), -1, -roomsize.Z + 1);
+#endif
+#if 0
+ if (doordir == v3s16(1, 0, 0)) // X+
+ roomplace = doorplace + v3s16(0, -1, -roomsize.Z / 2);
+ if (doordir == v3s16(-1, 0, 0)) // X-
+ roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z / 2);
+ if (doordir == v3s16(0, 0, 1)) // Z+
+ roomplace = doorplace + v3s16(-roomsize.X / 2, -1, 0);
+ if (doordir == v3s16(0, 0, -1)) // Z-
+ roomplace = doorplace + v3s16(-roomsize.X / 2, -1, -roomsize.Z + 1);
+#endif
+
+ // Check fit
+ bool fits = true;
+ for (s16 z = 1; z < roomsize.Z - 1; z++)
+ for (s16 y = 1; y < roomsize.Y - 1; y++)
+ for (s16 x = 1; x < roomsize.X - 1; x++)
+ {
+ v3s16 p = roomplace + v3s16(x, y, z);
+ if (vmanip->m_area.contains(p) == false)
+ {
+ fits = false;
+ break;
+ }
+ if (vmanip->m_flags[vmanip->m_area.index(p)]
+ & VMANIP_FLAG_DUNGEON_INSIDE)
+ {
+ fits = false;
+ break;
+ }
+ }
+ if(fits == false)
+ {
+ // Find new place
+ continue;
+ }
+ result_doorplace = doorplace;
+ result_doordir = doordir;
+ result_roomplace = roomplace;
+ return true;
+ }
+ return false;
+}
+
+
+v3s16 rand_ortho_dir(PseudoRandom &random)
+{
+ if (random.next() % 2 == 0)
+ return random.next() % 2 ? v3s16(-1, 0, 0) : v3s16(1, 0, 0);
+ else
+ return random.next() % 2 ? v3s16(0, 0, -1) : v3s16(0, 0, 1);
+}
+
+
+v3s16 turn_xz(v3s16 olddir, int t)
+{
+ v3s16 dir;
+ if (t == 0)
+ {
+ // Turn right
+ dir.X = olddir.Z;
+ dir.Z = -olddir.X;
+ dir.Y = olddir.Y;
+ }
+ else
+ {
+ // Turn left
+ dir.X = -olddir.Z;
+ dir.Z = olddir.X;
+ dir.Y = olddir.Y;
+ }
+ return dir;
+}
+
+
+v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
+{
+ int turn = random.range(0, 2);
+ v3s16 dir;
+ if (turn == 0)
+ {
+ // Go straight
+ dir = olddir;
+ }
+ else if (turn == 1)
+ // Turn right
+ dir = turn_xz(olddir, 0);
+ else
+ // Turn left
+ dir = turn_xz(olddir, 1);
+ return dir;
+}
+
+
+int dir_to_facedir(v3s16 d) {
+ if (abs(d.X) > abs(d.Z))
+ return d.X < 0 ? 3 : 1;
+ else
+ return d.Z < 0 ? 2 : 0;
+}
diff --git a/src/dungeongen.h b/src/dungeongen.h
new file mode 100644
index 000000000..4be3df4aa
--- /dev/null
+++ b/src/dungeongen.h
@@ -0,0 +1,128 @@
+/*
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef DUNGEONGEN_HEADER
+#define DUNGEONGEN_HEADER
+
+#include "voxel.h"
+#include "noise.h"
+
+#define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
+#define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
+#define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
+ VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
+
+class ManualMapVoxelManipulator;
+class INodeDefManager;
+
+v3s16 rand_ortho_dir(PseudoRandom &random);
+v3s16 turn_xz(v3s16 olddir, int t);
+v3s16 random_turn(PseudoRandom &random, v3s16 olddir);
+int dir_to_facedir(v3s16 d);
+
+class DungeonGen {
+public:
+ u32 blockseed;
+ u64 mapseed;
+ ManualMapVoxelManipulator *vmanip;
+ INodeDefManager *ndef;
+ PseudoRandom random;
+ v3s16 csize;
+ s16 water_level;
+
+ NoiseParams *np_rarity;
+ NoiseParams *np_wetness;
+ NoiseParams *np_density;
+
+ content_t cid_water_source;
+ content_t cid_cobble;
+ content_t cid_mossycobble;
+ content_t cid_torch;
+ content_t cid_cobblestair;
+
+ //RoomWalker
+ v3s16 m_pos;
+ v3s16 m_dir;
+
+ DungeonGen(INodeDefManager *ndef, u64 seed, s16 waterlevel);
+ void generate(ManualMapVoxelManipulator *vm, u32 bseed,
+ v3s16 full_node_min, v3s16 full_node_max);
+ //void generate(v3s16 full_node_min, v3s16 full_node_max, u32 bseed);
+
+ void makeDungeon(v3s16 start_padding);
+ void makeRoom(v3s16 roomsize, v3s16 roomplace);
+ void makeCorridor(v3s16 doorplace, v3s16 doordir,
+ v3s16 &result_place, v3s16 &result_dir);
+ void makeDoor(v3s16 doorplace, v3s16 doordir);
+ void makeFill(v3s16 place, v3s16 size, u8 avoid_flags, MapNode n, u8 or_flags);
+ void makeHole(v3s16 place);
+
+ bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir);
+ bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
+ v3s16 &result_doordir, v3s16 &result_roomplace);
+
+ void randomizeDir()
+ {
+ m_dir = rand_ortho_dir(random);
+ }
+};
+
+class RoomWalker
+{
+public:
+
+ RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
+ INodeDefManager *ndef):
+ vmanip(vmanip_),
+ m_pos(pos),
+ m_random(random),
+ m_ndef(ndef)
+ {
+ randomizeDir();
+ }
+
+ void randomizeDir()
+ {
+ m_dir = rand_ortho_dir(m_random);
+ }
+
+ void setPos(v3s16 pos)
+ {
+ m_pos = pos;
+ }
+
+ void setDir(v3s16 dir)
+ {
+ m_dir = dir;
+ }
+
+ //bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir);
+ //bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
+ // v3s16 &result_doordir, v3s16 &result_roomplace);
+
+private:
+ VoxelManipulator &vmanip;
+ v3s16 m_pos;
+ v3s16 m_dir;
+ PseudoRandom &m_random;
+ INodeDefManager *m_ndef;
+};
+
+
+#endif
diff --git a/src/emerge.cpp b/src/emerge.cpp
index 6c6863eff..e4bd997cb 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -39,6 +39,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "biome.h"
#include "emerge.h"
#include "mapgen_v6.h"
+#include "mapgen_indev.h"
+#include "mapgen_singlenode.h"
/////////////////////////////// Emerge Manager ////////////////////////////////
@@ -46,6 +48,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) {
//register built-in mapgens
registerMapgen("v6", new MapgenFactoryV6());
+ registerMapgen("indev", new MapgenFactoryIndev());
+ registerMapgen("singlenode", new MapgenFactorySinglenode());
this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
this->params = NULL;
@@ -359,7 +363,7 @@ void *EmergeThread::Thread() {
*/
BlockMakeData data;
MapBlock *block = NULL;
- core::map<v3s16, MapBlock *> modified_blocks;
+ std::map<v3s16, MapBlock *> modified_blocks;
if (getBlockOrStartGen(p, &block, &data, allow_generate)) {
{
@@ -415,13 +419,13 @@ void *EmergeThread::Thread() {
JMutexAutoLock lock(m_server->m_con_mutex);
// Add the originally fetched block to the modified list
if (block)
- modified_blocks.insert(p, block);
+ modified_blocks[p] = block;
// Set the modified blocks unsent for all the clients
- for (core::map<u16, RemoteClient*>::Iterator
- i = m_server->m_clients.getIterator();
- i.atEnd() == false; i++) {
- RemoteClient *client = i.getNode()->getValue();
+ for (std::map<u16, RemoteClient*>::iterator
+ i = m_server->m_clients.begin();
+ i != m_server->m_clients.end(); ++i) {
+ RemoteClient *client = i->second;
if (modified_blocks.size() > 0) {
// Remove block from sent history
client->SetBlocksNotSent(modified_blocks);
diff --git a/src/emerge.h b/src/emerge.h
index 70b67e731..3d717bce3 100644
--- a/src/emerge.h
+++ b/src/emerge.h
@@ -63,8 +63,9 @@ public:
std::map<v3s16, BlockEmergeData *> blocks_enqueued;
std::map<u16, u16> peer_queue_count;
- //biome manager
+ //Mapgen-related structures
BiomeDefManager *biomedef;
+ std::vector<Ore *> ores;
EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef);
~EmergeManager();
diff --git a/src/environment.cpp b/src/environment.cpp
index e939672e7..07cdb24d1 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -58,8 +58,8 @@ Environment::Environment():
Environment::~Environment()
{
// Deallocate players
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
+ for(std::list<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i)
{
delete (*i);
}
@@ -86,8 +86,8 @@ void Environment::removePlayer(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
re_search:
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
+ for(std::list<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i)
{
Player *player = *i;
if(player->peer_id != peer_id)
@@ -103,8 +103,8 @@ re_search:
Player * Environment::getPlayer(u16 peer_id)
{
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
+ for(std::list<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i)
{
Player *player = *i;
if(player->peer_id == peer_id)
@@ -115,8 +115,8 @@ Player * Environment::getPlayer(u16 peer_id)
Player * Environment::getPlayer(const char *name)
{
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
+ for(std::list<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i)
{
Player *player = *i;
if(strcmp(player->getName(), name) == 0)
@@ -127,12 +127,12 @@ Player * Environment::getPlayer(const char *name)
Player * Environment::getRandomConnectedPlayer()
{
- core::list<Player*> connected_players = getPlayers(true);
+ std::list<Player*> connected_players = getPlayers(true);
u32 chosen_one = myrand() % connected_players.size();
u32 j = 0;
- for(core::list<Player*>::Iterator
+ for(std::list<Player*>::iterator
i = connected_players.begin();
- i != connected_players.end(); i++)
+ i != connected_players.end(); ++i)
{
if(j == chosen_one)
{
@@ -146,12 +146,12 @@ Player * Environment::getRandomConnectedPlayer()
Player * Environment::getNearestConnectedPlayer(v3f pos)
{
- core::list<Player*> connected_players = getPlayers(true);
+ std::list<Player*> connected_players = getPlayers(true);
f32 nearest_d = 0;
Player *nearest_player = NULL;
- for(core::list<Player*>::Iterator
+ for(std::list<Player*>::iterator
i = connected_players.begin();
- i != connected_players.end(); i++)
+ i != connected_players.end(); ++i)
{
Player *player = *i;
f32 d = player->getPosition().getDistanceFrom(pos);
@@ -164,17 +164,17 @@ Player * Environment::getNearestConnectedPlayer(v3f pos)
return nearest_player;
}
-core::list<Player*> Environment::getPlayers()
+std::list<Player*> Environment::getPlayers()
{
return m_players;
}
-core::list<Player*> Environment::getPlayers(bool ignore_disconnected)
+std::list<Player*> Environment::getPlayers(bool ignore_disconnected)
{
- core::list<Player*> newlist;
- for(core::list<Player*>::Iterator
+ std::list<Player*> newlist;
+ for(std::list<Player*>::iterator
i = m_players.begin();
- i != m_players.end(); i++)
+ i != m_players.end(); ++i)
{
Player *player = *i;
@@ -193,7 +193,7 @@ core::list<Player*> Environment::getPlayers(bool ignore_disconnected)
void Environment::printPlayers(std::ostream &o)
{
o<<"Players in environment:"<<std::endl;
- for(core::list<Player*>::Iterator i = m_players.begin();
+ for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); i++)
{
Player *player = *i;
@@ -251,7 +251,7 @@ ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
ActiveBlockList
*/
-void fillRadiusBlock(v3s16 p0, s16 r, core::map<v3s16, bool> &list)
+void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
{
v3s16 p;
for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
@@ -259,21 +259,21 @@ void fillRadiusBlock(v3s16 p0, s16 r, core::map<v3s16, bool> &list)
for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
{
// Set in list
- list[p] = true;
+ list.insert(p);
}
}
-void ActiveBlockList::update(core::list<v3s16> &active_positions,
+void ActiveBlockList::update(std::list<v3s16> &active_positions,
s16 radius,
- core::map<v3s16, bool> &blocks_removed,
- core::map<v3s16, bool> &blocks_added)
+ std::set<v3s16> &blocks_removed,
+ std::set<v3s16> &blocks_added)
{
/*
Create the new list
*/
- core::map<v3s16, bool> newlist;
- for(core::list<v3s16>::Iterator i = active_positions.begin();
- i != active_positions.end(); i++)
+ std::set<v3s16> newlist;
+ for(std::list<v3s16>::iterator i = active_positions.begin();
+ i != active_positions.end(); ++i)
{
fillRadiusBlock(*i, radius, newlist);
}
@@ -282,37 +282,37 @@ void ActiveBlockList::update(core::list<v3s16> &active_positions,
Find out which blocks on the old list are not on the new list
*/
// Go through old list
- for(core::map<v3s16, bool>::Iterator i = m_list.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<v3s16>::iterator i = m_list.begin();
+ i != m_list.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
+ v3s16 p = *i;
// If not on new list, it's been removed
- if(newlist.find(p) == NULL)
- blocks_removed.insert(p, true);
+ if(newlist.find(p) == newlist.end())
+ blocks_removed.insert(p);
}
/*
Find out which blocks on the new list are not on the old list
*/
// Go through new list
- for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<v3s16>::iterator i = newlist.begin();
+ i != newlist.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
+ v3s16 p = *i;
// If not on old list, it's been added
- if(m_list.find(p) == NULL)
- blocks_added.insert(p, true);
+ if(m_list.find(p) == m_list.end())
+ blocks_added.insert(p);
}
/*
Update m_list
*/
m_list.clear();
- for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<v3s16>::iterator i = newlist.begin();
+ i != newlist.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
- m_list.insert(p, true);
+ v3s16 p = *i;
+ m_list.insert(p);
}
}
@@ -348,8 +348,8 @@ ServerEnvironment::~ServerEnvironment()
m_map->drop();
// Delete ActiveBlockModifiers
- for(core::list<ABMWithState>::Iterator
- i = m_abms.begin(); i != m_abms.end(); i++){
+ for(std::list<ABMWithState>::iterator
+ i = m_abms.begin(); i != m_abms.end(); ++i){
delete i->abm;
}
}
@@ -370,7 +370,7 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
std::string players_path = savedir + "/players";
fs::CreateDir(players_path);
- core::map<Player*, bool> saved_players;
+ std::set<Player*> saved_players;
std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
for(u32 i=0; i<player_files.size(); i++)
@@ -419,15 +419,15 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
continue;
}
player->serialize(os);
- saved_players.insert(player, true);
+ saved_players.insert(player);
}
}
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
+ for(std::list<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i)
{
Player *player = *i;
- if(saved_players.find(player) != NULL)
+ if(saved_players.find(player) != saved_players.end())
{
/*infostream<<"Player "<<player->getName()
<<" was already saved."<<std::endl;*/
@@ -473,7 +473,7 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
continue;
}
player->serialize(os);
- saved_players.insert(player, true);
+ saved_players.insert(player);
}
}
@@ -484,8 +484,6 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
{
std::string players_path = savedir + "/players";
- core::map<Player*, bool> saved_players;
-
std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
for(u32 i=0; i<player_files.size(); i++)
{
@@ -627,7 +625,7 @@ private:
ServerEnvironment *m_env;
std::map<content_t, std::list<ActiveABM> > m_aabms;
public:
- ABMHandler(core::list<ABMWithState> &abms,
+ ABMHandler(std::list<ABMWithState> &abms,
float dtime_s, ServerEnvironment *env,
bool use_timers):
m_env(env)
@@ -635,8 +633,8 @@ public:
if(dtime_s < 0.001)
return;
INodeDefManager *ndef = env->getGameDef()->ndef();
- for(core::list<ABMWithState>::Iterator
- i = abms.begin(); i != abms.end(); i++){
+ for(std::list<ABMWithState>::iterator
+ i = abms.begin(); i != abms.end(); ++i){
ActiveBlockModifier *abm = i->abm;
float trigger_interval = abm->getTriggerInterval();
if(trigger_interval < 0.001)
@@ -862,12 +860,12 @@ bool ServerEnvironment::removeNode(v3s16 p)
std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
{
std::set<u16> objects;
- for(core::map<u16, ServerActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, ServerActiveObject*>::iterator
+ i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i)
{
- ServerActiveObject* obj = i.getNode()->getValue();
- u16 id = i.getNode()->getKey();
+ ServerActiveObject* obj = i->second;
+ u16 id = i->first;
v3f objectpos = obj->getBasePosition();
if(objectpos.getDistanceFrom(pos) > radius)
continue;
@@ -880,16 +878,16 @@ void ServerEnvironment::clearAllObjects()
{
infostream<<"ServerEnvironment::clearAllObjects(): "
<<"Removing all active objects"<<std::endl;
- core::list<u16> objects_to_remove;
- for(core::map<u16, ServerActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
+ std::list<u16> objects_to_remove;
+ for(std::map<u16, ServerActiveObject*>::iterator
+ i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i)
{
- ServerActiveObject* obj = i.getNode()->getValue();
+ ServerActiveObject* obj = i->second;
if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
continue;
- u16 id = i.getNode()->getKey();
- v3f objectpos = obj->getBasePosition();
+ u16 id = i->first;
+ v3f objectpos = obj->getBasePosition();
// Delete static object if block is loaded
if(obj->m_static_exists){
MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
@@ -919,13 +917,13 @@ void ServerEnvironment::clearAllObjects()
objects_to_remove.push_back(id);
}
// Remove references from m_active_objects
- for(core::list<u16>::Iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); i++)
+ for(std::list<u16>::iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); ++i)
{
- m_active_objects.remove(*i);
+ m_active_objects.erase(*i);
}
- core::list<v3s16> loadable_blocks;
+ std::list<v3s16> loadable_blocks;
infostream<<"ServerEnvironment::clearAllObjects(): "
<<"Listing all loadable blocks"<<std::endl;
m_map->listAllLoadableBlocks(loadable_blocks);
@@ -937,8 +935,8 @@ void ServerEnvironment::clearAllObjects()
u32 num_blocks_checked = 0;
u32 num_blocks_cleared = 0;
u32 num_objs_cleared = 0;
- for(core::list<v3s16>::Iterator i = loadable_blocks.begin();
- i != loadable_blocks.end(); i++)
+ for(std::list<v3s16>::iterator i = loadable_blocks.begin();
+ i != loadable_blocks.end(); ++i)
{
v3s16 p = *i;
MapBlock *block = m_map->emergeBlock(p, false);
@@ -1002,8 +1000,8 @@ void ServerEnvironment::step(float dtime)
*/
{
ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
+ for(std::list<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i)
{
Player *player = *i;
@@ -1027,10 +1025,10 @@ void ServerEnvironment::step(float dtime)
/*
Get player block positions
*/
- core::list<v3s16> players_blockpos;
- for(core::list<Player*>::Iterator
+ std::list<v3s16> players_blockpos;
+ for(std::list<Player*>::iterator
i = m_players.begin();
- i != m_players.end(); i++)
+ i != m_players.end(); ++i)
{
Player *player = *i;
// Ignore disconnected players
@@ -1045,8 +1043,8 @@ void ServerEnvironment::step(float dtime)
Update list of active blocks, collecting changes
*/
const s16 active_block_range = g_settings->getS16("active_block_range");
- core::map<v3s16, bool> blocks_removed;
- core::map<v3s16, bool> blocks_added;
+ std::set<v3s16> blocks_removed;
+ std::set<v3s16> blocks_added;
m_active_blocks.update(players_blockpos, active_block_range,
blocks_removed, blocks_added);
@@ -1057,11 +1055,11 @@ void ServerEnvironment::step(float dtime)
// Convert active objects that are no more in active blocks to static
deactivateFarObjects(false);
- for(core::map<v3s16, bool>::Iterator
- i = blocks_removed.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<v3s16>::iterator
+ i = blocks_removed.begin();
+ i != blocks_removed.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
+ v3s16 p = *i;
/*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
<<") became inactive"<<std::endl;*/
@@ -1078,11 +1076,11 @@ void ServerEnvironment::step(float dtime)
Handle added blocks
*/
- for(core::map<v3s16, bool>::Iterator
- i = blocks_added.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<v3s16>::iterator
+ i = blocks_added.begin();
+ i != blocks_added.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
+ v3s16 p = *i;
/*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
<<") became active"<<std::endl;*/
@@ -1091,7 +1089,7 @@ void ServerEnvironment::step(float dtime)
if(block==NULL){
// Block needs to be fetched first
m_emerger->queueBlockEmerge(p, false);
- m_active_blocks.m_list.remove(p);
+ m_active_blocks.m_list.erase(p);
continue;
}
@@ -1108,11 +1106,11 @@ void ServerEnvironment::step(float dtime)
float dtime = 1.0;
- for(core::map<v3s16, bool>::Iterator
- i = m_active_blocks.m_list.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<v3s16>::iterator
+ i = m_active_blocks.m_list.begin();
+ i != m_active_blocks.m_list.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
+ v3s16 p = *i;
/*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
<<") being handled"<<std::endl;*/
@@ -1163,11 +1161,11 @@ void ServerEnvironment::step(float dtime)
// Initialize handling of ActiveBlockModifiers
ABMHandler abmhandler(m_abms, abm_interval, this, true);
- for(core::map<v3s16, bool>::Iterator
- i = m_active_blocks.m_list.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<v3s16>::iterator
+ i = m_active_blocks.m_list.begin();
+ i != m_active_blocks.m_list.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
+ v3s16 p = *i;
/*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
<<") being handled"<<std::endl;*/
@@ -1216,11 +1214,11 @@ void ServerEnvironment::step(float dtime)
send_recommended = true;
}
- for(core::map<u16, ServerActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, ServerActiveObject*>::iterator
+ i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i)
{
- ServerActiveObject* obj = i.getNode()->getValue();
+ ServerActiveObject* obj = i->second;
// Remove non-peaceful mobs on peaceful mode
if(g_settings->getBool("only_peaceful_mobs")){
if(!obj->isPeaceful())
@@ -1232,7 +1230,7 @@ void ServerEnvironment::step(float dtime)
// Step object
obj->step(dtime, send_recommended);
// Read messages from object
- while(obj->m_messages_out.size() > 0)
+ while(!obj->m_messages_out.empty())
{
m_active_object_messages.push_back(
obj->m_messages_out.pop_front());
@@ -1255,31 +1253,24 @@ void ServerEnvironment::step(float dtime)
ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
{
- core::map<u16, ServerActiveObject*>::Node *n;
+ std::map<u16, ServerActiveObject*>::iterator n;
n = m_active_objects.find(id);
- if(n == NULL)
+ if(n == m_active_objects.end())
return NULL;
- return n->getValue();
+ return n->second;
}
bool isFreeServerActiveObjectId(u16 id,
- core::map<u16, ServerActiveObject*> &objects)
+ std::map<u16, ServerActiveObject*> &objects)
{
if(id == 0)
return false;
-
- for(core::map<u16, ServerActiveObject*>::Iterator
- i = objects.getIterator();
- i.atEnd()==false; i++)
- {
- if(i.getNode()->getKey() == id)
- return false;
- }
- return true;
+
+ return objects.find(id) == objects.end();
}
u16 getFreeServerActiveObjectId(
- core::map<u16, ServerActiveObject*> &objects)
+ std::map<u16, ServerActiveObject*> &objects)
{
u16 new_id = 1;
for(;;)
@@ -1351,8 +1342,8 @@ bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
inside a radius around a position
*/
void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
- core::map<u16, bool> &current_objects,
- core::map<u16, bool> &added_objects)
+ std::set<u16> &current_objects,
+ std::set<u16> &added_objects)
{
v3f pos_f = intToFloat(pos, BS);
f32 radius_f = radius * BS;
@@ -1363,13 +1354,13 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
- discard objects that are found in current_objects.
- add remaining objects to added_objects
*/
- for(core::map<u16, ServerActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, ServerActiveObject*>::iterator
+ i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i)
{
- u16 id = i.getNode()->getKey();
+ u16 id = i->first;
// Get object
- ServerActiveObject *object = i.getNode()->getValue();
+ ServerActiveObject *object = i->second;
if(object == NULL)
continue;
// Discard if removed
@@ -1382,12 +1373,12 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
continue;
}
// Discard if already on current_objects
- core::map<u16, bool>::Node *n;
+ std::set<u16>::iterator n;
n = current_objects.find(id);
- if(n != NULL)
+ if(n != current_objects.end())
continue;
// Add to added_objects
- added_objects.insert(id, false);
+ added_objects.insert(id);
}
}
@@ -1396,8 +1387,8 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
inside a radius around a position
*/
void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
- core::map<u16, bool> &current_objects,
- core::map<u16, bool> &removed_objects)
+ std::set<u16> &current_objects,
+ std::set<u16> &removed_objects)
{
v3f pos_f = intToFloat(pos, BS);
f32 radius_f = radius * BS;
@@ -1409,23 +1400,23 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
- object has m_removed=true, or
- object is too far away
*/
- for(core::map<u16, bool>::Iterator
- i = current_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<u16>::iterator
+ i = current_objects.begin();
+ i != current_objects.end(); ++i)
{
- u16 id = i.getNode()->getKey();
+ u16 id = *i;
ServerActiveObject *object = getActiveObject(id);
if(object == NULL){
infostream<<"ServerEnvironment::getRemovedActiveObjects():"
<<" object in current_objects is NULL"<<std::endl;
- removed_objects.insert(id, false);
+ removed_objects.insert(id);
continue;
}
if(object->m_removed)
{
- removed_objects.insert(id, false);
+ removed_objects.insert(id);
continue;
}
@@ -1437,7 +1428,7 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
if(distance_f >= radius_f)
{
- removed_objects.insert(id, false);
+ removed_objects.insert(id);
continue;
}
@@ -1447,7 +1438,7 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
{
- if(m_active_object_messages.size() == 0)
+ if(m_active_object_messages.empty())
return ActiveObjectMessage(0);
return m_active_object_messages.pop_front();
@@ -1488,7 +1479,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
/*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
<<"added (id="<<object->getId()<<")"<<std::endl;*/
- m_active_objects.insert(object->getId(), object);
+ m_active_objects[object->getId()] = object;
verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
<<"Added id="<<object->getId()<<"; there are now "
@@ -1512,7 +1503,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
if(block)
{
- block->m_static_objects.m_active.insert(object->getId(), s_obj);
+ block->m_static_objects.m_active[object->getId()] = s_obj;
object->m_static_exists = true;
object->m_static_block = blockpos;
@@ -1536,13 +1527,13 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
*/
void ServerEnvironment::removeRemovedObjects()
{
- core::list<u16> objects_to_remove;
- for(core::map<u16, ServerActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
+ std::list<u16> objects_to_remove;
+ for(std::map<u16, ServerActiveObject*>::iterator
+ i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i)
{
- u16 id = i.getNode()->getKey();
- ServerActiveObject* obj = i.getNode()->getValue();
+ u16 id = i->first;
+ ServerActiveObject* obj = i->second;
// This shouldn't happen but check it
if(obj == NULL)
{
@@ -1593,10 +1584,10 @@ void ServerEnvironment::removeRemovedObjects()
objects_to_remove.push_back(id);
}
// Remove references from m_active_objects
- for(core::list<u16>::Iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); i++)
+ for(std::list<u16>::iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); ++i)
{
- m_active_objects.remove(*i);
+ m_active_objects.erase(*i);
}
}
@@ -1663,11 +1654,11 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
}
// A list for objects that couldn't be converted to active for some
// reason. They will be stored back.
- core::list<StaticObject> new_stored;
+ std::list<StaticObject> new_stored;
// Loop through stored static objects
- for(core::list<StaticObject>::Iterator
+ for(std::list<StaticObject>::iterator
i = block->m_static_objects.m_stored.begin();
- i != block->m_static_objects.m_stored.end(); i++)
+ i != block->m_static_objects.m_stored.end(); ++i)
{
/*infostream<<"Server: Creating an active object from "
<<"static data"<<std::endl;*/
@@ -1696,9 +1687,9 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
// Clear stored list
block->m_static_objects.m_stored.clear();
// Add leftover failed stuff to stored list
- for(core::list<StaticObject>::Iterator
+ for(std::list<StaticObject>::iterator
i = new_stored.begin();
- i != new_stored.end(); i++)
+ i != new_stored.end(); ++i)
{
StaticObject &s_obj = *i;
block->m_static_objects.m_stored.push_back(s_obj);
@@ -1726,12 +1717,12 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
*/
void ServerEnvironment::deactivateFarObjects(bool force_delete)
{
- core::list<u16> objects_to_remove;
- for(core::map<u16, ServerActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
+ std::list<u16> objects_to_remove;
+ for(std::map<u16, ServerActiveObject*>::iterator
+ i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i)
{
- ServerActiveObject* obj = i.getNode()->getValue();
+ ServerActiveObject* obj = i->second;
assert(obj);
// Do not deactivate if static data creation not allowed
@@ -1742,7 +1733,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
if(!force_delete && obj->m_pending_deactivation)
continue;
- u16 id = i.getNode()->getKey();
+ u16 id = i->first;
v3f objectpos = obj->getBasePosition();
// The block in which the object resides in
@@ -1778,10 +1769,10 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
- core::map<u16, StaticObject>::Node *n =
+ std::map<u16, StaticObject>::iterator n =
block->m_static_objects.m_active.find(id);
- if(n){
- StaticObject static_old = n->getValue();
+ if(n != block->m_static_objects.m_active.end()){
+ StaticObject static_old = n->second;
float save_movem = obj->getMinimumSavedMovement();
@@ -1840,7 +1831,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
// This shouldn't happen, but happens rarely for some
// unknown reason. Unsuccessful attempts have been made to
// find said reason.
- if(new_id && block->m_static_objects.m_active.find(new_id)){
+ if(new_id && block->m_static_objects.m_active.find(new_id) != block->m_static_objects.m_active.end()){
infostream<<"ServerEnv: WARNING: Performing hack #83274"
<<std::endl;
block->m_static_objects.remove(new_id);
@@ -1900,10 +1891,10 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
}
// Remove references from m_active_objects
- for(core::list<u16>::Iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); i++)
+ for(std::list<u16>::iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); ++i)
{
- m_active_objects.remove(*i);
+ m_active_objects.erase(*i);
}
}
@@ -1930,15 +1921,15 @@ ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
ClientEnvironment::~ClientEnvironment()
{
// delete active objects
- for(core::map<u16, ClientActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, ClientActiveObject*>::iterator
+ i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i)
{
- delete i.getNode()->getValue();
+ delete i->second;
}
- for(core::list<ClientSimpleObject*>::Iterator
- i = m_simple_objects.begin(); i != m_simple_objects.end(); i++)
+ for(std::list<ClientSimpleObject*>::iterator
+ i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i)
{
delete *i;
}
@@ -1971,8 +1962,8 @@ void ClientEnvironment::addPlayer(Player *player)
LocalPlayer * ClientEnvironment::getLocalPlayer()
{
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
+ for(std::list<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i)
{
Player *player = *i;
if(player->isLocal())
@@ -1996,7 +1987,7 @@ void ClientEnvironment::step(float dtime)
LocalPlayer *lplayer = getLocalPlayer();
assert(lplayer);
// collision info queue
- core::list<CollisionInfo> player_collisions;
+ std::list<CollisionInfo> player_collisions;
/*
Get the speed the player is going
@@ -2105,7 +2096,7 @@ void ClientEnvironment::step(float dtime)
Move the lplayer.
This also does collision detection.
*/
- lplayer->move(dtime_part, *m_map, position_max_increment,
+ lplayer->move(dtime_part, this, position_max_increment,
&player_collisions);
}
}
@@ -2113,9 +2104,9 @@ void ClientEnvironment::step(float dtime)
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
- for(core::list<CollisionInfo>::Iterator
+ for(std::list<CollisionInfo>::iterator
i = player_collisions.begin();
- i != player_collisions.end(); i++)
+ i != player_collisions.end(); ++i)
{
CollisionInfo &info = *i;
v3f speed_diff = info.new_speed - info.old_speed;;
@@ -2179,8 +2170,8 @@ void ClientEnvironment::step(float dtime)
/*
Stuff that can be done in an arbitarily large dtime
*/
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
+ for(std::list<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i)
{
Player *player = *i;
v3f playerpos = player->getPosition();
@@ -2214,11 +2205,11 @@ void ClientEnvironment::step(float dtime)
*/
bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
- for(core::map<u16, ClientActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, ClientActiveObject*>::iterator
+ i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i)
{
- ClientActiveObject* obj = i.getNode()->getValue();
+ ClientActiveObject* obj = i->second;
// Step object
obj->step(dtime, this);
@@ -2242,12 +2233,12 @@ void ClientEnvironment::step(float dtime)
/*
Step and handle simple objects
*/
- for(core::list<ClientSimpleObject*>::Iterator
+ for(std::list<ClientSimpleObject*>::iterator
i = m_simple_objects.begin(); i != m_simple_objects.end();)
{
ClientSimpleObject *simple = *i;
- core::list<ClientSimpleObject*>::Iterator cur = i;
- i++;
+ std::list<ClientSimpleObject*>::iterator cur = i;
+ ++i;
simple->step(dtime);
if(simple->m_to_be_removed){
delete simple;
@@ -2263,31 +2254,24 @@ void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
{
- core::map<u16, ClientActiveObject*>::Node *n;
+ std::map<u16, ClientActiveObject*>::iterator n;
n = m_active_objects.find(id);
- if(n == NULL)
+ if(n == m_active_objects.end())
return NULL;
- return n->getValue();
+ return n->second;
}
bool isFreeClientActiveObjectId(u16 id,
- core::map<u16, ClientActiveObject*> &objects)
+ std::map<u16, ClientActiveObject*> &objects)
{
if(id == 0)
return false;
-
- for(core::map<u16, ClientActiveObject*>::Iterator
- i = objects.getIterator();
- i.atEnd()==false; i++)
- {
- if(i.getNode()->getKey() == id)
- return false;
- }
- return true;
+
+ return objects.find(id) == objects.end();
}
u16 getFreeClientActiveObjectId(
- core::map<u16, ClientActiveObject*> &objects)
+ std::map<u16, ClientActiveObject*> &objects)
{
u16 new_id = 1;
for(;;)
@@ -2326,7 +2310,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
}
infostream<<"ClientEnvironment::addActiveObject(): "
<<"added (id="<<object->getId()<<")"<<std::endl;
- m_active_objects.insert(object->getId(), object);
+ m_active_objects[object->getId()] = object;
object->addToScene(m_smgr, m_texturesource, m_irr);
{ // Update lighting immediately
u8 light = 0;
@@ -2389,7 +2373,7 @@ void ClientEnvironment::removeActiveObject(u16 id)
}
obj->removeFromScene(true);
delete obj;
- m_active_objects.remove(id);
+ m_active_objects.erase(id);
}
void ClientEnvironment::processActiveObjectMessage(u16 id,
@@ -2445,13 +2429,13 @@ void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
*/
void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
- core::array<DistanceSortedActiveObject> &dest)
+ std::vector<DistanceSortedActiveObject> &dest)
{
- for(core::map<u16, ClientActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, ClientActiveObject*>::iterator
+ i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i)
{
- ClientActiveObject* obj = i.getNode()->getValue();
+ ClientActiveObject* obj = i->second;
f32 d = (obj->getPosition() - origin).getLength();
@@ -2466,7 +2450,7 @@ void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
ClientEnvEvent ClientEnvironment::getClientEvent()
{
- if(m_client_event_queue.size() == 0)
+ if(m_client_event_queue.empty())
{
ClientEnvEvent event;
event.type = CEE_NONE;
diff --git a/src/environment.h b/src/environment.h
index 07a4d7635..02301e5d3 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include <set>
+#include <list>
#include "irrlichttypes_extrabloated.h"
#include "player.h"
#include <ostream>
@@ -73,8 +74,8 @@ public:
Player * getPlayer(const char *name);
Player * getRandomConnectedPlayer();
Player * getNearestConnectedPlayer(v3f pos);
- core::list<Player*> getPlayers();
- core::list<Player*> getPlayers(bool ignore_disconnected);
+ std::list<Player*> getPlayers();
+ std::list<Player*> getPlayers(bool ignore_disconnected);
void printPlayers(std::ostream &o);
u32 getDayNightRatio();
@@ -102,7 +103,7 @@ public:
protected:
// peer_ids in here should be unique, except that there may be many 0s
- core::list<Player*> m_players;
+ std::list<Player*> m_players;
// Time of day in milli-hours (0-23999); determines day and night
u32 m_time_of_day;
// Time of day in 0...1
@@ -156,20 +157,20 @@ struct ABMWithState
class ActiveBlockList
{
public:
- void update(core::list<v3s16> &active_positions,
+ void update(std::list<v3s16> &active_positions,
s16 radius,
- core::map<v3s16, bool> &blocks_removed,
- core::map<v3s16, bool> &blocks_added);
+ std::set<v3s16> &blocks_removed,
+ std::set<v3s16> &blocks_added);
bool contains(v3s16 p){
- return (m_list.find(p) != NULL);
+ return (m_list.find(p) != m_list.end());
}
void clear(){
m_list.clear();
}
- core::map<v3s16, bool> m_list;
+ std::set<v3s16> m_list;
private:
};
@@ -249,16 +250,16 @@ public:
inside a radius around a position
*/
void getAddedActiveObjects(v3s16 pos, s16 radius,
- core::map<u16, bool> &current_objects,
- core::map<u16, bool> &added_objects);
+ std::set<u16> &current_objects,
+ std::set<u16> &added_objects);
/*
Find out what new objects have been removed from
inside a radius around a position
*/
void getRemovedActiveObjects(v3s16 pos, s16 radius,
- core::map<u16, bool> &current_objects,
- core::map<u16, bool> &removed_objects);
+ std::set<u16> &current_objects,
+ std::set<u16> &removed_objects);
/*
Get the next message emitted by some active object.
@@ -350,7 +351,7 @@ private:
// Background block emerger (the server, in practice)
IBackgroundBlockEmerger *m_emerger;
// Active object list
- core::map<u16, ServerActiveObject*> m_active_objects;
+ std::map<u16, ServerActiveObject*> m_active_objects;
// Outgoing network message buffer for active objects
Queue<ActiveObjectMessage> m_active_object_messages;
// Some timers
@@ -368,7 +369,7 @@ private:
u32 m_game_time;
// A helper variable for incrementing the latter
float m_game_time_fraction_counter;
- core::list<ABMWithState> m_abms;
+ std::list<ABMWithState> m_abms;
// An interval for generally sending object positions and stuff
float m_recommended_send_interval;
};
@@ -463,7 +464,7 @@ public:
// Get all nearby objects
void getActiveObjects(v3f origin, f32 max_d,
- core::array<DistanceSortedActiveObject> &dest);
+ std::vector<DistanceSortedActiveObject> &dest);
// Get event from queue. CEE_NONE is returned if queue is empty.
ClientEnvEvent getClientEvent();
@@ -476,8 +477,8 @@ private:
ITextureSource *m_texturesource;
IGameDef *m_gamedef;
IrrlichtDevice *m_irr;
- core::map<u16, ClientActiveObject*> m_active_objects;
- core::list<ClientSimpleObject*> m_simple_objects;
+ std::map<u16, ClientActiveObject*> m_active_objects;
+ std::list<ClientSimpleObject*> m_simple_objects;
Queue<ClientEnvEvent> m_client_event_queue;
IntervalLimiter m_active_object_light_update_interval;
IntervalLimiter m_lava_hurt_interval;
diff --git a/src/farmesh.cpp b/src/farmesh.cpp
index 443e2b3bf..ecf01ee07 100644
--- a/src/farmesh.cpp
+++ b/src/farmesh.cpp
@@ -112,13 +112,13 @@ struct HeightPoint
float have_sand;
float tree_amount;
};
-core::map<v2s16, HeightPoint> g_heights;
+std::map<v2s16, HeightPoint> g_heights;
HeightPoint ground_height(u64 seed, v2s16 p2d)
{
- core::map<v2s16, HeightPoint>::Node *n = g_heights.find(p2d);
- if(n)
- return n->getValue();
+ std::map<v2s16, HeightPoint>::iterator n = g_heights.find(p2d);
+ if(n != g_heights.end())
+ return n->second;
HeightPoint hp;
s16 level = Mapgen::find_ground_level_from_noise(seed, p2d, 3);
hp.gh = (level-4)*BS;
diff --git a/src/game.cpp b/src/game.cpp
index 1ae29b13b..5e4e06148 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -2186,6 +2186,47 @@ void the_game(
{
update_wielded_item_trigger = true;
}
+ else if(event.type == CE_SPAWN_PARTICLE)
+ {
+ LocalPlayer* player = client.getEnv().getLocalPlayer();
+ AtlasPointer ap =
+ gamedef->tsrc()->getTexture(*(event.spawn_particle.texture));
+
+ new Particle(gamedef, smgr, player, client.getEnv(),
+ *event.spawn_particle.pos,
+ *event.spawn_particle.vel,
+ *event.spawn_particle.acc,
+ event.spawn_particle.expirationtime,
+ event.spawn_particle.size,
+ event.spawn_particle.collisiondetection, ap);
+ }
+ else if(event.type == CE_ADD_PARTICLESPAWNER)
+ {
+ LocalPlayer* player = client.getEnv().getLocalPlayer();
+ AtlasPointer ap =
+ gamedef->tsrc()->getTexture(*(event.add_particlespawner.texture));
+
+ new ParticleSpawner(gamedef, smgr, player,
+ event.add_particlespawner.amount,
+ event.add_particlespawner.spawntime,
+ *event.add_particlespawner.minpos,
+ *event.add_particlespawner.maxpos,
+ *event.add_particlespawner.minvel,
+ *event.add_particlespawner.maxvel,
+ *event.add_particlespawner.minacc,
+ *event.add_particlespawner.maxacc,
+ event.add_particlespawner.minexptime,
+ event.add_particlespawner.maxexptime,
+ event.add_particlespawner.minsize,
+ event.add_particlespawner.maxsize,
+ event.add_particlespawner.collisiondetection,
+ ap,
+ event.add_particlespawner.id);
+ }
+ else if(event.type == CE_DELETE_PARTICLESPAWNER)
+ {
+ delete_particlespawner (event.delete_particlespawner.id);
+ }
}
}
@@ -2353,11 +2394,6 @@ void the_game(
}
}
- // We can't actually know, but assume the sound of right-clicking
- // to be the sound of placing a node
- soundmaker.m_player_rightpunch_sound.gain = 0.5;
- soundmaker.m_player_rightpunch_sound.name = "default_place_node";
-
/*
Handle digging
*/
@@ -2415,7 +2451,8 @@ void the_game(
const ContentFeatures &features =
client.getNodeDefManager()->get(n);
addPunchingParticles
- (gamedef, smgr, player, nodepos, features.tiles);
+ (gamedef, smgr, player, client.getEnv(),
+ nodepos, features.tiles);
}
}
@@ -2453,7 +2490,8 @@ void the_game(
const ContentFeatures &features =
client.getNodeDefManager()->get(wasnode);
addDiggingParticles
- (gamedef, smgr, player, nodepos, features.tiles);
+ (gamedef, smgr, player, client.getEnv(),
+ nodepos, features.tiles);
}
dig_time = 0;
@@ -2574,6 +2612,9 @@ void the_game(
<<") - Position not loaded"<<std::endl;
}
}while(0);
+
+ // Read the sound
+ soundmaker.m_player_rightpunch_sound = def.sound_place;
}
}
}
@@ -2734,6 +2775,7 @@ void the_game(
*/
allparticles_step(dtime, client.getEnv());
+ allparticlespawners_step(dtime, client.getEnv());
/*
Fog
@@ -3220,6 +3262,7 @@ void the_game(
clouds->drop();
if(gui_chat_console)
gui_chat_console->drop();
+ clear_particles ();
/*
Draw a "shutting down" screen, which will be shown while the map
diff --git a/src/game.h b/src/game.h
index fef777fea..a2c1fc09c 100644
--- a/src/game.h
+++ b/src/game.h
@@ -23,17 +23,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include <string>
#include "keycode.h"
+#include <list>
-class KeyList : protected core::list<KeyPress>
+class KeyList : protected std::list<KeyPress>
{
- typedef core::list<KeyPress> super;
- typedef super::Iterator Iterator;
- typedef super::ConstIterator ConstIterator;
+ typedef std::list<KeyPress> super;
+ typedef super::iterator iterator;
+ typedef super::const_iterator const_iterator;
- virtual ConstIterator find(const KeyPress &key) const
+ virtual const_iterator find(const KeyPress &key) const
{
- ConstIterator f(begin());
- ConstIterator e(end());
+ const_iterator f(begin());
+ const_iterator e(end());
while (f!=e) {
if (*f == key)
return f;
@@ -42,10 +43,10 @@ class KeyList : protected core::list<KeyPress>
return e;
}
- virtual Iterator find(const KeyPress &key)
+ virtual iterator find(const KeyPress &key)
{
- Iterator f(begin());
- Iterator e(end());
+ iterator f(begin());
+ iterator e(end());
while (f!=e) {
if (*f == key)
return f;
@@ -65,14 +66,14 @@ public:
void unset(const KeyPress &key)
{
- Iterator p(find(key));
+ iterator p(find(key));
if (p != end())
erase(p);
}
void toggle(const KeyPress &key)
{
- Iterator p(this->find(key));
+ iterator p(this->find(key));
if (p != end())
erase(p);
else
diff --git a/src/gettime.h b/src/gettime.h
index 611906559..cde1471e5 100644
--- a/src/gettime.h
+++ b/src/gettime.h
@@ -31,7 +31,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Normal build: main.cpp
Server build: servermain.cpp
*/
+enum TimePrecision {
+ PRECISION_SECONDS,
+ PRECISION_MILLI,
+ PRECISION_MICRO,
+ PRECISION_NANO
+};
+
extern u32 getTimeMs();
+extern u32 getTime(TimePrecision prec);
/*
Timestamp stuff
diff --git a/src/guiChatConsole.cpp b/src/guiChatConsole.cpp
index f522af01f..5fc576cf8 100644
--- a/src/guiChatConsole.cpp
+++ b/src/guiChatConsole.cpp
@@ -535,7 +535,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
{
// Tab or Shift-Tab pressed
// Nick completion
- core::list<std::wstring> names = m_client->getConnectedPlayerNames();
+ std::list<std::wstring> names = m_client->getConnectedPlayerNames();
bool backwards = event.KeyInput.Shift;
m_chat_backend->getPrompt().nickCompletion(names, backwards);
return true;
diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp
index 120d6629a..1754422d0 100644
--- a/src/guiFormSpecMenu.cpp
+++ b/src/guiFormSpecMenu.cpp
@@ -207,18 +207,18 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
Strfnd f(m_formspec_string);
while(f.atend() == false)
{
- std::string type = trim(f.next("["));
+ std::string type = trim(f.next_esc("["));
if(type == "invsize" || type == "size")
{
v2f invsize;
- invsize.X = stof(f.next(","));
+ invsize.X = stof(f.next_esc(","));
if(type == "size")
{
- invsize.Y = stof(f.next("]"));
+ invsize.Y = stof(f.next_esc("]"));
}
else{
- invsize.Y = stof(f.next(";"));
- f.next("]");
+ invsize.Y = stof(f.next_esc(";"));
+ f.next_esc("]");
}
infostream<<"Form size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
@@ -242,24 +242,24 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
else if(type == "list")
{
- std::string name = f.next(";");
+ std::string name = f.next_esc(";");
InventoryLocation loc;
if(name == "context" || name == "current_name")
loc = m_current_inventory_location;
else
loc.deSerialize(name);
- std::string listname = f.next(";");
+ std::string listname = f.next_esc(";");
v2s32 pos = basepos;
- pos.X += stof(f.next(",")) * (float)spacing.X;
- pos.Y += stof(f.next(";")) * (float)spacing.Y;
+ pos.X += stof(f.next_esc(",")) * (float)spacing.X;
+ pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom;
- geom.X = stoi(f.next(","));
- geom.Y = stoi(f.next(";"));
+ geom.X = stoi(f.next_esc(","));
+ geom.Y = stoi(f.next_esc(";"));
infostream<<"list inv="<<name<<", listname="<<listname
<<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")"
<<std::endl;
- std::string start_i_s = f.next("]");
+ std::string start_i_s = f.next_esc("]");
s32 start_i = 0;
if(start_i_s != "")
start_i = stoi(start_i_s);
@@ -270,12 +270,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "image")
{
v2s32 pos = basepos;
- pos.X += stof(f.next(",")) * (float)spacing.X;
- pos.Y += stof(f.next(";")) * (float)spacing.Y;
+ pos.X += stof(f.next_esc(",")) * (float)spacing.X;
+ pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom;
- geom.X = stof(f.next(",")) * (float)imgsize.X;
- geom.Y = stof(f.next(";")) * (float)imgsize.Y;
- std::string name = f.next("]");
+ geom.X = stof(f.next_esc(",")) * (float)imgsize.X;
+ geom.Y = stof(f.next_esc(";")) * (float)imgsize.Y;
+ std::string name = f.next_esc("]");
infostream<<"image name="<<name
<<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")"
@@ -287,12 +287,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "item_image")
{
v2s32 pos = basepos;
- pos.X += stof(f.next(",")) * (float)spacing.X;
- pos.Y += stof(f.next(";")) * (float)spacing.Y;
+ pos.X += stof(f.next_esc(",")) * (float)spacing.X;
+ pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom;
- geom.X = stof(f.next(",")) * (float)imgsize.X;
- geom.Y = stof(f.next(";")) * (float)imgsize.Y;
- std::string name = f.next("]");
+ geom.X = stof(f.next_esc(",")) * (float)imgsize.X;
+ geom.Y = stof(f.next_esc(";")) * (float)imgsize.Y;
+ std::string name = f.next_esc("]");
infostream<<"item name="<<name
<<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")"
@@ -304,12 +304,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "background")
{
v2s32 pos = basepos;
- pos.X += stof(f.next(",")) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2;
- pos.Y += stof(f.next(";")) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2;
+ pos.X += stof(f.next_esc(",")) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2;
+ pos.Y += stof(f.next_esc(";")) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2;
v2s32 geom;
- geom.X = stof(f.next(",")) * (float)spacing.X;
- geom.Y = stof(f.next(";")) * (float)spacing.Y;
- std::string name = f.next("]");
+ geom.X = stof(f.next_esc(",")) * (float)spacing.X;
+ geom.Y = stof(f.next_esc(";")) * (float)spacing.Y;
+ std::string name = f.next_esc("]");
infostream<<"image name="<<name
<<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")"
@@ -320,8 +320,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
else if(type == "field" || type == "textarea")
{
- std::string fname = f.next(";");
- std::string flabel = f.next(";");
+ std::string fname = f.next_esc(";");
+ std::string flabel = f.next_esc(";");
if(fname.find(",") == std::string::npos && flabel.find(",") == std::string::npos)
{
@@ -372,14 +372,14 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
- fname = f.next(";");
- flabel = f.next(";");
+ fname = f.next_esc(";");
+ flabel = f.next_esc(";");
if(bp_set != 2)
errorstream<<"WARNING: invalid use of positioned "<<type<<" without a size[] element"<<std::endl;
}
- std::string odefault = f.next("]");
+ std::string odefault = f.next_esc("]");
std::string fdefault;
// fdefault may contain a variable reference, which
@@ -389,6 +389,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else
fdefault = odefault;
+ fdefault = unescape_string(fdefault);
+ flabel = unescape_string(flabel);
+
FieldSpec spec = FieldSpec(
narrow_to_wide(fname.c_str()),
narrow_to_wide(flabel.c_str()),
@@ -434,15 +437,17 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "label")
{
v2s32 pos = padding;
- pos.X += stof(f.next(",")) * (float)spacing.X;
- pos.Y += stof(f.next(";")) * (float)spacing.Y;
+ pos.X += stof(f.next_esc(",")) * (float)spacing.X;
+ pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+300, pos.Y+((imgsize.Y/2)+15));
- std::string flabel = f.next("]");
+ std::string flabel = f.next_esc("]");
if(bp_set != 2)
errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl;
+ flabel = unescape_string(flabel);
+
FieldSpec spec = FieldSpec(
narrow_to_wide(""),
narrow_to_wide(flabel.c_str()),
@@ -455,19 +460,21 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "button" || type == "button_exit")
{
v2s32 pos = padding;
- pos.X += stof(f.next(",")) * (float)spacing.X;
- pos.Y += stof(f.next(";")) * (float)spacing.Y;
+ pos.X += stof(f.next_esc(",")) * (float)spacing.X;
+ pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom;
- geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
- pos.Y += (stof(f.next(";")) * (float)imgsize.Y)/2;
+ geom.X = (stof(f.next_esc(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
+ pos.Y += (stof(f.next_esc(";")) * (float)imgsize.Y)/2;
rect = core::rect<s32>(pos.X, pos.Y-15, pos.X+geom.X, pos.Y+15);
- std::string fname = f.next(";");
- std::string flabel = f.next("]");
+ std::string fname = f.next_esc(";");
+ std::string flabel = f.next_esc("]");
if(bp_set != 2)
errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
+ flabel = unescape_string(flabel);
+
FieldSpec spec = FieldSpec(
narrow_to_wide(fname.c_str()),
narrow_to_wide(flabel.c_str()),
@@ -483,20 +490,22 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "image_button" || type == "image_button_exit")
{
v2s32 pos = padding;
- pos.X += stof(f.next(",")) * (float)spacing.X;
- pos.Y += stof(f.next(";")) * (float)spacing.Y;
+ pos.X += stof(f.next_esc(",")) * (float)spacing.X;
+ pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom;
- geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
- geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
+ geom.X = (stof(f.next_esc(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
+ geom.Y = (stof(f.next_esc(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
- std::string fimage = f.next(";");
- std::string fname = f.next(";");
- std::string flabel = f.next("]");
+ std::string fimage = f.next_esc(";");
+ std::string fname = f.next_esc(";");
+ std::string flabel = f.next_esc("]");
if(bp_set != 2)
errorstream<<"WARNING: invalid use of image_button without a size[] element"<<std::endl;
+ flabel = unescape_string(flabel);
+
FieldSpec spec = FieldSpec(
narrow_to_wide(fname.c_str()),
narrow_to_wide(flabel.c_str()),
@@ -519,15 +528,15 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "item_image_button")
{
v2s32 pos = padding;
- pos.X += stof(f.next(",")) * (float)spacing.X;
- pos.Y += stof(f.next(";")) * (float)spacing.Y;
+ pos.X += stof(f.next_esc(",")) * (float)spacing.X;
+ pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom;
- geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
- geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
+ geom.X = (stof(f.next_esc(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
+ geom.Y = (stof(f.next_esc(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
- std::string fimage = f.next(";");
- std::string fname = f.next(";");
- std::string flabel = f.next("]");
+ std::string fimage = f.next_esc(";");
+ std::string fname = f.next_esc(";");
+ std::string flabel = f.next_esc("]");
if(bp_set != 2)
errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl;
IItemDefManager *idef = m_gamedef->idef();
@@ -535,6 +544,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
item.deSerialize(fimage, idef);
video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
std::string tooltip = item.getDefinition(idef).description;
+ flabel = unescape_string(flabel);
FieldSpec spec = FieldSpec(
narrow_to_wide(fname.c_str()),
narrow_to_wide(flabel.c_str()),
@@ -556,7 +566,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else
{
// Ignore others
- std::string ts = f.next("]");
+ std::string ts = f.next_esc("]");
infostream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\""
<<std::endl;
}
diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h
index aee16736e..17b202b18 100644
--- a/src/guiFormSpecMenu.h
+++ b/src/guiFormSpecMenu.h
@@ -209,11 +209,11 @@ protected:
IFormSource *m_form_src;
TextDest *m_text_dst;
- core::array<ListDrawSpec> m_inventorylists;
- core::array<ImageDrawSpec> m_backgrounds;
- core::array<ImageDrawSpec> m_images;
- core::array<ImageDrawSpec> m_itemimages;
- core::array<FieldSpec> m_fields;
+ std::vector<ListDrawSpec> m_inventorylists;
+ std::vector<ImageDrawSpec> m_backgrounds;
+ std::vector<ImageDrawSpec> m_images;
+ std::vector<ImageDrawSpec> m_itemimages;
+ std::vector<FieldSpec> m_fields;
ItemSpec *m_selected_item;
u32 m_selected_amount;
diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp
index c2e68579e..4c2030039 100644
--- a/src/guiMainMenu.cpp
+++ b/src/guiMainMenu.cpp
@@ -42,6 +42,43 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
#include "subgame.h"
+#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
+#define LSTRING(x) LSTRING_(x)
+#define LSTRING_(x) L##x
+
+const wchar_t *contrib_core_strs[] = {
+ L"Perttu Ahola (celeron55) <celeron55@gmail.com>",
+ L"Ryan Kwolek (kwolekr) <kwolekr@minetest.net>",
+ L"PilzAdam <pilzadam@minetest.net>",
+ L"Ilya Zhuravlev (thexyz) <xyz@minetest.net>",
+ L"Lisa Milne (darkrose) <lisa@ltmnet.com>",
+ L"Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>",
+ L"proller <proler@gmail.com>"
+};
+
+const wchar_t *contrib_active_strs[] = {
+ L"sfan5 <sfan5@live.de>",
+ L"sapier <sapier@gmx.net>",
+ L"Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>",
+ L"Jurgen Doser (doserj) <jurgen.doser@gmail.com>",
+ L"Jeija <jeija@mesecons.net>",
+ L"MirceaKitsune <mirceakitsune@gmail.com>",
+ L"ShadowNinja",
+ L"dannydark <the_skeleton_of_a_child@yahoo.co.uk>",
+ L"0gb.us <0gb.us@0gb.us>"
+};
+
+const wchar_t *contrib_previous_strs[] = {
+ L"kahrl <kahrl@gmx.net>",
+ L"Giuseppe Bilotta (Oblomov) <giuseppe.bilotta@gmail.com>",
+ L"Jonathan Neuschafer <j.neuschaefer@gmx.net>",
+ L"Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>",
+ L"Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>",
+ L"matttpt <matttpt@gmail.com>",
+ L"JacobF <queatz@gmail.com>"
+};
+
+
struct CreateWorldDestMainMenu : public CreateWorldDest
{
CreateWorldDestMainMenu(GUIMainMenu *menu):
@@ -106,6 +143,7 @@ enum
GUI_ID_SHADERS_CB,
GUI_ID_PRELOAD_ITEM_VISUALS_CB,
GUI_ID_ENABLE_PARTICLES_CB,
+ GUI_ID_LIQUID_FINITE_CB,
GUI_ID_DAMAGE_CB,
GUI_ID_CREATIVE_CB,
GUI_ID_PUBLIC_CB,
@@ -119,6 +157,7 @@ enum
GUI_ID_SERVERLIST,
GUI_ID_SERVERLIST_TOGGLE,
GUI_ID_SERVERLIST_DELETE,
+ GUI_ID_SERVERLIST_TITLE,
};
enum
@@ -209,7 +248,6 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
changeCtype("");
// Version
- //if(m_data->selected_tab != TAB_CREDITS)
{
core::rect<s32> rect(0, 0, size.X, 40);
rect += v2s32(4, 0);
@@ -219,7 +257,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
}
//v2s32 center(size.X/2, size.Y/2);
- v2s32 c800(size.X/2-400, size.Y/2-300);
+ v2s32 c800(size.X/2-400, size.Y/2-270);
m_topleft_client = c800 + v2s32(90, 70+50+30);
m_size_client = v2s32(620, 270);
@@ -237,7 +275,6 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
m_topleft_server = m_topleft_client + v2s32(0, m_size_client.Y+20);
// Tabs
-#if 1
{
core::rect<s32> rect(0, 0, m_size_client.X, 30);
rect += m_topleft_client + v2s32(0, -30);
@@ -250,7 +287,6 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
e->addTab(wgettext("Credits"));
e->setActiveTab(m_data->selected_tab);
}
-#endif
if(m_data->selected_tab == TAB_SINGLEPLAYER)
{
@@ -259,7 +295,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 10, m_size_client.Y);
rect += m_topleft_client + v2s32(15, 0);
//const wchar_t *text = L"H\nY\nB\nR\nI\nD";
- const wchar_t *text = L"T\nA\nP\nE\n\nA\nN\nD\n\nG\nL\nU\nE";
+ const wchar_t *text = L"S\nI\nN\nG\nL\nE\n \nP\nL\nA\nY\nE\nR\n";
gui::IGUIStaticText *t =
Environment->addStaticText(text, rect, false, true, this, -1);
t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
@@ -392,13 +428,38 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
changeCtype("");
// Server List
{
- core::rect<s32> rect(0, 0, 390, 160);
- rect += m_topleft_client + v2s32(50, 10);
+ core::rect<s32> rect(0, 0, 390, 140);
+ rect += m_topleft_client + v2s32(50, 30);
gui::IGUIListBox *e = Environment->addListBox(rect, this,
GUI_ID_SERVERLIST);
e->setDrawBackground(true);
- if (m_data->serverlist_show_available == false)
+#if USE_CURL
+ if(m_data->selected_serverlist == SERVERLIST_FAVORITES) {
m_data->servers = ServerList::getLocal();
+ {
+ core::rect<s32> rect(0, 0, 390, 20);
+ rect += m_topleft_client + v2s32(50, 10);
+ Environment->addStaticText(wgettext("Favorites:"),
+ rect, false, true, this, GUI_ID_SERVERLIST_TITLE);
+ }
+ } else {
+ m_data->servers = ServerList::getOnline();
+ {
+ core::rect<s32> rect(0, 0, 390, 20);
+ rect += m_topleft_client + v2s32(50, 10);
+ Environment->addStaticText(wgettext("Public Server List:"),
+ rect, false, true, this, GUI_ID_SERVERLIST_TITLE);
+ }
+ }
+#else
+ m_data->servers = ServerList::getLocal();
+ {
+ core::rect<s32> rect(0, 0, 390, 20);
+ rect += m_topleft_client + v2s32(50, 10);
+ Environment->addStaticText(wgettext("Favorites:"),
+ rect, false, true, this, GUI_ID_SERVERLIST_TITLE);
+ }
+#endif
updateGuiServerList();
e->setSelected(0);
}
@@ -435,7 +496,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_TOGGLE,
wgettext("Show Public"));
e->setIsPushButton(true);
- if (m_data->serverlist_show_available)
+ if (m_data->selected_serverlist == SERVERLIST_PUBLIC)
{
e->setText(wgettext("Show Favorites"));
e->setPressed();
@@ -448,7 +509,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
rect += m_topleft_client + v2s32(50+260+10, 180);
gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_DELETE,
wgettext("Delete"));
- if (m_data->serverlist_show_available) // Hidden on Show-Online mode
+ if (m_data->selected_serverlist == SERVERLIST_PUBLIC) // Hidden when on public list
e->setVisible(false);
}
// Start game button
@@ -691,6 +752,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
GUI_ID_ENABLE_PARTICLES_CB, wgettext("Enable Particles"));
}
+ {
+ core::rect<s32> rect(0, 0, option_w+20+20, 30);
+ rect += m_topleft_client + v2s32(option_x+175*2, option_y+20*3);
+ Environment->addCheckBox(m_data->liquid_finite, rect, this,
+ GUI_ID_LIQUID_FINITE_CB, wgettext("Finite liquid"));
+ }
+
// Key change button
{
core::rect<s32> rect(0, 0, 120, 30);
@@ -706,7 +774,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
{
// CREDITS
{
- core::rect<s32> rect(0, 0, 10, m_size_client.Y);
+ core::rect<s32> rect(0, 0, 9, m_size_client.Y);
rect += m_topleft_client + v2s32(15, 0);
const wchar_t *text = L"C\nR\nE\nD\nI\nT\nS";
gui::IGUIStaticText *t =
@@ -714,15 +782,34 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
}
{
- core::rect<s32> rect(0, 0, 454, 250);
- rect += m_topleft_client + v2s32(110, 50+35);
- Environment->addStaticText(narrow_to_wide(
- "Minetest " VERSION_STRING "\n"
- "http://minetest.net/\n"
- "\n"
- "by Perttu Ahola <celeron55@gmail.com>\n"
- "and contributors: PilzAdam, Taoki, tango_, kahrl (kaaaaaahrl?), darkrose, matttpt, erlehmann, SpeedProg, JacobF, teddydestodes, marktraceur, Jonathan Neuschäfer, thexyz, VanessaE, sfan5... and tens of more random people."
- ).c_str(), rect, false, true, this, -1);
+ core::rect<s32> rect(0, 0, 130, 70);
+ rect += m_topleft_client + v2s32(35, 160);
+ Environment->addStaticText(
+ L"Minetest " LSTRING(VERSION_STRING) L"\nhttp://minetest.net/",
+ rect, false, true, this, -1);
+ }
+ {
+ video::SColor yellow(255, 255, 255, 0);
+ core::rect<s32> rect(0, 0, 450, 260);
+ rect += m_topleft_client + v2s32(168, 5);
+
+ irr::gui::IGUIListBox *list = Environment->addListBox(rect, this);
+
+ list->addItem(L"Core Developers");
+ list->setItemOverrideColor(list->getItemCount() - 1, yellow);
+ for (int i = 0; i != ARRAYLEN(contrib_core_strs); i++)
+ list->addItem(contrib_core_strs[i]);
+ list->addItem(L"");
+ list->addItem(L"Active Contributors");
+ list->setItemOverrideColor(list->getItemCount() - 1, yellow);
+ for (int i = 0; i != ARRAYLEN(contrib_active_strs); i++)
+ list->addItem(contrib_active_strs[i]);
+ list->addItem(L"");
+ list->addItem(L"Previous Contributors");
+ list->setItemOverrideColor(list->getItemCount() - 1, yellow);
+ for (int i = 0; i != ARRAYLEN(contrib_previous_strs); i++)
+ list->addItem(contrib_previous_strs[i]);
+ list->addItem(L"");
}
}
@@ -786,15 +873,15 @@ void GUIMainMenu::drawMenu()
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
}
video::ITexture *logotexture =
- driver->getTexture(getTexturePath("menulogo.png").c_str());
+ driver->getTexture(getTexturePath("logo.png").c_str());
if(logotexture)
{
v2s32 logosize(logotexture->getOriginalSize().Width,
logotexture->getOriginalSize().Height);
- logosize *= 2;
+
core::rect<s32> rect(0,0,logosize.X,logosize.Y);
rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
- rect += v2s32(130, 50);
+ rect += v2s32(50, 60);
driver->draw2DImage(logotexture, rect,
core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(logotexture->getSize())),
@@ -919,6 +1006,12 @@ void GUIMainMenu::readInput(MainMenuData *dst)
}
{
+ gui::IGUIElement *e = getElementFromId(GUI_ID_LIQUID_FINITE_CB);
+ if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
+ dst->liquid_finite = ((gui::IGUICheckBox*)e)->isChecked();
+ }
+
+ {
gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX);
if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX)
dst->selected_world = ((gui::IGUIListBox*)e)->getSelected();
@@ -1083,25 +1176,28 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
gui::IGUIElement *togglebutton = getElementFromId(GUI_ID_SERVERLIST_TOGGLE);
gui::IGUIElement *deletebutton = getElementFromId(GUI_ID_SERVERLIST_DELETE);
gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
- if (m_data->serverlist_show_available) // switch to favorite list
+ gui::IGUIElement *title = getElementFromId(GUI_ID_SERVERLIST_TITLE);
+ if (m_data->selected_serverlist == SERVERLIST_PUBLIC) // switch to favorite list
{
m_data->servers = ServerList::getLocal();
togglebutton->setText(wgettext("Show Public"));
+ title->setText(wgettext("Favorites:"));
deletebutton->setVisible(true);
updateGuiServerList();
serverlist->setSelected(0);
+ m_data->selected_serverlist = SERVERLIST_FAVORITES;
}
else // switch to online list
{
m_data->servers = ServerList::getOnline();
togglebutton->setText(wgettext("Show Favorites"));
+ title->setText(wgettext("Public Server List:"));
deletebutton->setVisible(false);
updateGuiServerList();
serverlist->setSelected(0);
+ m_data->selected_serverlist = SERVERLIST_PUBLIC;
}
serverListOnSelected();
-
- m_data->serverlist_show_available = !m_data->serverlist_show_available;
}
#endif
}
diff --git a/src/guiMainMenu.h b/src/guiMainMenu.h
index a21f3b32a..a594ccd41 100644
--- a/src/guiMainMenu.h
+++ b/src/guiMainMenu.h
@@ -29,6 +29,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class IGameCallback;
+enum {
+ SERVERLIST_FAVORITES,
+ SERVERLIST_PUBLIC,
+};
+
struct MainMenuData
{
// These are in the native format of the gui elements
@@ -52,6 +57,7 @@ struct MainMenuData
int enable_shaders;
bool preload_item_visuals;
bool enable_particles;
+ bool liquid_finite;
// Server options
bool creative_mode;
bool enable_damage;
@@ -63,7 +69,7 @@ struct MainMenuData
std::string create_world_gameid;
bool only_refresh;
- bool serverlist_show_available; // if false show local favorites only
+ int selected_serverlist;
std::vector<WorldSpec> worlds;
std::vector<SubgameSpec> games;
@@ -84,7 +90,7 @@ struct MainMenuData
// Actions
only_refresh(false),
- serverlist_show_available(false)
+ selected_serverlist(SERVERLIST_FAVORITES)
{}
};
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 7051b611f..d6815d329 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -903,6 +903,10 @@ void Inventory::deSerialize(std::istream &is)
m_lists.push_back(list);
}
+ else
+ {
+ throw SerializationError("invalid inventory specifier");
+ }
}
}
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index 5fd27fca3..72ce0e654 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -75,6 +75,7 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
}
groups = def.groups;
node_placement_prediction = def.node_placement_prediction;
+ sound_place = def.sound_place;
return *this;
}
@@ -107,13 +108,17 @@ void ItemDefinition::reset()
tool_capabilities = NULL;
}
groups.clear();
+ sound_place = SimpleSoundSpec();
node_placement_prediction = "";
}
-void ItemDefinition::serialize(std::ostream &os) const
+void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
{
- writeU8(os, 1); // version
+ if(protocol_version <= 17)
+ writeU8(os, 1); // version
+ else
+ writeU8(os, 2); // version
writeU8(os, type);
os<<serializeString(name);
os<<serializeString(description);
@@ -126,7 +131,7 @@ void ItemDefinition::serialize(std::ostream &os) const
std::string tool_capabilities_s = "";
if(tool_capabilities){
std::ostringstream tmp_os(std::ios::binary);
- tool_capabilities->serialize(tmp_os);
+ tool_capabilities->serialize(tmp_os, protocol_version);
tool_capabilities_s = tmp_os.str();
}
os<<serializeString(tool_capabilities_s);
@@ -137,6 +142,11 @@ void ItemDefinition::serialize(std::ostream &os) const
writeS16(os, i->second);
}
os<<serializeString(node_placement_prediction);
+ if(protocol_version > 17){
+ //serializeSimpleSoundSpec(sound_place, os);
+ os<<serializeString(sound_place.name);
+ writeF1000(os, sound_place.gain);
+ }
}
void ItemDefinition::deSerialize(std::istream &is)
@@ -146,7 +156,7 @@ void ItemDefinition::deSerialize(std::istream &is)
// Deserialize
int version = readU8(is);
- if(version != 1)
+ if(version != 1 && version != 2)
throw SerializationError("unsupported ItemDefinition version");
type = (enum ItemType)readU8(is);
name = deSerializeString(is);
@@ -171,10 +181,24 @@ void ItemDefinition::deSerialize(std::istream &is)
int value = readS16(is);
groups[name] = value;
}
+ if(version == 1){
+ // We cant be sure that node_placement_prediction is send in version 1
+ try{
+ node_placement_prediction = deSerializeString(is);
+ }catch(SerializationError &e) {};
+ // Set the old default sound
+ sound_place.name = "default_place_node";
+ sound_place.gain = 0.5;
+ } else if(version == 2) {
+ node_placement_prediction = deSerializeString(is);
+ //deserializeSimpleSoundSpec(sound_place, is);
+ sound_place.name = deSerializeString(is);
+ sound_place.gain = readF1000(is);
+ }
// If you add anything here, insert it primarily inside the try-catch
// block to not need to increase the version.
try{
- node_placement_prediction = deSerializeString(is);
+
}catch(SerializationError &e) {};
}
@@ -211,8 +235,8 @@ public:
virtual ~CItemDefManager()
{
#ifndef SERVER
- const core::list<ClientCached*> &values = m_clientcached.getValues();
- for(core::list<ClientCached*>::ConstIterator
+ const std::list<ClientCached*> &values = m_clientcached.getValues();
+ for(std::list<ClientCached*>::const_iterator
i = values.begin(); i != values.end(); ++i)
{
ClientCached *cc = *i;
@@ -547,7 +571,7 @@ public:
m_aliases[name] = convert_to;
}
}
- void serialize(std::ostream &os)
+ void serialize(std::ostream &os, u16 protocol_version)
{
writeU8(os, 0); // version
u16 count = m_item_definitions.size();
@@ -559,7 +583,7 @@ public:
ItemDefinition *def = i->second;
// Serialize ItemDefinition and write wrapped in a string
std::ostringstream tmp_os(std::ios::binary);
- def->serialize(tmp_os);
+ def->serialize(tmp_os, protocol_version);
os<<serializeString(tmp_os.str());
}
writeU16(os, m_aliases.size());
@@ -599,7 +623,7 @@ public:
void processQueue(IGameDef *gamedef)
{
#ifndef SERVER
- while(m_get_clientcached_queue.size() > 0)
+ while(!m_get_clientcached_queue.empty())
{
GetRequest<std::string, ClientCached*, u8, u8>
request = m_get_clientcached_queue.pop();
diff --git a/src/itemdef.h b/src/itemdef.h
index dd20ba353..08c9c8358 100644
--- a/src/itemdef.h
+++ b/src/itemdef.h
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream>
#include <set>
#include "itemgroup.h"
+#include "sound.h"
class IGameDef;
struct ToolCapabilities;
@@ -66,6 +67,7 @@ struct ItemDefinition
// May be NULL. If non-NULL, deleted by destructor
ToolCapabilities *tool_capabilities;
ItemGroupList groups;
+ SimpleSoundSpec sound_place;
// Client shall immediately place this node when player places the item.
// Server will update the precise end result a moment later.
@@ -80,7 +82,7 @@ struct ItemDefinition
ItemDefinition& operator=(const ItemDefinition &def);
~ItemDefinition();
void reset();
- void serialize(std::ostream &os) const;
+ void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is);
private:
void resetInitial();
@@ -109,7 +111,7 @@ public:
IGameDef *gamedef) const=0;
#endif
- virtual void serialize(std::ostream &os)=0;
+ virtual void serialize(std::ostream &os, u16 protocol_version)=0;
};
class IWritableItemDefManager : public IItemDefManager
@@ -146,7 +148,7 @@ public:
virtual void registerAlias(const std::string &name,
const std::string &convert_to)=0;
- virtual void serialize(std::ostream &os)=0;
+ virtual void serialize(std::ostream &os, u16 protocol_version)=0;
virtual void deSerialize(std::istream &is)=0;
// Do stuff asked by threads that can only be done in the main thread
diff --git a/src/json/CMakeLists.txt b/src/json/CMakeLists.txt
index 0957799aa..5887d523a 100644
--- a/src/json/CMakeLists.txt
+++ b/src/json/CMakeLists.txt
@@ -6,9 +6,9 @@ else( UNIX )
set(json_platform_LIBS "")
endif( UNIX )
-add_library(json ${json_SRCS})
+add_library(jsoncpp ${json_SRCS})
target_link_libraries(
- json
+ jsoncpp
${json_platform_LIBS}
)
diff --git a/src/keycode.cpp b/src/keycode.cpp
index 8aadab2f1..96631b4ea 100644
--- a/src/keycode.cpp
+++ b/src/keycode.cpp
@@ -345,17 +345,16 @@ const KeyPress NumberKey[] = {
*/
// A simple cache for quicker lookup
-core::map<std::string, KeyPress> g_key_setting_cache;
+std::map<std::string, KeyPress> g_key_setting_cache;
KeyPress getKeySetting(const char *settingname)
{
- core::map<std::string, KeyPress>::Node *n;
+ std::map<std::string, KeyPress>::iterator n;
n = g_key_setting_cache.find(settingname);
- if(n)
- return n->getValue();
- g_key_setting_cache.insert(settingname,
- g_settings->get(settingname).c_str());
- return g_key_setting_cache.find(settingname)->getValue();
+ if(n != g_key_setting_cache.end())
+ return n->second;
+ g_key_setting_cache[settingname] = g_settings->get(settingname).c_str();
+ return g_key_setting_cache.find(settingname)->second;
}
void clearKeyCache()
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 0554302e0..ee9b41c58 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h"
#include "nodedef.h"
#include "settings.h"
+#include "environment.h"
#include "map.h"
#include "util/numeric.h"
@@ -57,9 +58,10 @@ LocalPlayer::~LocalPlayer()
{
}
-void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
- core::list<CollisionInfo> *collision_info)
+void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
+ std::list<CollisionInfo> *collision_info)
{
+ Map *map = &env->getMap();
INodeDefManager *nodemgr = m_gamedef->ndef();
v3f position = getPosition();
@@ -97,15 +99,15 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
if(in_liquid)
{
v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
- in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
- liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity;
+ in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid();
+ liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity;
}
// If not in liquid, the threshold of going in is at lower y
else
{
v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
- in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
- liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity;
+ in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid();
+ liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity;
}
}
catch(InvalidPositionException &e)
@@ -118,7 +120,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
*/
try{
v3s16 pp = floatToInt(position + v3f(0,0,0), BS);
- in_liquid_stable = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
+ in_liquid_stable = nodemgr->get(map->getNode(pp).getContent()).isLiquid();
}
catch(InvalidPositionException &e)
{
@@ -132,8 +134,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
try {
v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
- is_climbing = ((nodemgr->get(map.getNode(pp).getContent()).climbable ||
- nodemgr->get(map.getNode(pp2).getContent()).climbable) && !free_move);
+ is_climbing = ((nodemgr->get(map->getNode(pp).getContent()).climbable ||
+ nodemgr->get(map->getNode(pp2).getContent()).climbable) && !free_move);
}
catch(InvalidPositionException &e)
{
@@ -197,7 +199,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
v3f accel_f = v3f(0,0,0);
- collisionMoveResult result = collisionMoveSimple(&map, m_gamedef,
+ collisionMoveResult result = collisionMoveSimple(env, m_gamedef,
pos_max_d, playerbox, player_stepheight, dtime,
position, m_speed, accel_f);
@@ -219,7 +221,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
*/
v3s16 current_node = floatToInt(position - v3f(0,BS/2,0), BS);
if(m_sneak_node_exists &&
- nodemgr->get(map.getNodeNoEx(m_old_node_below)).name == "air" &&
+ nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
m_old_node_below_type != "air")
{
// Old node appears to have been removed; that is,
@@ -227,7 +229,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
m_need_to_get_new_sneak_node = false;
m_sneak_node_exists = false;
}
- else if(nodemgr->get(map.getNodeNoEx(current_node)).name != "air")
+ else if(nodemgr->get(map->getNodeNoEx(current_node)).name != "air")
{
// We are on something, so make sure to recalculate the sneak
// node.
@@ -267,10 +269,10 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
try{
// The node to be sneaked on has to be walkable
- if(nodemgr->get(map.getNode(p)).walkable == false)
+ if(nodemgr->get(map->getNode(p)).walkable == false)
continue;
// And the node above it has to be nonwalkable
- if(nodemgr->get(map.getNode(p+v3s16(0,1,0))).walkable == true)
+ if(nodemgr->get(map->getNode(p+v3s16(0,1,0))).walkable == true)
continue;
}
catch(InvalidPositionException &e)
@@ -331,7 +333,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
{
camera_barely_in_ceiling = false;
v3s16 camera_np = floatToInt(getEyePosition(), BS);
- MapNode n = map.getNodeNoEx(camera_np);
+ MapNode n = map->getNodeNoEx(camera_np);
if(n.getContent() != CONTENT_IGNORE){
if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
camera_barely_in_ceiling = true;
@@ -343,21 +345,21 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
Update the node last under the player
*/
m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
- m_old_node_below_type = nodemgr->get(map.getNodeNoEx(m_old_node_below)).name;
+ m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
/*
Check properties of the node on which the player is standing
*/
- const ContentFeatures &f = nodemgr->get(map.getNodeNoEx(getStandingNodePos()));
+ const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
// Determine if jumping is possible
m_can_jump = touching_ground && !in_liquid;
if(itemgroup_get(f.groups, "disable_jump"))
m_can_jump = false;
}
-void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
+void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d)
{
- move(dtime, map, pos_max_d, NULL);
+ move(dtime, env, pos_max_d, NULL);
}
void LocalPlayer::applyControl(float dtime)
diff --git a/src/localplayer.h b/src/localplayer.h
index f372c787d..17434d379 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -21,6 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define LOCALPLAYER_HEADER
#include "player.h"
+#include <list>
+
+class ClientEnvironment;
class LocalPlayer : public Player
{
@@ -37,9 +40,9 @@ public:
v3f overridePosition;
- void move(f32 dtime, Map &map, f32 pos_max_d,
- core::list<CollisionInfo> *collision_info);
- void move(f32 dtime, Map &map, f32 pos_max_d);
+ void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
+ std::list<CollisionInfo> *collision_info);
+ void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d);
void applyControl(float dtime);
diff --git a/src/main.cpp b/src/main.cpp
index cfd643ac7..2e57a8c20 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "debug.h"
#include "test.h"
+#include "clouds.h"
#include "server.h"
#include "constants.h"
#include "porting.h"
@@ -132,7 +133,12 @@ MainGameCallback *g_gamecallback = NULL;
u32 getTimeMs()
{
/* Use imprecise system calls directly (from porting.h) */
- return porting::getTimeMs();
+ return porting::getTime(PRECISION_MILLI);
+}
+
+u32 getTime(TimePrecision prec)
+{
+ return porting::getTime(prec);
}
#else
@@ -141,7 +147,7 @@ u32 getTimeMs()
class TimeGetter
{
public:
- virtual u32 getTime() = 0;
+ virtual u32 getTime(TimePrecision prec) = 0;
};
// A precise irrlicht one
@@ -151,11 +157,15 @@ public:
IrrlichtTimeGetter(IrrlichtDevice *device):
m_device(device)
{}
- u32 getTime()
- {
- if(m_device == NULL)
- return 0;
- return m_device->getTimer()->getRealTime();
+ u32 getTime(TimePrecision prec)
+ {
+ if (prec == PRECISION_MILLI) {
+ if(m_device == NULL)
+ return 0;
+ return m_device->getTimer()->getRealTime();
+ } else {
+ return porting::getTime(prec);
+ }
}
private:
IrrlichtDevice *m_device;
@@ -164,9 +174,9 @@ private:
class SimpleTimeGetter: public TimeGetter
{
public:
- u32 getTime()
+ u32 getTime(TimePrecision prec)
{
- return porting::getTimeMs();
+ return porting::getTime(prec);
}
};
@@ -178,7 +188,13 @@ u32 getTimeMs()
{
if(g_timegetter == NULL)
return 0;
- return g_timegetter->getTime();
+ return g_timegetter->getTime(PRECISION_MILLI);
+}
+
+u32 getTime(TimePrecision prec) {
+ if (g_timegetter == NULL)
+ return 0;
+ return g_timegetter->getTime(prec);
}
#endif
@@ -596,50 +612,120 @@ private:
bool rightreleased;
};
-void drawMenuBackground(video::IVideoDriver* driver)
-{
+//Draw the tiled menu background
+void drawMenuBackground(video::IVideoDriver* driver) {
core::dimension2d<u32> screensize = driver->getScreenSize();
+
+ std::string path = getTexturePath("menubg.png");
+ if (path[0]) {
+ video::ITexture *bgtexture =
+ driver->getTexture(path.c_str());
+
+ if (bgtexture) {
+ s32 scaledsize = 128;
- video::ITexture *bgtexture =
- driver->getTexture(getTexturePath("menubg.png").c_str());
- if(bgtexture)
- {
- s32 scaledsize = 128;
-
- // The important difference between destsize and screensize is
- // that destsize is rounded to whole scaled pixels.
- // These formulas use component-wise multiplication and division of v2u32.
- v2u32 texturesize = bgtexture->getSize();
- v2u32 sourcesize = texturesize * screensize / scaledsize + v2u32(1,1);
- v2u32 destsize = scaledsize * sourcesize / texturesize;
+ // The important difference between destsize and screensize is
+ // that destsize is rounded to whole scaled pixels.
+ // These formulas use component-wise multiplication and division of v2u32.
+ v2u32 texturesize = bgtexture->getSize();
+ v2u32 sourcesize = texturesize * screensize / scaledsize + v2u32(1,1);
+ v2u32 destsize = scaledsize * sourcesize / texturesize;
- // Default texture wrapping mode in Irrlicht is ETC_REPEAT.
- driver->draw2DImage(bgtexture,
- core::rect<s32>(0, 0, destsize.X, destsize.Y),
- core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
- NULL, NULL, true);
+ // Default texture wrapping mode in Irrlicht is ETC_REPEAT.
+ driver->draw2DImage(bgtexture,
+ core::rect<s32>(0, 0, destsize.X, destsize.Y),
+ core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
+ NULL, NULL, true);
+ }
}
-
- video::ITexture *logotexture =
- driver->getTexture(getTexturePath("menulogo.png").c_str());
- if(logotexture)
- {
- v2s32 logosize(logotexture->getOriginalSize().Width,
- logotexture->getOriginalSize().Height);
- logosize *= 4;
-
- video::SColor bgcolor(255,50,50,50);
- core::rect<s32> bgrect(0, screensize.Height-logosize.Y-20,
- screensize.Width, screensize.Height);
- driver->draw2DRectangle(bgcolor, bgrect, NULL);
-
- core::rect<s32> rect(0,0,logosize.X,logosize.Y);
- rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y);
- rect -= v2s32(logosize.X/2, 0);
- driver->draw2DImage(logotexture, rect,
- core::rect<s32>(core::position2d<s32>(0,0),
- core::dimension2di(logotexture->getSize())),
- NULL, NULL, true);
+}
+
+//Draw the footer at the bottom of the window
+void drawMenuFooter(video::IVideoDriver* driver, bool clouds) {
+ core::dimension2d<u32> screensize = driver->getScreenSize();
+ std::string path = getTexturePath(clouds ?
+ "menufooter_clouds.png" : "menufooter.png");
+ if (path[0]) {
+ video::ITexture *footertexture =
+ driver->getTexture(path.c_str());
+
+ if (footertexture) {
+ f32 mult = (((f32)screensize.Width)) /
+ ((f32)footertexture->getOriginalSize().Width);
+
+ v2s32 footersize(((f32)footertexture->getOriginalSize().Width) * mult,
+ ((f32)footertexture->getOriginalSize().Height) * mult);
+
+ // Don't draw the footer if there isn't enough room
+ s32 free_space = (((s32)screensize.Height)-320)/2;
+ if (free_space > footersize.Y) {
+ core::rect<s32> rect(0,0,footersize.X,footersize.Y);
+ rect += v2s32(screensize.Width/2,screensize.Height-footersize.Y);
+ rect -= v2s32(footersize.X/2, 0);
+
+ driver->draw2DImage(footertexture, rect,
+ core::rect<s32>(core::position2d<s32>(0,0),
+ core::dimension2di(footertexture->getSize())),
+ NULL, NULL, true);
+ }
+ }
+ }
+}
+
+// Draw the Header over the main menu
+void drawMenuHeader(video::IVideoDriver* driver) {
+ core::dimension2d<u32> screensize = driver->getScreenSize();
+
+ std::string path = getTexturePath("menuheader.png");
+ if (path[0]) {
+ video::ITexture *splashtexture =
+ driver->getTexture(path.c_str());
+
+ if(splashtexture) {
+ //v2s32 splashsize((splashtexture->getOriginalSize().Width*100)/
+ // splashtexture->getOriginalSize().Height, 80);
+
+ f32 mult = (((f32)screensize.Width / 2)) /
+ ((f32)splashtexture->getOriginalSize().Width);
+
+ v2s32 splashsize(((f32)splashtexture->getOriginalSize().Width) * mult,
+ ((f32)splashtexture->getOriginalSize().Height) * mult);
+
+ // Don't draw the header is there isn't enough room
+ s32 free_space = (((s32)screensize.Height)-320)/2;
+ if (free_space > splashsize.Y) {
+ core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
+ splashrect += v2s32((screensize.Width/2)-(splashsize.X/2),
+ ((free_space/2)-splashsize.Y/2)+10);
+
+ video::SColor bgcolor(255,50,50,50);
+
+ driver->draw2DImage(splashtexture, splashrect,
+ core::rect<s32>(core::position2d<s32>(0,0),
+ core::dimension2di(splashtexture->getSize())),
+ NULL, NULL, true);
+ }
+ }
+ }
+}
+
+// Draw the Splash over the clouds and under the main menu
+void drawMenuSplash(video::IVideoDriver* driver) {
+ core::dimension2d<u32> screensize = driver->getScreenSize();
+ if (getTexturePath("menusplash.png") != "") {
+ video::ITexture *splashtexture =
+ driver->getTexture(getTexturePath("menusplash.png").c_str());
+
+ if(splashtexture) {
+ core::rect<s32> splashrect(0, 0, screensize.Width, screensize.Height);
+
+ video::SColor bgcolor(255,50,50,50);
+
+ driver->draw2DImage(splashtexture, splashrect,
+ core::rect<s32>(core::position2d<s32>(0,0),
+ core::dimension2di(splashtexture->getSize())),
+ NULL, NULL, true);
+ }
}
}
@@ -700,14 +786,14 @@ void SpeedTests()
}
{
- TimeTaker timer("Testing core::map speed");
+ TimeTaker timer("Testing std::map speed");
- core::map<v2s16, f32> map1;
+ std::map<v2s16, f32> map1;
tempf = -324;
const s16 ii=300;
for(s16 y=0; y<ii; y++){
for(s16 x=0; x<ii; x++){
- map1.insert(v2s16(x,y), tempf);
+ map1[v2s16(x,y)] = tempf;
tempf += 1;
}
}
@@ -734,7 +820,7 @@ void SpeedTests()
}
}
// Do at least 10ms
- while(timer.getTime() < 10);
+ while(timer.getTimerTime() < 10);
u32 dtime = timer.stop();
u32 per_ms = n / dtime;
@@ -788,48 +874,48 @@ int main(int argc, char *argv[])
*/
// List all allowed options
- core::map<std::string, ValueSpec> allowed_options;
- allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG,
- _("Show allowed options")));
- allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,
- _("Load configuration from specified file")));
- allowed_options.insert("port", ValueSpec(VALUETYPE_STRING,
- _("Set network port (UDP)")));
- allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG,
- _("Disable unit tests")));
- allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG,
- _("Enable unit tests")));
- allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING,
- _("Same as --world (deprecated)")));
- allowed_options.insert("world", ValueSpec(VALUETYPE_STRING,
- _("Set world path (implies local game) ('list' lists all)")));
- allowed_options.insert("worldname", ValueSpec(VALUETYPE_STRING,
- _("Set world by name (implies local game)")));
- allowed_options.insert("info", ValueSpec(VALUETYPE_FLAG,
- _("Print more information to console")));
- allowed_options.insert("verbose", ValueSpec(VALUETYPE_FLAG,
- _("Print even more information to console")));
- allowed_options.insert("trace", ValueSpec(VALUETYPE_FLAG,
- _("Print enormous amounts of information to log and console")));
- allowed_options.insert("logfile", ValueSpec(VALUETYPE_STRING,
- _("Set logfile path ('' = no logging)")));
- allowed_options.insert("gameid", ValueSpec(VALUETYPE_STRING,
- _("Set gameid (\"--gameid list\" prints available ones)")));
+ std::map<std::string, ValueSpec> allowed_options;
+ allowed_options.insert(std::make_pair("help", ValueSpec(VALUETYPE_FLAG,
+ _("Show allowed options"))));
+ allowed_options.insert(std::make_pair("config", ValueSpec(VALUETYPE_STRING,
+ _("Load configuration from specified file"))));
+ allowed_options.insert(std::make_pair("port", ValueSpec(VALUETYPE_STRING,
+ _("Set network port (UDP)"))));
+ allowed_options.insert(std::make_pair("disable-unittests", ValueSpec(VALUETYPE_FLAG,
+ _("Disable unit tests"))));
+ allowed_options.insert(std::make_pair("enable-unittests", ValueSpec(VALUETYPE_FLAG,
+ _("Enable unit tests"))));
+ allowed_options.insert(std::make_pair("map-dir", ValueSpec(VALUETYPE_STRING,
+ _("Same as --world (deprecated)"))));
+ allowed_options.insert(std::make_pair("world", ValueSpec(VALUETYPE_STRING,
+ _("Set world path (implies local game) ('list' lists all)"))));
+ allowed_options.insert(std::make_pair("worldname", ValueSpec(VALUETYPE_STRING,
+ _("Set world by name (implies local game)"))));
+ allowed_options.insert(std::make_pair("info", ValueSpec(VALUETYPE_FLAG,
+ _("Print more information to console"))));
+ allowed_options.insert(std::make_pair("verbose", ValueSpec(VALUETYPE_FLAG,
+ _("Print even more information to console"))));
+ allowed_options.insert(std::make_pair("trace", ValueSpec(VALUETYPE_FLAG,
+ _("Print enormous amounts of information to log and console"))));
+ allowed_options.insert(std::make_pair("logfile", ValueSpec(VALUETYPE_STRING,
+ _("Set logfile path ('' = no logging)"))));
+ allowed_options.insert(std::make_pair("gameid", ValueSpec(VALUETYPE_STRING,
+ _("Set gameid (\"--gameid list\" prints available ones)"))));
#ifndef SERVER
- allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG,
- _("Run speed tests")));
- allowed_options.insert("address", ValueSpec(VALUETYPE_STRING,
- _("Address to connect to. ('' = local game)")));
- allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG,
- _("Enable random user input, for testing")));
- allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,
- _("Run dedicated server")));
- allowed_options.insert("name", ValueSpec(VALUETYPE_STRING,
- _("Set player name")));
- allowed_options.insert("password", ValueSpec(VALUETYPE_STRING,
- _("Set password")));
- allowed_options.insert("go", ValueSpec(VALUETYPE_FLAG,
- _("Disable main menu")));
+ allowed_options.insert(std::make_pair("speedtests", ValueSpec(VALUETYPE_FLAG,
+ _("Run speed tests"))));
+ allowed_options.insert(std::make_pair("address", ValueSpec(VALUETYPE_STRING,
+ _("Address to connect to. ('' = local game)"))));
+ allowed_options.insert(std::make_pair("random-input", ValueSpec(VALUETYPE_FLAG,
+ _("Enable random user input, for testing"))));
+ allowed_options.insert(std::make_pair("server", ValueSpec(VALUETYPE_FLAG,
+ _("Run dedicated server"))));
+ allowed_options.insert(std::make_pair("name", ValueSpec(VALUETYPE_STRING,
+ _("Set player name"))));
+ allowed_options.insert(std::make_pair("password", ValueSpec(VALUETYPE_STRING,
+ _("Set password"))));
+ allowed_options.insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG,
+ _("Disable main menu"))));
#endif
Settings cmd_args;
@@ -839,20 +925,20 @@ int main(int argc, char *argv[])
if(ret == false || cmd_args.getFlag("help") || cmd_args.exists("nonopt1"))
{
dstream<<_("Allowed options:")<<std::endl;
- for(core::map<std::string, ValueSpec>::Iterator
- i = allowed_options.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<std::string, ValueSpec>::iterator
+ i = allowed_options.begin();
+ i != allowed_options.end(); ++i)
{
std::ostringstream os1(std::ios::binary);
- os1<<" --"<<i.getNode()->getKey();
- if(i.getNode()->getValue().type == VALUETYPE_FLAG)
+ os1<<" --"<<i->first;
+ if(i->second.type == VALUETYPE_FLAG)
{}
else
os1<<_(" <value>");
dstream<<padStringRight(os1.str(), 24);
- if(i.getNode()->getValue().help != NULL)
- dstream<<i.getNode()->getValue().help;
+ if(i->second.help != NULL)
+ dstream<<i->second.help;
dstream<<std::endl;
}
@@ -953,7 +1039,7 @@ int main(int argc, char *argv[])
}
else
{
- core::array<std::string> filenames;
+ std::vector<std::string> filenames;
filenames.push_back(porting::path_user +
DIR_DELIM + "minetest.conf");
// Legacy configuration file location
@@ -1279,6 +1365,14 @@ int main(int argc, char *argv[])
driverType = video::EDT_DIRECT3D9;
else if(driverstring == "opengl")
driverType = video::EDT_OPENGL;
+#ifdef _IRR_COMPILE_WITH_OGLES1_
+ else if(driverstring == "ogles1")
+ driverType = video::EDT_OGLES1;
+#endif
+#ifdef _IRR_COMPILE_WITH_OGLES2_
+ else if(driverstring == "ogles2")
+ driverType = video::EDT_OGLES2;
+#endif
else
{
errorstream<<"WARNING: Invalid video_driver specified; defaulting "
@@ -1462,6 +1556,8 @@ int main(int argc, char *argv[])
MainMenuData menudata;
if(g_settings->exists("selected_mainmenu_tab"))
menudata.selected_tab = g_settings->getS32("selected_mainmenu_tab");
+ if(g_settings->exists("selected_serverlist"))
+ menudata.selected_serverlist = g_settings->getS32("selected_serverlist");
menudata.address = narrow_to_wide(address);
menudata.name = narrow_to_wide(playername);
menudata.port = narrow_to_wide(itos(port));
@@ -1478,6 +1574,7 @@ int main(int argc, char *argv[])
menudata.enable_shaders = g_settings->getS32("enable_shaders");
menudata.preload_item_visuals = g_settings->getBool("preload_item_visuals");
menudata.enable_particles = g_settings->getBool("enable_particles");
+ menudata.liquid_finite = g_settings->getBool("liquid_finite");
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, menudata.mip_map);
menudata.creative_mode = g_settings->getBool("creative_mode");
menudata.enable_damage = g_settings->getBool("enable_damage");
@@ -1518,7 +1615,7 @@ int main(int argc, char *argv[])
if(skip_main_menu == false)
{
video::IVideoDriver* driver = device->getVideoDriver();
-
+ float fps_max = g_settings->getFloat("fps_max");
infostream<<"Waiting for other menus"<<std::endl;
while(device->run() && kill == false)
{
@@ -1540,6 +1637,22 @@ int main(int argc, char *argv[])
&g_menumgr, &menudata, g_gamecallback);
menu->allowFocusRemoval(true);
+ // Clouds for the main menu
+ bool cloud_menu_background = false;
+ Clouds *clouds = NULL;
+ if (g_settings->getBool("menu_clouds")) {
+ cloud_menu_background = true;
+ clouds = new Clouds(smgr->getRootSceneNode(),
+ smgr, -1, rand(), 100);
+ clouds->update(v2f(0, 0), video::SColor(255,200,200,255));
+
+ // A camera to see the clouds
+ scene::ICameraSceneNode* camera;
+ camera = smgr->addCameraSceneNode(0,
+ v3f(0,0,0), v3f(0, 60, 100));
+ camera->setFarValue(10000);
+ }
+
if(error_message != L"")
{
verbosestream<<"error_message = "
@@ -1552,6 +1665,9 @@ int main(int argc, char *argv[])
error_message = L"";
}
+ // Time is in milliseconds, for clouds
+ u32 lasttime = device->getTimer()->getTime();
+
infostream<<"Created main menu"<<std::endl;
while(device->run() && kill == false)
@@ -1559,26 +1675,75 @@ int main(int argc, char *argv[])
if(menu->getStatus() == true)
break;
- //driver->beginScene(true, true, video::SColor(255,0,0,0));
- driver->beginScene(true, true, video::SColor(255,128,128,128));
+ // Time calc for the clouds
+ f32 dtime; // in seconds
+ if (cloud_menu_background) {
+ u32 time = device->getTimer()->getTime();
+ if(time > lasttime)
+ dtime = (time - lasttime) / 1000.0;
+ else
+ dtime = 0;
+ lasttime = time;
+ }
- drawMenuBackground(driver);
+ //driver->beginScene(true, true, video::SColor(255,0,0,0));
+ driver->beginScene(true, true, video::SColor(255,140,186,250));
+
+ if (cloud_menu_background) {
+ // *3 otherwise the clouds would move very slowly
+ clouds->step(dtime*3);
+ clouds->render();
+ smgr->drawAll();
+ drawMenuSplash(driver);
+ drawMenuFooter(driver, true);
+ drawMenuHeader(driver);
+ } else {
+ drawMenuBackground(driver);
+ drawMenuFooter(driver, false);
+ }
guienv->drawAll();
-
+
driver->endScene();
// On some computers framerate doesn't seem to be
// automatically limited
- sleep_ms(25);
+ if (cloud_menu_background) {
+ // Time of frame without fps limit
+ float busytime;
+ u32 busytime_u32;
+ // not using getRealTime is necessary for wine
+ u32 time = device->getTimer()->getTime();
+ if(time > lasttime)
+ busytime_u32 = time - lasttime;
+ else
+ busytime_u32 = 0;
+ busytime = busytime_u32 / 1000.0;
+
+ // FPS limiter
+ u32 frametime_min = 1000./fps_max;
+
+ if(busytime_u32 < frametime_min) {
+ u32 sleeptime = frametime_min - busytime_u32;
+ device->sleep(sleeptime);
+ }
+ } else {
+ sleep_ms(25);
+ }
}
infostream<<"Dropping main menu"<<std::endl;
menu->drop();
+ if (cloud_menu_background) {
+ clouds->drop();
+ smgr->clear();
+ }
}
playername = wide_to_narrow(menudata.name);
+ if (playername == "")
+ playername = std::string("Guest") + itos(myrand_range(1000,9999));
password = translatePassword(playername, menudata.password);
//infostream<<"Main: password hash: '"<<password<<"'"<<std::endl;
@@ -1589,6 +1754,7 @@ int main(int argc, char *argv[])
simple_singleplayer_mode = menudata.simple_singleplayer_mode;
// Save settings
g_settings->setS32("selected_mainmenu_tab", menudata.selected_tab);
+ g_settings->setS32("selected_serverlist", menudata.selected_serverlist);
g_settings->set("new_style_leaves", itos(menudata.fancy_trees));
g_settings->set("smooth_lighting", itos(menudata.smooth_lighting));
g_settings->set("enable_3d_clouds", itos(menudata.clouds_3d));
@@ -1602,6 +1768,7 @@ int main(int argc, char *argv[])
g_settings->setS32("enable_shaders", menudata.enable_shaders);
g_settings->set("preload_item_visuals", itos(menudata.preload_item_visuals));
g_settings->set("enable_particles", itos(menudata.enable_particles));
+ g_settings->set("liquid_finite", itos(menudata.liquid_finite));
g_settings->set("creative_mode", itos(menudata.creative_mode));
g_settings->set("enable_damage", itos(menudata.enable_damage));
diff --git a/src/mainmenumanager.h b/src/mainmenumanager.h
index ce7684f11..a3133686b 100644
--- a/src/mainmenumanager.h
+++ b/src/mainmenumanager.h
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h" // assert
#include "modalMenu.h"
#include "guiPauseMenu.h" //For IGameCallback
+#include <list>
extern gui::IGUIEnvironment* guienv;
extern gui::IGUIStaticText *guiroot;
@@ -37,15 +38,15 @@ class MainMenuManager : public IMenuManager
public:
virtual void createdMenu(GUIModalMenu *menu)
{
- for(core::list<GUIModalMenu*>::Iterator
+ for(std::list<GUIModalMenu*>::iterator
i = m_stack.begin();
- i != m_stack.end(); i++)
+ i != m_stack.end(); ++i)
{
assert(*i != menu);
}
if(m_stack.size() != 0)
- (*m_stack.getLast())->setVisible(false);
+ m_stack.back()->setVisible(false);
m_stack.push_back(menu);
}
@@ -55,9 +56,9 @@ public:
bool removed_entry;
do{
removed_entry = false;
- for(core::list<GUIModalMenu*>::Iterator
+ for(std::list<GUIModalMenu*>::iterator
i = m_stack.begin();
- i != m_stack.end(); i++)
+ i != m_stack.end(); ++i)
{
if(*i == menu)
{
@@ -73,7 +74,7 @@ public:
m_stack.erase(i);*/
if(m_stack.size() != 0)
- (*m_stack.getLast())->setVisible(true);
+ m_stack.back()->setVisible(true);
}
u32 menuCount()
@@ -81,7 +82,7 @@ public:
return m_stack.size();
}
- core::list<GUIModalMenu*> m_stack;
+ std::list<GUIModalMenu*> m_stack;
};
extern MainMenuManager g_menumgr;
diff --git a/src/map.cpp b/src/map.cpp
index 4be094326..5d6b79fb0 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "rollback_interface.h"
#include "emerge.h"
#include "mapgen_v6.h"
+#include "mapgen_indev.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@@ -73,34 +74,30 @@ Map::~Map()
/*
Free all MapSectors
*/
- core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
- for(; i.atEnd() == false; i++)
+ for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
+ i != m_sectors.end(); ++i)
{
- MapSector *sector = i.getNode()->getValue();
- delete sector;
+ delete i->second;
}
}
void Map::addEventReceiver(MapEventReceiver *event_receiver)
{
- m_event_receivers.insert(event_receiver, false);
+ m_event_receivers.insert(event_receiver);
}
void Map::removeEventReceiver(MapEventReceiver *event_receiver)
{
- if(m_event_receivers.find(event_receiver) == NULL)
- return;
- m_event_receivers.remove(event_receiver);
+ m_event_receivers.erase(event_receiver);
}
void Map::dispatchEvent(MapEditEvent *event)
{
- for(core::map<MapEventReceiver*, bool>::Iterator
- i = m_event_receivers.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<MapEventReceiver*>::iterator
+ i = m_event_receivers.begin();
+ i != m_event_receivers.end(); ++i)
{
- MapEventReceiver* event_receiver = i.getNode()->getKey();
- event_receiver->onMapEditEvent(event);
+ (*i)->onMapEditEvent(event);
}
}
@@ -111,12 +108,12 @@ MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
return sector;
}
- core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
+ std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
- if(n == NULL)
+ if(n == m_sectors.end())
return NULL;
- MapSector *sector = n->getValue();
+ MapSector *sector = n->second;
// Cache the last result
m_sector_cache_p = p;
@@ -236,9 +233,9 @@ void Map::setNode(v3s16 p, MapNode & n)
values of from_nodes are lighting values.
*/
void Map::unspreadLight(enum LightBank bank,
- core::map<v3s16, u8> & from_nodes,
- core::map<v3s16, bool> & light_sources,
- core::map<v3s16, MapBlock*> & modified_blocks)
+ std::map<v3s16, u8> & from_nodes,
+ std::set<v3s16> & light_sources,
+ std::map<v3s16, MapBlock*> & modified_blocks)
{
INodeDefManager *nodemgr = m_gamedef->ndef();
@@ -256,9 +253,7 @@ void Map::unspreadLight(enum LightBank bank,
u32 blockchangecount = 0;
- core::map<v3s16, u8> unlighted_nodes;
- core::map<v3s16, u8>::Iterator j;
- j = from_nodes.getIterator();
+ std::map<v3s16, u8> unlighted_nodes;
/*
Initialize block cache
@@ -268,9 +263,10 @@ void Map::unspreadLight(enum LightBank bank,
// Cache this a bit, too
bool block_checked_in_modified = false;
- for(; j.atEnd() == false; j++)
+ for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
+ j != from_nodes.end(); ++j)
{
- v3s16 pos = j.getNode()->getKey();
+ v3s16 pos = j->first;
v3s16 blockpos = getNodeBlockPos(pos);
// Only fetch a new block if the block position has changed
@@ -297,7 +293,7 @@ void Map::unspreadLight(enum LightBank bank,
// Get node straight from the block
MapNode n = block->getNode(relpos);
- u8 oldlight = j.getNode()->getValue();
+ u8 oldlight = j->second;
// Loop through 6 neighbors
for(u16 i=0; i<6; i++)
@@ -354,7 +350,7 @@ void Map::unspreadLight(enum LightBank bank,
n2.setLight(bank, 0, nodemgr);
block->setNode(relpos, n2);
- unlighted_nodes.insert(n2pos, current_light);
+ unlighted_nodes[n2pos] = current_light;
changed = true;
/*
@@ -373,16 +369,16 @@ void Map::unspreadLight(enum LightBank bank,
light_sources.remove(n2pos);*/
}
else{
- light_sources.insert(n2pos, true);
+ light_sources.insert(n2pos);
}
// Add to modified_blocks
if(changed == true && block_checked_in_modified == false)
{
// If the block is not found in modified_blocks, add.
- if(modified_blocks.find(blockpos) == NULL)
+ if(modified_blocks.find(blockpos) == modified_blocks.end())
{
- modified_blocks.insert(blockpos, block);
+ modified_blocks[blockpos] = block;
}
block_checked_in_modified = true;
}
@@ -408,11 +404,11 @@ void Map::unspreadLight(enum LightBank bank,
*/
void Map::unLightNeighbors(enum LightBank bank,
v3s16 pos, u8 lightwas,
- core::map<v3s16, bool> & light_sources,
- core::map<v3s16, MapBlock*> & modified_blocks)
+ std::set<v3s16> & light_sources,
+ std::map<v3s16, MapBlock*> & modified_blocks)
{
- core::map<v3s16, u8> from_nodes;
- from_nodes.insert(pos, lightwas);
+ std::map<v3s16, u8> from_nodes;
+ from_nodes[pos] = lightwas;
unspreadLight(bank, from_nodes, light_sources, modified_blocks);
}
@@ -422,8 +418,8 @@ void Map::unLightNeighbors(enum LightBank bank,
goes on recursively.
*/
void Map::spreadLight(enum LightBank bank,
- core::map<v3s16, bool> & from_nodes,
- core::map<v3s16, MapBlock*> & modified_blocks)
+ std::set<v3s16> & from_nodes,
+ std::map<v3s16, MapBlock*> & modified_blocks)
{
INodeDefManager *nodemgr = m_gamedef->ndef();
@@ -441,9 +437,7 @@ void Map::spreadLight(enum LightBank bank,
u32 blockchangecount = 0;
- core::map<v3s16, bool> lighted_nodes;
- core::map<v3s16, bool>::Iterator j;
- j = from_nodes.getIterator();
+ std::set<v3s16> lighted_nodes;
/*
Initialize block cache
@@ -453,12 +447,10 @@ void Map::spreadLight(enum LightBank bank,
// Cache this a bit, too
bool block_checked_in_modified = false;
- for(; j.atEnd() == false; j++)
- //for(; j != from_nodes.end(); j++)
+ for(std::set<v3s16>::iterator j = from_nodes.begin();
+ j != from_nodes.end(); ++j)
{
- v3s16 pos = j.getNode()->getKey();
- //v3s16 pos = *j;
- //infostream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
+ v3s16 pos = *j;
v3s16 blockpos = getNodeBlockPos(pos);
// Only fetch a new block if the block position has changed
@@ -525,8 +517,7 @@ void Map::spreadLight(enum LightBank bank,
*/
if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
{
- lighted_nodes.insert(n2pos, true);
- //lighted_nodes.push_back(n2pos);
+ lighted_nodes.insert(n2pos);
changed = true;
}
/*
@@ -539,8 +530,7 @@ void Map::spreadLight(enum LightBank bank,
{
n2.setLight(bank, newlight, nodemgr);
block->setNode(relpos, n2);
- lighted_nodes.insert(n2pos, true);
- //lighted_nodes.push_back(n2pos);
+ lighted_nodes.insert(n2pos);
changed = true;
}
}
@@ -549,9 +539,9 @@ void Map::spreadLight(enum LightBank bank,
if(changed == true && block_checked_in_modified == false)
{
// If the block is not found in modified_blocks, add.
- if(modified_blocks.find(blockpos) == NULL)
+ if(modified_blocks.find(blockpos) == modified_blocks.end())
{
- modified_blocks.insert(blockpos, block);
+ modified_blocks[blockpos] = block;
}
block_checked_in_modified = true;
}
@@ -577,10 +567,10 @@ void Map::spreadLight(enum LightBank bank,
*/
void Map::lightNeighbors(enum LightBank bank,
v3s16 pos,
- core::map<v3s16, MapBlock*> & modified_blocks)
+ std::map<v3s16, MapBlock*> & modified_blocks)
{
- core::map<v3s16, bool> from_nodes;
- from_nodes.insert(pos, true);
+ std::set<v3s16> from_nodes;
+ from_nodes.insert(pos);
spreadLight(bank, from_nodes, modified_blocks);
}
@@ -635,7 +625,7 @@ v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
Mud is turned into grass in where the sunlight stops.
*/
s16 Map::propagateSunlight(v3s16 start,
- core::map<v3s16, MapBlock*> & modified_blocks)
+ std::map<v3s16, MapBlock*> & modified_blocks)
{
INodeDefManager *nodemgr = m_gamedef->ndef();
@@ -662,7 +652,7 @@ s16 Map::propagateSunlight(v3s16 start,
n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
block->setNode(relpos, n);
- modified_blocks.insert(blockpos, block);
+ modified_blocks[blockpos] = block;
}
else
{
@@ -674,8 +664,8 @@ s16 Map::propagateSunlight(v3s16 start,
}
void Map::updateLighting(enum LightBank bank,
- core::map<v3s16, MapBlock*> & a_blocks,
- core::map<v3s16, MapBlock*> & modified_blocks)
+ std::map<v3s16, MapBlock*> & a_blocks,
+ std::map<v3s16, MapBlock*> & modified_blocks)
{
INodeDefManager *nodemgr = m_gamedef->ndef();
@@ -688,22 +678,21 @@ void Map::updateLighting(enum LightBank bank,
//bool debug=true;
//u32 count_was = modified_blocks.size();
- core::map<v3s16, MapBlock*> blocks_to_update;
+ std::map<v3s16, MapBlock*> blocks_to_update;
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
- core::map<v3s16, u8> unlight_from;
+ std::map<v3s16, u8> unlight_from;
int num_bottom_invalid = 0;
{
//TimeTaker t("first stuff");
- core::map<v3s16, MapBlock*>::Iterator i;
- i = a_blocks.getIterator();
- for(; i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator i = a_blocks.begin();
+ i != a_blocks.end(); ++i)
{
- MapBlock *block = i.getNode()->getValue();
+ MapBlock *block = i->second;
for(;;)
{
@@ -713,9 +702,8 @@ void Map::updateLighting(enum LightBank bank,
v3s16 pos = block->getPos();
v3s16 posnodes = block->getPosRelative();
- modified_blocks.insert(pos, block);
-
- blocks_to_update.insert(pos, block);
+ modified_blocks[pos] = block;
+ blocks_to_update[pos] = block;
/*
Clear all light from block
@@ -735,7 +723,7 @@ void Map::updateLighting(enum LightBank bank,
// If node sources light, add to list
u8 source = nodemgr->get(n).light_source;
if(source != 0)
- light_sources[p + posnodes] = true;
+ light_sources.insert(p + posnodes);
// Collect borders for unlighting
if((x==0 || x == MAP_BLOCKSIZE-1
@@ -744,7 +732,7 @@ void Map::updateLighting(enum LightBank bank,
&& oldlight != 0)
{
v3s16 p_map = p + posnodes;
- unlight_from.insert(p_map, oldlight);
+ unlight_from[p_map] = oldlight;
}
}
catch(InvalidPositionException &e)
@@ -912,8 +900,8 @@ void Map::updateLighting(enum LightBank bank,
//m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
}
-void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
- core::map<v3s16, MapBlock*> & modified_blocks)
+void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
+ std::map<v3s16, MapBlock*> & modified_blocks)
{
updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
@@ -921,11 +909,11 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
/*
Update information about whether day and night light differ
*/
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- MapBlock *block = i.getNode()->getValue();
+ MapBlock *block = i->second;
block->expireDayNightDiff();
}
}
@@ -933,7 +921,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
/*
*/
void Map::addNodeAndUpdate(v3s16 p, MapNode n,
- core::map<v3s16, MapBlock*> &modified_blocks)
+ std::map<v3s16, MapBlock*> &modified_blocks)
{
INodeDefManager *ndef = m_gamedef->ndef();
@@ -952,7 +940,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
v3s16 bottompos = p + v3s16(0,-1,0);
bool node_under_sunlight = true;
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
/*
Collect old node for rollback
@@ -994,7 +982,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
v3s16 blockpos = getNodeBlockPos(p);
MapBlock * block = getBlockNoCreate(blockpos);
assert(block != NULL);
- modified_blocks.insert(blockpos, block);
+ modified_blocks[blockpos] = block;
assert(isValidPosition(p));
@@ -1078,12 +1066,11 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
/*
Update information about whether day and night light differ
*/
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- MapBlock *block = i.getNode()->getValue();
- block->expireDayNightDiff();
+ i->second->expireDayNightDiff();
}
/*
@@ -1132,7 +1119,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
/*
*/
void Map::removeNodeAndUpdate(v3s16 p,
- core::map<v3s16, MapBlock*> &modified_blocks)
+ std::map<v3s16, MapBlock*> &modified_blocks)
{
INodeDefManager *ndef = m_gamedef->ndef();
@@ -1166,7 +1153,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
{
}
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
enum LightBank banks[] =
{
@@ -1214,7 +1201,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
v3s16 blockpos = getNodeBlockPos(p);
MapBlock * block = getBlockNoCreate(blockpos);
assert(block != NULL);
- modified_blocks.insert(blockpos, block);
+ modified_blocks[blockpos] = block;
/*
If the removed node was under sunlight, propagate the
@@ -1270,12 +1257,11 @@ void Map::removeNodeAndUpdate(v3s16 p,
/*
Update information about whether day and night light differ
*/
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- MapBlock *block = i.getNode()->getValue();
- block->expireDayNightDiff();
+ i->second->expireDayNightDiff();
}
/*
@@ -1330,15 +1316,15 @@ bool Map::addNodeWithEvent(v3s16 p, MapNode n)
bool succeeded = true;
try{
- core::map<v3s16, MapBlock*> modified_blocks;
+ std::map<v3s16, MapBlock*> modified_blocks;
addNodeAndUpdate(p, n, modified_blocks);
// Copy modified_blocks to event
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- event.modified_blocks.insert(i.getNode()->getKey(), false);
+ event.modified_blocks.insert(i->first);
}
}
catch(InvalidPositionException &e){
@@ -1358,15 +1344,15 @@ bool Map::removeNodeWithEvent(v3s16 p)
bool succeeded = true;
try{
- core::map<v3s16, MapBlock*> modified_blocks;
+ std::map<v3s16, MapBlock*> modified_blocks;
removeNodeAndUpdate(p, modified_blocks);
// Copy modified_blocks to event
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- event.modified_blocks.insert(i.getNode()->getKey(), false);
+ event.modified_blocks.insert(i->first);
}
}
catch(InvalidPositionException &e){
@@ -1439,33 +1425,31 @@ bool Map::getDayNightDiff(v3s16 blockpos)
Updates usage timers
*/
void Map::timerUpdate(float dtime, float unload_timeout,
- core::list<v3s16> *unloaded_blocks)
+ std::list<v3s16> *unloaded_blocks)
{
bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
// Profile modified reasons
Profiler modprofiler;
- core::list<v2s16> sector_deletion_queue;
+ std::list<v2s16> sector_deletion_queue;
u32 deleted_blocks_count = 0;
u32 saved_blocks_count = 0;
u32 block_count_all = 0;
- core::map<v2s16, MapSector*>::Iterator si;
-
beginSave();
- si = m_sectors.getIterator();
- for(; si.atEnd() == false; si++)
+ for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+ si != m_sectors.end(); ++si)
{
- MapSector *sector = si.getNode()->getValue();
+ MapSector *sector = si->second;
bool all_blocks_deleted = true;
- core::list<MapBlock*> blocks;
+ std::list<MapBlock*> blocks;
sector->getBlocks(blocks);
- for(core::list<MapBlock*>::Iterator i = blocks.begin();
- i != blocks.end(); i++)
+ for(std::list<MapBlock*>::iterator i = blocks.begin();
+ i != blocks.end(); ++i)
{
MapBlock *block = (*i);
@@ -1501,7 +1485,7 @@ void Map::timerUpdate(float dtime, float unload_timeout,
if(all_blocks_deleted)
{
- sector_deletion_queue.push_back(si.getNode()->getKey());
+ sector_deletion_queue.push_back(si->first);
}
}
endSave();
@@ -1526,17 +1510,17 @@ void Map::timerUpdate(float dtime, float unload_timeout,
}
}
-void Map::deleteSectors(core::list<v2s16> &list)
+void Map::deleteSectors(std::list<v2s16> &list)
{
- core::list<v2s16>::Iterator j;
- for(j=list.begin(); j!=list.end(); j++)
+ for(std::list<v2s16>::iterator j = list.begin();
+ j != list.end(); ++j)
{
MapSector *sector = m_sectors[*j];
// If sector is in sector cache, remove it from there
if(m_sector_cache == sector)
m_sector_cache = NULL;
// Remove from map and delete
- m_sectors.remove(*j);
+ m_sectors.erase(*j);
delete sector;
}
}
@@ -1642,7 +1626,7 @@ const v3s16 g_7dirs[7] =
#define D_TOP 6
#define D_SELF 1
-void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
+void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
{
INodeDefManager *nodemgr = m_gamedef->ndef();
@@ -1656,19 +1640,16 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
bool fast_flood = g_settings->getS16("liquid_fast_flood");
int water_level = g_settings->getS16("water_level");
- /*if(initial_size != 0)
- infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
-
// list of nodes that due to viscosity have not reached their max level height
UniqueQueue<v3s16> must_reflow, must_reflow_second;
// List of MapBlocks that will require a lighting update (due to lava)
- core::map<v3s16, MapBlock*> lighting_modified_blocks;
+ std::map<v3s16, MapBlock*> lighting_modified_blocks;
- while(m_transforming_liquid.size() > 0)
+ while (m_transforming_liquid.size() > 0)
{
// This should be done here so that it is done when continue is used
- if(loopcount >= initial_size || loopcount >= 1000)
+ if (loopcount >= initial_size || loopcount >= 1000)
break;
loopcount++;
/*
@@ -1676,9 +1657,12 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
*/
v3s16 p0 = m_transforming_liquid.pop_front();
u16 total_level = 0;
- NodeNeighbor neighbors[7]; // surrounding flowing liquid nodes
- s8 liquid_levels[7] = {-1, -1, -1, -1, -1, -1, -1}; // current level of every block
- s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1}; // target levels
+ // surrounding flowing liquid nodes
+ NodeNeighbor neighbors[7];
+ // current level of every block
+ s8 liquid_levels[7] = {-1, -1, -1, -1, -1, -1, -1};
+ // target levels
+ s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1};
s8 can_liquid_same_level = 0;
content_t liquid_kind = CONTENT_IGNORE;
content_t liquid_kind_flowing = CONTENT_IGNORE;
@@ -1713,9 +1697,11 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
}
break;
case LIQUID_SOURCE:
- // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
+ // if this node is not (yet) of a liquid type,
+ // choose the first liquid type we encounter
if (liquid_kind_flowing == CONTENT_IGNORE)
- liquid_kind_flowing = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
+ liquid_kind_flowing = nodemgr->getId(
+ nodemgr->get(nb.n).liquid_alternative_flowing);
if (liquid_kind == CONTENT_IGNORE)
liquid_kind = nb.n.getContent();
if (nb.n.getContent() == liquid_kind) {
@@ -1725,37 +1711,55 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
}
break;
case LIQUID_FLOWING:
- // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
+ // if this node is not (yet) of a liquid type,
+ // choose the first liquid type we encounter
if (liquid_kind_flowing == CONTENT_IGNORE)
liquid_kind_flowing = nb.n.getContent();
if (liquid_kind == CONTENT_IGNORE)
- liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_source);
+ liquid_kind = nodemgr->getId(
+ nodemgr->get(nb.n).liquid_alternative_source);
if (nb.n.getContent() == liquid_kind_flowing) {
liquid_levels[i] = (nb.n.param2 & LIQUID_LEVEL_MASK);
nb.l = 1;
}
break;
}
- if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL) ++can_liquid_same_level;
- if (liquid_levels[i] > 0) total_level += liquid_levels[i];
+
+ if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL)
+ ++can_liquid_same_level;
+ if (liquid_levels[i] > 0)
+ total_level += liquid_levels[i];
/*
- infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c="<<nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1="<< (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt="<<nodemgr->get(nb.n.getContent()).liquid_type
+ infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c="
+ << nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1="
+ << (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt="
+ << nodemgr->get(nb.n.getContent()).liquid_type
//<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing
- << " l="<< nb.l << " inf="<< nb.i << " nlevel=" << (int)liquid_levels[i] << " tlevel=" << (int)total_level << " cansame="<<(int)can_liquid_same_level<<std::endl;
+ << " l="<< nb.l << " inf="<< nb.i << " nlevel=" << (int)liquid_levels[i]
+ << " tlevel=" << (int)total_level << " cansame="
+ << (int)can_liquid_same_level << std::endl;
*/
}
- if (liquid_kind == CONTENT_IGNORE || !neighbors[D_SELF].l || total_level <= 0)
+ if (liquid_kind == CONTENT_IGNORE ||
+ !neighbors[D_SELF].l ||
+ total_level <= 0)
continue;
// fill bottom block
if (neighbors[D_BOTTOM].l) {
- liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ? LIQUID_LEVEL_SOURCE : total_level;
+ liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ?
+ LIQUID_LEVEL_SOURCE : total_level;
total_level -= liquid_levels_want[D_BOTTOM];
}
- if (relax && p0.Y <= water_level && liquid_levels[D_TOP] == 0 && total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level - can_liquid_same_level + 2 && can_liquid_same_level >= relax + 1) { //relax up
+ //relax up
+ if (relax && p0.Y <= water_level && liquid_levels[D_TOP] == 0 &&
+ liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE &&
+ total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level-
+ (can_liquid_same_level - relax) &&
+ can_liquid_same_level >= relax + 1) {
total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level;
}
@@ -1766,7 +1770,11 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
: total_level / can_liquid_same_level;
total_level -= want_level * can_liquid_same_level;
- if (relax && p0.Y > water_level && liquid_levels[D_TOP] == 0 && liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 && total_level <= can_liquid_same_level - 2 && can_liquid_same_level >= relax + 1) { //relax down
+ //relax down
+ if (relax && p0.Y == water_level + 1 && liquid_levels[D_TOP] == 0 &&
+ liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 &&
+ total_level <= (can_liquid_same_level - relax) &&
+ can_liquid_same_level >= relax + 1) {
total_level = 0;
}
@@ -1784,7 +1792,8 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
for (u16 ii = 0; ii < 7; ++ii) {
if (total_level < 1) break;
- if (liquid_levels_want[ii] >= 0 && liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE) {
+ if (liquid_levels_want[ii] >= 0 &&
+ liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE) {
++liquid_levels_want[ii];
--total_level;
}
@@ -1792,7 +1801,8 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
// fill top block if can
if (neighbors[D_TOP].l) {
- liquid_levels_want[D_TOP] = total_level > LIQUID_LEVEL_SOURCE ? LIQUID_LEVEL_SOURCE : total_level ;
+ liquid_levels_want[D_TOP] = total_level > LIQUID_LEVEL_SOURCE ?
+ LIQUID_LEVEL_SOURCE : total_level;
total_level -= liquid_levels_want[D_TOP];
}
@@ -1807,7 +1817,15 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
&& liquid_levels[D_TOP] >= LIQUID_LEVEL_SOURCE))))
liquid_levels_want[ii] = LIQUID_LEVEL_SOURCE;
- //if (total_level > 0 /*|| flowed != volume*/) infostream <<" AFTER level=" << (int)total_level /*<< " flowed="<<flowed<< " volume=" <<volume*/<< " wantsame="<<(int)want_level<< " top="<< (int)liquid_levels_want[D_TOP]<< " topwas="<< (int)liquid_levels[D_TOP]<< " bot="<< (int)liquid_levels_want[D_BOTTOM]<<std::endl;
+ /*
+ if (total_level > 0) //|| flowed != volume)
+ infostream <<" AFTER level=" << (int)total_level
+ //<< " flowed="<<flowed<< " volume=" << volume
+ << " wantsame="<<(int)want_level<< " top="
+ << (int)liquid_levels_want[D_TOP]<< " topwas="
+ << (int)liquid_levels[D_TOP]<< " bot="
+ << (int)liquid_levels_want[D_BOTTOM]<<std::endl;
+ */
u8 changed = 0;
for (u16 i = 0; i < 7; i++) {
@@ -1831,8 +1849,10 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
new_node_level = liquid_levels[i] - 1;
else if (level_inc > 0)
new_node_level = liquid_levels[i] + 1;
- } else
+ } else {
new_node_level = liquid_levels_want[i];
+ }
+
if (new_node_level >= LIQUID_LEVEL_SOURCE)
new_node_content = liquid_kind;
else if (new_node_level > 0)
@@ -1841,25 +1861,30 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
new_node_content = CONTENT_AIR;
// last level must flow down on stairs
- if (liquid_levels_want[i] != liquid_levels[i] && liquid_levels[D_TOP] <= 0 && !neighbors[D_BOTTOM].l && new_node_level >= 1 && new_node_level <= 2) //maybe == 1 //
+ if (liquid_levels_want[i] != liquid_levels[i] &&
+ liquid_levels[D_TOP] <= 0 && !neighbors[D_BOTTOM].l &&
+ new_node_level >= 1 && new_node_level <= 2) {
for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
- if (!neighbors[ii].l)
- continue;
- must_reflow_second.push_back(p0 + dirs[ii]);
+ if (neighbors[ii].l)
+ must_reflow_second.push_back(p0 + dirs[ii]);
+ }
}
/*
- check if anything has changed. if not, just continue with the next node.
+ check if anything has changed.
+ if not, just continue with the next node.
*/
if (
new_node_content == n0.getContent()
&& (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level
- // &&((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)== flowing_down
+ //&& ((n0.param2 & LIQUID_FLOW_DOWN_MASK) ==
+ //LIQUID_FLOW_DOWN_MASK) == flowing_down
))
&&
(nodemgr->get(n0.getContent()).liquid_type != LIQUID_SOURCE ||
- (((n0.param2 & LIQUID_INFINITY_MASK) == LIQUID_INFINITY_MASK) == neighbors[i].i
+ (((n0.param2 & LIQUID_INFINITY_MASK) ==
+ LIQUID_INFINITY_MASK) == neighbors[i].i
))
) {
continue;
@@ -1876,7 +1901,12 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
//n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
n0.param2 = (neighbors[i].i ? LIQUID_INFINITY_MASK : 0x00);
}
- //infostream << "set node i=" <<(int)i<<" "<< PP(p0)<< " nc="<<new_node_content<< " p2="<<(int)n0.param2<< " nl="<<(int)new_node_level<<std::endl;
+ /*
+ infostream << "set node i=" <<(int)i<<" "<< PP(p0)<< " nc="
+ <<new_node_content<< " p2="<<(int)n0.param2<< " nl="
+ <<(int)new_node_level<<std::endl;
+ */
+
n0.setContent(new_node_content);
// Find out whether there is a suspect for this action
std::string suspect;
@@ -1886,7 +1916,8 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
if(!suspect.empty()){
// Blame suspect
- RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
+ RollbackScopeActor rollback_scope(m_gamedef->rollback(),
+ suspect, true);
// Get old node for rollback
RollbackNode rollback_oldnode(this, p0, m_gamedef);
// Set node
@@ -1904,20 +1935,25 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
v3s16 blockpos = getNodeBlockPos(p0);
MapBlock *block = getBlockNoCreateNoEx(blockpos);
if(block != NULL) {
- modified_blocks.insert(blockpos, block);
+ modified_blocks[blockpos] = block;
// If node emits light, MapBlock requires lighting update
if(nodemgr->get(n0).light_source != 0)
lighting_modified_blocks[block->getPos()] = block;
}
must_reflow.push_back(neighbors[i].p);
}
- /* //for better relax
- if (changed) for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
+ /* //for better relax only same level
+ if (changed) for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) {
if (!neighbors[ii].l) continue;
must_reflow.push_back(p0 + dirs[ii]);
}*/
}
- //if (loopcount) infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<" reflow="<<must_reflow.size()<<" queue="<< m_transforming_liquid.size()<<std::endl;
+ /*
+ if (loopcount)
+ infostream<<"Map::transformLiquids(): loopcount="<<loopcount
+ <<" reflow="<<must_reflow.size()
+ <<" queue="<< m_transforming_liquid.size()<<std::endl;
+ */
while (must_reflow.size() > 0)
m_transforming_liquid.push_back(must_reflow.pop_front());
while (must_reflow_second.size() > 0)
@@ -1925,11 +1961,12 @@ void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
updateLighting(lighting_modified_blocks, modified_blocks);
}
-void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
+void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
{
- if (g_settings->getBool("liquid_finite")) return Map::transformLiquidsFinite(modified_blocks);
-
+ if (g_settings->getBool("liquid_finite"))
+ return Map::transformLiquidsFinite(modified_blocks);
+
INodeDefManager *nodemgr = m_gamedef->ndef();
DSTACK(__FUNCTION_NAME);
@@ -1945,7 +1982,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
UniqueQueue<v3s16> must_reflow;
// List of MapBlocks that will require a lighting update (due to lava)
- core::map<v3s16, MapBlock*> lighting_modified_blocks;
+ std::map<v3s16, MapBlock*> lighting_modified_blocks;
while(m_transforming_liquid.size() != 0)
{
@@ -2165,7 +2202,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
v3s16 blockpos = getNodeBlockPos(p0);
MapBlock *block = getBlockNoCreateNoEx(blockpos);
if(block != NULL) {
- modified_blocks.insert(blockpos, block);
+ modified_blocks[blockpos] = block;
// If node emits light, MapBlock requires lighting update
if(nodemgr->get(n0).light_source != 0)
lighting_modified_blocks[block->getPos()] = block;
@@ -2460,19 +2497,15 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
- //s16 chunksize = 3;
- //v3s16 chunk_offset(-1,-1,-1);
- //s16 chunksize = 4;
- //v3s16 chunk_offset(-1,-1,-1);
- s16 chunksize = 5;
- v3s16 chunk_offset(-2,-2,-2);
+ s16 chunksize = m_mgparams->chunksize;
+ s16 coffset = -chunksize / 2;
+ v3s16 chunk_offset(coffset, coffset, coffset);
v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
v3s16 blockpos_min = blockpos_div * chunksize;
v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
blockpos_min += chunk_offset;
blockpos_max += chunk_offset;
- //v3s16 extra_borders(1,1,1);
v3s16 extra_borders(1,1,1);
// Do nothing if not inside limits (+-1 because of neighbors)
@@ -2571,7 +2604,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
}
MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
- core::map<v3s16, MapBlock*> &changed_blocks)
+ std::map<v3s16, MapBlock*> &changed_blocks)
{
v3s16 blockpos_min = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max;
@@ -2676,10 +2709,10 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
/*
Go through changed blocks
*/
- for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
+ i != changed_blocks.end(); ++i)
{
- MapBlock *block = i.getNode()->getValue();
+ MapBlock *block = i->second;
assert(block);
/*
Update day/night difference cache of the MapBlocks
@@ -2797,7 +2830,7 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
/*
Insert to container
*/
- m_sectors.insert(p2d, sector);
+ m_sectors[p2d] = sector;
return sector;
}
@@ -2808,7 +2841,7 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
*/
MapBlock * ServerMap::generateBlock(
v3s16 p,
- core::map<v3s16, MapBlock*> &modified_blocks
+ std::map<v3s16, MapBlock*> &modified_blocks
)
{
DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
@@ -3008,7 +3041,7 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
}
/*if(allow_generate)
{
- core::map<v3s16, MapBlock*> modified_blocks;
+ std::map<v3s16, MapBlock*> modified_blocks;
MapBlock *block = generateBlock(p, modified_blocks);
if(block)
{
@@ -3017,11 +3050,11 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
event.p = p;
// Copy modified_blocks to event
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- event.modified_blocks.insert(i.getNode()->getKey(), false);
+ event.modified_blocks.insert(i->first);
}
// Queue event
@@ -3262,10 +3295,10 @@ void ServerMap::save(ModifiedState save_level)
// Don't do anything with sqlite unless something is really saved
bool save_started = false;
- core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
- for(; i.atEnd() == false; i++)
+ for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
+ i != m_sectors.end(); ++i)
{
- ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
+ ServerMapSector *sector = (ServerMapSector*)i->second;
assert(sector->getId() == MAPSECTOR_SERVER);
if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
@@ -3273,11 +3306,11 @@ void ServerMap::save(ModifiedState save_level)
saveSectorMeta(sector);
sector_meta_count++;
}
- core::list<MapBlock*> blocks;
+ std::list<MapBlock*> blocks;
sector->getBlocks(blocks);
- core::list<MapBlock*>::Iterator j;
- for(j=blocks.begin(); j!=blocks.end(); j++)
+ for(std::list<MapBlock*>::iterator j = blocks.begin();
+ j != blocks.end(); ++j)
{
MapBlock *block = *j;
@@ -3350,7 +3383,7 @@ v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
return v3s16(x,y,z);
}
-void ServerMap::listAllLoadableBlocks(core::list<v3s16> &dst)
+void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst)
{
if(loadFromFolders()){
errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
@@ -3487,7 +3520,7 @@ MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load
<<" Continuing with a sector with no metadata."
<<std::endl;*/
sector = new ServerMapSector(this, p2d, m_gamedef);
- m_sectors.insert(p2d, sector);
+ m_sectors[p2d] = sector;
}
else
{
@@ -3987,9 +4020,9 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
u8 flags = 0;
MapBlock *block;
v3s16 p(x,y,z);
- core::map<v3s16, u8>::Node *n;
+ std::map<v3s16, u8>::iterator n;
n = m_loaded_blocks.find(p);
- if(n != NULL)
+ if(n != m_loaded_blocks.end())
continue;
bool block_data_inexistent = false;
@@ -4017,7 +4050,7 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
if(block_data_inexistent)
{
flags |= VMANIP_BLOCK_DATA_INEXIST;
-
+
VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
// Fill with VOXELFLAG_INEXISTENT
for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
@@ -4033,7 +4066,7 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
}*/
- m_loaded_blocks.insert(p, flags);
+ m_loaded_blocks[p] = flags;
}
//infostream<<"emerge done"<<std::endl;
@@ -4045,7 +4078,7 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
run on background.
*/
void MapVoxelManipulator::blitBack
- (core::map<v3s16, MapBlock*> & modified_blocks)
+ (std::map<v3s16, MapBlock*> & modified_blocks)
{
if(m_area.getExtent() == v3s16(0,0,0))
return;
@@ -4156,9 +4189,9 @@ void ManualMapVoxelManipulator::initialEmerge(
u8 flags = 0;
MapBlock *block;
v3s16 p(x,y,z);
- core::map<v3s16, u8>::Node *n;
+ std::map<v3s16, u8>::iterator n;
n = m_loaded_blocks.find(p);
- if(n != NULL)
+ if(n != m_loaded_blocks.end())
continue;
bool block_data_inexistent = false;
@@ -4199,12 +4232,12 @@ void ManualMapVoxelManipulator::initialEmerge(
flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
}*/
- m_loaded_blocks.insert(p, flags);
+ m_loaded_blocks[p] = flags;
}
}
void ManualMapVoxelManipulator::blitBackAll(
- core::map<v3s16, MapBlock*> * modified_blocks)
+ std::map<v3s16, MapBlock*> * modified_blocks)
{
if(m_area.getExtent() == v3s16(0,0,0))
return;
@@ -4212,37 +4245,22 @@ void ManualMapVoxelManipulator::blitBackAll(
/*
Copy data of all blocks
*/
- for(core::map<v3s16, u8>::Iterator
- i = m_loaded_blocks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, u8>::iterator
+ i = m_loaded_blocks.begin();
+ i != m_loaded_blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
- u8 flags = i.getNode()->getValue();
-
- bool existed = !(flags & VMANIP_BLOCK_DATA_INEXIST);
- if(existed == false)
- {
- // The Great Bug was found using this
- /*infostream<<"ManualMapVoxelManipulator::blitBackAll: "
- <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
- <<std::endl;*/
- continue;
- }
-
+ v3s16 p = i->first;
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- if(block == NULL)
+ bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
+ if(existed == false)
{
- infostream<<"WARNING: "<<__FUNCTION_NAME
- <<": got NULL block "
- <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
- <<std::endl;
continue;
}
block->copyFrom(*this);
-
+
if(modified_blocks)
- modified_blocks->insert(p, block);
+ (*modified_blocks)[p] = block;
}
}
diff --git a/src/map.h b/src/map.h
index d356da2d1..31001e4c3 100644
--- a/src/map.h
+++ b/src/map.h
@@ -25,6 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <jthread.h>
#include <iostream>
#include <sstream>
+#include <set>
+#include <map>
+#include <list>
#include "irrlichttypes_bloated.h"
#include "mapnode.h"
@@ -47,7 +50,7 @@ class NodeMetadata;
class IGameDef;
class IRollbackReportSink;
class EmergeManager;
-class BlockMakeData;
+struct BlockMakeData;
/*
@@ -75,7 +78,7 @@ struct MapEditEvent
MapEditEventType type;
v3s16 p;
MapNode n;
- core::map<v3s16, bool> modified_blocks;
+ std::set<v3s16> modified_blocks;
u16 already_known_by_peer;
MapEditEvent():
@@ -90,14 +93,7 @@ struct MapEditEvent
event->type = type;
event->p = p;
event->n = n;
- for(core::map<v3s16, bool>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd()==false; i++)
- {
- v3s16 p = i.getNode()->getKey();
- bool v = i.getNode()->getValue();
- event->modified_blocks.insert(p, v);
- }
+ event->modified_blocks = modified_blocks;
return event;
}
@@ -117,11 +113,11 @@ struct MapEditEvent
case MEET_OTHER:
{
VoxelArea a;
- for(core::map<v3s16, bool>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<v3s16>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
+ v3s16 p = *i;
v3s16 np1 = p*MAP_BLOCKSIZE;
v3s16 np2 = np1 + v3s16(1,1,1)*MAP_BLOCKSIZE - v3s16(1,1,1);
a.addPoint(np1);
@@ -186,7 +182,7 @@ public:
*/
virtual MapSector * emergeSector(v2s16 p){ return NULL; }
virtual MapSector * emergeSector(v2s16 p,
- core::map<v3s16, MapBlock*> &changed_blocks){ return NULL; }
+ std::map<v3s16, MapBlock*> &changed_blocks){ return NULL; }
// Returns InvalidPositionException if not found
MapBlock * getBlockNoCreate(v3s16 p);
@@ -212,42 +208,42 @@ public:
MapNode getNodeNoEx(v3s16 p);
void unspreadLight(enum LightBank bank,
- core::map<v3s16, u8> & from_nodes,
- core::map<v3s16, bool> & light_sources,
- core::map<v3s16, MapBlock*> & modified_blocks);
+ std::map<v3s16, u8> & from_nodes,
+ std::set<v3s16> & light_sources,
+ std::map<v3s16, MapBlock*> & modified_blocks);
void unLightNeighbors(enum LightBank bank,
v3s16 pos, u8 lightwas,
- core::map<v3s16, bool> & light_sources,
- core::map<v3s16, MapBlock*> & modified_blocks);
+ std::set<v3s16> & light_sources,
+ std::map<v3s16, MapBlock*> & modified_blocks);
void spreadLight(enum LightBank bank,
- core::map<v3s16, bool> & from_nodes,
- core::map<v3s16, MapBlock*> & modified_blocks);
+ std::set<v3s16> & from_nodes,
+ std::map<v3s16, MapBlock*> & modified_blocks);
void lightNeighbors(enum LightBank bank,
v3s16 pos,
- core::map<v3s16, MapBlock*> & modified_blocks);
+ std::map<v3s16, MapBlock*> & modified_blocks);
v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p);
s16 propagateSunlight(v3s16 start,
- core::map<v3s16, MapBlock*> & modified_blocks);
+ std::map<v3s16, MapBlock*> & modified_blocks);
void updateLighting(enum LightBank bank,
- core::map<v3s16, MapBlock*> & a_blocks,
- core::map<v3s16, MapBlock*> & modified_blocks);
+ std::map<v3s16, MapBlock*> & a_blocks,
+ std::map<v3s16, MapBlock*> & modified_blocks);
- void updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
- core::map<v3s16, MapBlock*> & modified_blocks);
+ void updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
+ std::map<v3s16, MapBlock*> & modified_blocks);
/*
These handle lighting but not faces.
*/
void addNodeAndUpdate(v3s16 p, MapNode n,
- core::map<v3s16, MapBlock*> &modified_blocks);
+ std::map<v3s16, MapBlock*> &modified_blocks);
void removeNodeAndUpdate(v3s16 p,
- core::map<v3s16, MapBlock*> &modified_blocks);
+ std::map<v3s16, MapBlock*> &modified_blocks);
/*
Wrappers for the latter ones.
@@ -281,12 +277,12 @@ public:
Saves modified blocks before unloading on MAPTYPE_SERVER.
*/
void timerUpdate(float dtime, float unload_timeout,
- core::list<v3s16> *unloaded_blocks=NULL);
+ std::list<v3s16> *unloaded_blocks=NULL);
// Deletes sectors and their blocks from memory
// Takes cache into account
// If deleted sector is in sector cache, clears cache
- void deleteSectors(core::list<v2s16> &list);
+ void deleteSectors(std::list<v2s16> &list);
#if 0
/*
@@ -301,8 +297,8 @@ public:
// For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: "
virtual void PrintInfo(std::ostream &out);
- void transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks);
- void transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks);
+ void transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks);
+ void transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks);
/*
Node metadata
@@ -325,7 +321,7 @@ public:
/*
Misc.
*/
- core::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
+ std::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
/*
Variables
@@ -340,9 +336,9 @@ protected:
IGameDef *m_gamedef;
- core::map<MapEventReceiver*, bool> m_event_receivers;
+ std::set<MapEventReceiver*> m_event_receivers;
- core::map<v2s16, MapSector*> m_sectors;
+ std::map<v2s16, MapSector*> m_sectors;
// Be sure to set this to NULL when the cached sector is deleted
MapSector *m_sector_cache;
@@ -385,13 +381,7 @@ public:
*/
bool initBlockMake(BlockMakeData *data, v3s16 blockpos);
MapBlock *finishBlockMake(BlockMakeData *data,
- core::map<v3s16, MapBlock*> &changed_blocks);
-
- // A non-threaded wrapper to the above - DEFUNCT
-/* MapBlock * generateBlock(
- v3s16 p,
- core::map<v3s16, MapBlock*> &modified_blocks
- );*/
+ std::map<v3s16, MapBlock*> &changed_blocks);
/*
Get a block from somewhere.
@@ -444,9 +434,7 @@ public:
void save(ModifiedState save_level);
//void loadAll();
-
- void listAllLoadableBlocks(core::list<v3s16> &dst);
-
+ void listAllLoadableBlocks(std::list<v3s16> &dst);
// Saves map seed and possibly other stuff
void saveMapMeta();
void loadMapMeta();
@@ -538,15 +526,15 @@ public:
virtual void emerge(VoxelArea a, s32 caller_id=-1);
- void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
-
+ void blitBack(std::map<v3s16, MapBlock*> & modified_blocks);
+
+protected:
+ Map *m_map;
/*
key = blockpos
value = flags describing the block
*/
- core::map<v3s16, u8> m_loaded_blocks;
-protected:
- Map *m_map;
+ std::map<v3s16, u8> m_loaded_blocks;
};
class ManualMapVoxelManipulator : public MapVoxelManipulator
@@ -563,7 +551,7 @@ public:
void initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max);
// This is much faster with big chunks of generated data
- void blitBackAll(core::map<v3s16, MapBlock*> * modified_blocks);
+ void blitBackAll(std::map<v3s16, MapBlock*> * modified_blocks);
protected:
bool m_create_area;
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index a6e9b3951..dd95ab77f 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -168,7 +168,7 @@ MapNode MapBlock::getNodeParentNoEx(v3s16 p)
if black_air_left!=NULL, it is set to true if non-sunlighted
air is left in block.
*/
-bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
+bool MapBlock::propagateSunlight(std::set<v3s16> & light_sources,
bool remove_light, bool *black_air_left)
{
INodeDefManager *nodemgr = m_gamedef->ndef();
@@ -287,7 +287,7 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
if(diminish_light(current_light) != 0)
{
- light_sources.insert(pos_relative + pos, true);
+ light_sources.insert(pos_relative + pos);
}
if(current_light == 0 && stopped_to_solid_object)
diff --git a/src/mapblock.h b/src/mapblock.h
index 692b54318..05bb944a6 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <jmutex.h>
#include <jmutexautolock.h>
#include <exception>
+#include <set>
#include "debug.h"
#include "irrlichttypes.h"
#include "irr_v3d.h"
@@ -352,7 +353,7 @@ public:
}
// See comments in mapblock.cpp
- bool propagateSunlight(core::map<v3s16, bool> & light_sources,
+ bool propagateSunlight(std::set<v3s16> & light_sources,
bool remove_light=false, bool *black_air_left=NULL);
// Copies data to VoxelManipulator to getPosRelative()
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index f4d57922a..f68a79e41 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -445,7 +445,7 @@ struct FastFace
};
static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
- v3f p, v3s16 dir, v3f scale, u8 light_source, core::array<FastFace> &dest)
+ v3f p, v3s16 dir, v3f scale, u8 light_source, std::vector<FastFace> &dest)
{
FastFace face;
@@ -455,6 +455,80 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
v3f vertex_pos[4];
v3s16 vertex_dirs[4];
getNodeVertexDirs(dir, vertex_dirs);
+ v3s16 t;
+ switch (tile.rotation)
+ {
+ case 0:
+ break;
+ case 1: //R90
+ t = vertex_dirs[0];
+ vertex_dirs[0] = vertex_dirs[3];
+ vertex_dirs[3] = vertex_dirs[2];
+ vertex_dirs[2] = vertex_dirs[1];
+ vertex_dirs[1] = t;
+ break;
+ case 2: //R180
+ t = vertex_dirs[0];
+ vertex_dirs[0] = vertex_dirs[2];
+ vertex_dirs[2] = t;
+ t = vertex_dirs[1];
+ vertex_dirs[1] = vertex_dirs[3];
+ vertex_dirs[3] = t;
+ break;
+ case 3: //R270
+ t = vertex_dirs[0];
+ vertex_dirs[0] = vertex_dirs[1];
+ vertex_dirs[1] = vertex_dirs[2];
+ vertex_dirs[2] = vertex_dirs[3];
+ vertex_dirs[3] = t;
+ break;
+ case 4: //FXR90
+ t = vertex_dirs[0];
+ vertex_dirs[0] = vertex_dirs[3];
+ vertex_dirs[3] = vertex_dirs[2];
+ vertex_dirs[2] = vertex_dirs[1];
+ vertex_dirs[1] = t;
+ tile.texture.pos.Y += tile.texture.size.Y;
+ tile.texture.size.Y *= -1;
+ break;
+ case 5: //FXR270
+ t = vertex_dirs[0];
+ vertex_dirs[0] = vertex_dirs[1];
+ vertex_dirs[1] = vertex_dirs[2];
+ vertex_dirs[2] = vertex_dirs[3];
+ vertex_dirs[3] = t;
+ tile.texture.pos.Y += tile.texture.size.Y;
+ tile.texture.size.Y *= -1;
+ break;
+ case 6: //FYR90
+ t = vertex_dirs[0];
+ vertex_dirs[0] = vertex_dirs[3];
+ vertex_dirs[3] = vertex_dirs[2];
+ vertex_dirs[2] = vertex_dirs[1];
+ vertex_dirs[1] = t;
+ tile.texture.pos.X += tile.texture.size.X;
+ tile.texture.size.X *= -1;
+ break;
+ case 7: //FYR270
+ t = vertex_dirs[0];
+ vertex_dirs[0] = vertex_dirs[1];
+ vertex_dirs[1] = vertex_dirs[2];
+ vertex_dirs[2] = vertex_dirs[3];
+ vertex_dirs[3] = t;
+ tile.texture.pos.X += tile.texture.size.X;
+ tile.texture.size.X *= -1;
+ break;
+ case 8: //FX
+ tile.texture.pos.Y += tile.texture.size.Y;
+ tile.texture.size.Y *= -1;
+ break;
+ case 9: //FY
+ tile.texture.pos.X += tile.texture.size.X;
+ tile.texture.size.X *= -1;
+ break;
+ default:
+ break;
+ }
for(u16 i=0; i<4; i++)
{
vertex_pos[i] = v3f(
@@ -601,60 +675,50 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
// 5 = (0,0,-1)
// 6 = (0,-1,0)
// 7 = (-1,0,0)
- u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
+ u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
// Get rotation for things like chests
u8 facedir = mn.getFaceDir(ndef);
- assert(facedir <= 3);
-
- static const u8 dir_to_tile[4 * 8] =
+ assert(facedir <= 23);
+ static const u16 dir_to_tile[24 * 16] =
{
- // 0 +X +Y +Z 0 -Z -Y -X
- 0, 2, 0, 4, 0, 5, 1, 3, // facedir = 0
- 0, 4, 0, 3, 0, 2, 1, 5, // facedir = 1
- 0, 3, 0, 5, 0, 4, 1, 2, // facedir = 2
- 0, 5, 0, 2, 0, 3, 1, 4, // facedir = 3
+ // 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
+ 0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
+ 0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
+ 0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
+ 0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
+
+ 0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
+ 0,0, 4,3 , 2,0 , 0,3 , 0,0, 1,1 , 3,2 , 5,1 ,
+ 0,0, 3,3 , 4,0 , 0,0 , 0,0, 1,2 , 5,2 , 2,1 ,
+ 0,0, 5,3 , 3,0 , 0,1 , 0,0, 1,3 , 2,2 , 4,1 ,
+
+ 0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
+ 0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
+ 0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
+ 0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
+
+ 0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
+ 0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
+ 0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
+ 0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
+
+ 0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
+ 0,0, 1,2 , 4,1 , 3,3 , 0,0, 2,1 , 5,1 , 0,0 ,
+ 0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
+ 0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
+
+ 0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
+ 0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
+ 0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
+ 0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
+
};
- u8 tileindex = dir_to_tile[facedir*8 + dir_i];
-
- // If not rotated or is side tile, we're done
- if(facedir == 0 || (tileindex != 0 && tileindex != 1))
- return getNodeTileN(mn, p, tileindex, data);
-
- // This is the top or bottom tile, and it shall be rotated; thus rotate it
- TileSpec spec = getNodeTileN(mn, p, tileindex, data);
- if(tileindex == 0){
- if(facedir == 1){ // -90
- std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
- name += "^[transformR270";
- spec.texture = data->m_gamedef->tsrc()->getTexture(name);
- }
- else if(facedir == 2){ // 180
- spec.texture.pos += spec.texture.size;
- spec.texture.size *= -1;
- }
- else if(facedir == 3){ // 90
- std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
- name += "^[transformR90";
- spec.texture = data->m_gamedef->tsrc()->getTexture(name);
- }
- }
- else if(tileindex == 1){
- if(facedir == 1){ // -90
- std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
- name += "^[transformR90";
- spec.texture = data->m_gamedef->tsrc()->getTexture(name);
- }
- else if(facedir == 2){ // 180
- spec.texture.pos += spec.texture.size;
- spec.texture.size *= -1;
- }
- else if(facedir == 3){ // 90
- std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
- name += "^[transformR270";
- spec.texture = data->m_gamedef->tsrc()->getTexture(name);
- }
- }
+ u16 tile_index=facedir*16 + dir_i;
+ TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
+ spec.rotation=dir_to_tile[tile_index + 1];
+ std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
+ spec.texture = data->m_gamedef->tsrc()->getTexture(name);
return spec;
}
@@ -745,7 +809,7 @@ static void updateFastFaceRow(
v3f translate_dir_f,
v3s16 face_dir,
v3f face_dir_f,
- core::array<FastFace> &dest)
+ std::vector<FastFace> &dest)
{
v3s16 p = startpos;
@@ -794,6 +858,7 @@ static void updateFastFaceRow(
&& next_lights[2] == lights[2]
&& next_lights[3] == lights[3]
&& next_tile == tile
+ && tile.rotation == 0
&& next_light_source == light_source)
{
next_is_different = false;
@@ -897,7 +962,7 @@ static void updateFastFaceRow(
}
static void updateAllFastFaceRows(MeshMakeData *data,
- core::array<FastFace> &dest)
+ std::vector<FastFace> &dest)
{
/*
Go through every y,z and get top(y+) faces in rows of x+
@@ -962,7 +1027,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
// 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
//TimeTaker timer1("MapBlockMesh()");
- core::array<FastFace> fastfaces_new;
+ std::vector<FastFace> fastfaces_new;
/*
We are including the faces of the trailing edges of the block.
@@ -1124,8 +1189,8 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
m_mesh->addMeshBuffer(buf);
// Mesh grabbed it
buf->drop();
- buf->append(p.vertices.pointer(), p.vertices.size(),
- p.indices.pointer(), p.indices.size());
+ buf->append(&p.vertices[0], p.vertices.size(),
+ &p.indices[0], p.indices.size());
}
/*
diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h
index 5b33990c6..c75984021 100644
--- a/src/mapblock_mesh.h
+++ b/src/mapblock_mesh.h
@@ -143,13 +143,13 @@ private:
struct PreMeshBuffer
{
TileSpec tile;
- core::array<u16> indices;
- core::array<video::S3DVertex> vertices;
+ std::vector<u16> indices;
+ std::vector<video::S3DVertex> vertices;
};
struct MeshCollector
{
- core::array<PreMeshBuffer> prebuffers;
+ std::vector<PreMeshBuffer> prebuffers;
void append(const TileSpec &material,
const video::S3DVertex *vertices, u32 numVertices,
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index ef5da6bf1..b5deaae52 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -39,914 +39,366 @@ FlagDesc flagdesc_mapgen[] = {
{"trees", MG_TREES},
{"caves", MG_CAVES},
{"dungeons", MG_DUNGEONS},
- {"v6_forests", MGV6_FORESTS},
+ {"v6_jungles", MGV6_JUNGLES},
{"v6_biome_blend", MGV6_BIOME_BLEND},
{"flat", MG_FLAT},
{NULL, 0}
};
-///////////////////////////////////////////////////////////////////////////////
-
-/////////////////////
-
-bool MapgenV6Params::readParams(Settings *settings) {
- freq_desert = settings->getFloat("mgv6_freq_desert");
- freq_beach = settings->getFloat("mgv6_freq_beach");
-
- np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base");
- np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
- np_steepness = settings->getNoiseParams("mgv6_np_steepness");
- np_height_select = settings->getNoiseParams("mgv6_np_height_select");
- np_trees = settings->getNoiseParams("mgv6_np_trees");
- np_mud = settings->getNoiseParams("mgv6_np_mud");
- np_beach = settings->getNoiseParams("mgv6_np_beach");
- np_biome = settings->getNoiseParams("mgv6_np_biome");
- np_cave = settings->getNoiseParams("mgv6_np_cave");
-
- bool success =
- np_terrain_base && np_terrain_higher && np_steepness &&
- np_height_select && np_trees && np_mud &&
- np_beach && np_biome && np_cave;
- return success;
-}
-
-
-void MapgenV6Params::writeParams(Settings *settings) {
- settings->setFloat("mgv6_freq_desert", freq_desert);
- settings->setFloat("mgv6_freq_beach", freq_beach);
-
- settings->setNoiseParams("mgv6_np_terrain_base", np_terrain_base);
- settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
- settings->setNoiseParams("mgv6_np_steepness", np_steepness);
- settings->setNoiseParams("mgv6_np_height_select", np_height_select);
- settings->setNoiseParams("mgv6_np_trees", np_trees);
- settings->setNoiseParams("mgv6_np_mud", np_mud);
- settings->setNoiseParams("mgv6_np_beach", np_beach);
- settings->setNoiseParams("mgv6_np_biome", np_biome);
- settings->setNoiseParams("mgv6_np_cave", np_cave);
-}
-
-
-/////////////////////////////////// legacy static functions for farmesh
-
-
-s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
- //just need to return something
- s16 level = 5;
- return level;
-}
-
-
-bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
- double sandnoise = noise2d_perlin(
- 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
- seed+59420, 3, 0.50);
-
- return (sandnoise > 0.15);
-}
-
-
-double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
- double noise = noise2d_perlin(
- 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
- seed+2, 4, 0.66);
- double zeroval = -0.39;
- if(noise < zeroval)
- return 0;
- else
- return 0.04 * (noise-zeroval) / (1.0-zeroval);
-}
-
-
-#if 0 /// BIG COMMENT
-namespace mapgen
-{
-
-/*
- Some helper functions for the map generator
-*/
-
-#if 1
-// Returns Y one under area minimum if not found
-static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
- INodeDefManager *ndef)
-{
- v3s16 em = vmanip.m_area.getExtent();
- s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
- s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
- s16 y;
- for(y=y_nodes_max; y>=y_nodes_min; y--)
- {
- MapNode &n = vmanip.m_data[i];
- if(ndef->get(n).walkable)
- break;
-
- vmanip.m_area.add_y(em, i, -1);
- }
- if(y >= y_nodes_min)
- return y;
- else
- return y_nodes_min - 1;
-}
-
-#if 0
-// Returns Y one under area minimum if not found
-static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
- INodeDefManager *ndef)
-{
- if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
- return vmanip.m_area.MinEdge.Y-1;
- v3s16 em = vmanip.m_area.getExtent();
- s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
- s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
- s16 y;
- content_t c_tree = ndef->getId("mapgen_tree");
- content_t c_leaves = ndef->getId("mapgen_leaves");
- for(y=y_nodes_max; y>=y_nodes_min; y--)
- {
- MapNode &n = vmanip.m_data[i];
- if(ndef->get(n).walkable
- && n.getContent() != c_tree
- && n.getContent() != c_leaves)
- break;
- vmanip.m_area.add_y(em, i, -1);
- }
- if(y >= y_nodes_min)
- return y;
- else
- return y_nodes_min - 1;
-}
-#endif
-
-// Returns Y one under area minimum if not found
-static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
- INodeDefManager *ndef)
-{
- v3s16 em = vmanip.m_area.getExtent();
- s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
- s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
- s16 y;
- content_t c_stone = ndef->getId("mapgen_stone");
- content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
- for(y=y_nodes_max; y>=y_nodes_min; y--)
- {
- MapNode &n = vmanip.m_data[i];
- content_t c = n.getContent();
- if(c != CONTENT_IGNORE && (
- c == c_stone || c == c_desert_stone))
- break;
-
- vmanip.m_area.add_y(em, i, -1);
- }
- if(y >= y_nodes_min)
- return y;
- else
- return y_nodes_min - 1;
-}
-#endif
-
-
-#if 0
-
-static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
- INodeDefManager *ndef)
-{
- MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
-
- s16 trunk_h = myrand_range(2, 3);
- v3s16 p1 = p0;
- for(s16 ii=0; ii<trunk_h; ii++)
- {
- if(vmanip.m_area.contains(p1))
- vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
- p1.Y++;
- }
-}
+///////////////////////////////////////////////////////////////////////////////
-static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
- INodeDefManager *ndef)
-{
- MapNode cactusnode(ndef->getId("mapgen_cactus"));
- s16 trunk_h = 3;
- v3s16 p1 = p0;
- for(s16 ii=0; ii<trunk_h; ii++)
- {
- if(vmanip.m_area.contains(p1))
- vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
- p1.Y++;
+Ore *createOre(OreType type) {
+ switch (type) {
+ case ORE_SCATTER:
+ return new OreScatter;
+ case ORE_SHEET:
+ return new OreSheet;
+ //case ORE_CLAYLIKE: //TODO: implement this!
+ // return new OreClaylike;
+ default:
+ return NULL;
}
}
-#endif
-#if 0
-/*
- Dungeon making routines
-*/
-
-#define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
-#define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
-#define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
- VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
-
-static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
- INodeDefManager *ndef)
-{
- // Make +-X walls
- for(s16 z=0; z<roomsize.Z; z++)
- for(s16 y=0; y<roomsize.Y; y++)
- {
- {
- v3s16 p = roomplace + v3s16(0,y,z);
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
- continue;
- vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
- }
- {
- v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
- continue;
- vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
- }
- }
- // Make +-Z walls
- for(s16 x=0; x<roomsize.X; x++)
- for(s16 y=0; y<roomsize.Y; y++)
- {
- {
- v3s16 p = roomplace + v3s16(x,y,0);
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
- continue;
- vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
- }
- {
- v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
- continue;
- vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
+void Ore::resolveNodeNames(INodeDefManager *ndef) {
+ if (ore == CONTENT_IGNORE) {
+ ore = ndef->getId(ore_name);
+ if (ore == CONTENT_IGNORE) {
+ errorstream << "Ore::resolveNodeNames: ore node '"
+ << ore_name << "' not defined";
+ ore = CONTENT_AIR;
+ wherein = CONTENT_AIR;
}
}
-
- // Make +-Y walls (floor and ceiling)
- for(s16 z=0; z<roomsize.Z; z++)
- for(s16 x=0; x<roomsize.X; x++)
- {
- {
- v3s16 p = roomplace + v3s16(x,0,z);
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
- continue;
- vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
- }
- {
- v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
- continue;
- vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
+
+ if (wherein == CONTENT_IGNORE) {
+ wherein = ndef->getId(wherein_name);
+ if (wherein == CONTENT_IGNORE) {
+ errorstream << "Ore::resolveNodeNames: wherein node '"
+ << wherein_name << "' not defined";
+ ore = CONTENT_AIR;
+ wherein = CONTENT_AIR;
}
}
-
- // Fill with air
- for(s16 z=1; z<roomsize.Z-1; z++)
- for(s16 y=1; y<roomsize.Y-1; y++)
- for(s16 x=1; x<roomsize.X-1; x++)
- {
- v3s16 p = roomplace + v3s16(x,y,z);
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
- vmanip.m_data[vi] = MapNode(CONTENT_AIR);
- }
}
-static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
- u8 avoid_flags, MapNode n, u8 or_flags)
-{
- for(s16 z=0; z<size.Z; z++)
- for(s16 y=0; y<size.Y; y++)
- for(s16 x=0; x<size.X; x++)
- {
- v3s16 p = place + v3s16(x,y,z);
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_flags[vi] & avoid_flags)
+
+void OreScatter::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
+ if (nmin.Y > height_max || nmax.Y < height_min)
+ return;
+
+ resolveNodeNames(mg->ndef);
+
+ MapNode n_ore(ore);
+ ManualMapVoxelManipulator *vm = mg->vm;
+ PseudoRandom pr(blockseed);
+
+ int ymin = MYMAX(nmin.Y, height_min);
+ int ymax = MYMIN(nmax.Y, height_max);
+ if (clust_size >= ymax - ymin + 1)
+ return;
+
+ int volume = (nmax.X - nmin.X + 1) *
+ (nmax.Y - nmin.Y + 1) *
+ (nmax.Z - nmin.Z + 1);
+ int csize = clust_size;
+ int orechance = (csize * csize * csize) / clust_num_ores;
+ int nclusters = volume / clust_scarcity;
+
+ for (int i = 0; i != nclusters; i++) {
+ int x0 = pr.range(nmin.X, nmax.X - csize + 1);
+ int y0 = pr.range(ymin, ymax - csize + 1);
+ int z0 = pr.range(nmin.Z, nmax.Z - csize + 1);
+
+ if (np && (NoisePerlin3D(np, x0, y0, z0, mg->seed) < nthresh))
continue;
- vmanip.m_flags[vi] |= or_flags;
- vmanip.m_data[vi] = n;
+
+ for (int z1 = 0; z1 != csize; z1++)
+ for (int y1 = 0; y1 != csize; y1++)
+ for (int x1 = 0; x1 != csize; x1++) {
+ if (pr.range(1, orechance) != 1)
+ continue;
+
+ u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
+ if (vm->m_data[i].getContent() == wherein)
+ vm->m_data[i] = n_ore;
+ }
}
}
-static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
- INodeDefManager *ndef)
-{
- make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
- VMANIP_FLAG_DUNGEON_INSIDE);
-}
-static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
- INodeDefManager *ndef)
-{
- make_hole1(vmanip, doorplace, ndef);
- // Place torch (for testing)
- //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
-}
+void OreSheet::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
+ if (nmin.Y > height_max || nmax.Y < height_min)
+ return;
-static v3s16 rand_ortho_dir(PseudoRandom &random)
-{
- if(random.next()%2==0)
- return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
- else
- return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
-}
+ resolveNodeNames(mg->ndef);
-static v3s16 turn_xz(v3s16 olddir, int t)
-{
- v3s16 dir;
- if(t == 0)
- {
- // Turn right
- dir.X = olddir.Z;
- dir.Z = -olddir.X;
- dir.Y = olddir.Y;
+ MapNode n_ore(ore);
+ ManualMapVoxelManipulator *vm = mg->vm;
+ PseudoRandom pr(blockseed + 4234);
+
+ int ymin = MYMAX(nmin.Y, height_min);
+ int ymax = MYMIN(nmax.Y, height_max);
+ if (clust_size >= ymax - ymin + 1)
+ return;
+
+ int x0 = nmin.X;
+ int z0 = nmin.Z;
+
+ int x1 = nmax.X;
+ int z1 = nmax.Z;
+
+ int max_height = clust_size;
+ int y_start = pr.range(ymin, ymax - max_height);
+
+ if (!noise) {
+ int sx = nmax.X - nmin.X + 1;
+ int sz = nmax.Z - nmin.Z + 1;
+ noise = new Noise(np, 0, sx, sz);
}
- else
- {
- // Turn left
- dir.X = -olddir.Z;
- dir.Z = olddir.X;
- dir.Y = olddir.Y;
+ noise->seed = mg->seed + y_start;
+ noise->perlinMap2D(x0, z0);
+
+ int index = 0;
+ for (int z = z0; z != z1; z++)
+ for (int x = x0; x != x1; x++) {
+ float noiseval = noise->result[index++];
+ if (noiseval < nthresh)
+ continue;
+
+ int height = max_height * (1. / pr.range(1, 3));
+ int y0 = y_start + np->scale * noiseval; //pr.range(1, 3) - 1;
+ int y1 = y0 + height;
+ for (int y = y0; y != y1; y++) {
+ u32 i = vm->m_area.index(x, y, z);
+ if (!vm->m_area.contains(i))
+ continue;
+
+ if (vm->m_data[i].getContent() == wherein)
+ vm->m_data[i] = n_ore;
+ }
}
- return dir;
}
-static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
-{
- int turn = random.range(0,2);
- v3s16 dir;
- if(turn == 0)
- {
- // Go straight
- dir = olddir;
- }
- else if(turn == 1)
- // Turn right
- dir = turn_xz(olddir, 0);
- else
- // Turn left
- dir = turn_xz(olddir, 1);
- return dir;
-}
-static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
- v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
- PseudoRandom &random, INodeDefManager *ndef)
-{
- make_hole1(vmanip, doorplace, ndef);
- v3s16 p0 = doorplace;
- v3s16 dir = doordir;
- u32 length;
- if(random.next()%2)
- length = random.range(1,13);
- else
- length = random.range(1,6);
- length = random.range(1,13);
- u32 partlength = random.range(1,13);
- u32 partcount = 0;
- s16 make_stairs = 0;
- if(random.next()%2 == 0 && partlength >= 3)
- make_stairs = random.next()%2 ? 1 : -1;
- for(u32 i=0; i<length; i++)
- {
- v3s16 p = p0 + dir;
- if(partcount != 0)
- p.Y += make_stairs;
+void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax) {
+ bool isliquid, wasliquid;
+ v3s16 em = vm->m_area.getExtent();
- /*// If already empty
- if(vmanip.getNodeNoExNoEmerge(p).getContent()
- == CONTENT_AIR
- && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
- == CONTENT_AIR)
- {
- }*/
+ for (s16 z = nmin.Z; z <= nmax.Z; z++) {
+ for (s16 x = nmin.X; x <= nmax.X; x++) {
+ wasliquid = true;
+
+ u32 i = vm->m_area.index(x, nmax.Y, z);
+ for (s16 y = nmax.Y; y >= nmin.Y; y--) {
+ isliquid = ndef->get(vm->m_data[i]).isLiquid();
+
+ // there was a change between liquid and nonliquid, add to queue
+ if (isliquid != wasliquid)
+ trans_liquid->push_back(v3s16(x, y, z));
- if(vmanip.m_area.contains(p) == true
- && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
- {
- if(make_stairs)
- {
- make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
- VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
- make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
- VMANIP_FLAG_DUNGEON_INSIDE);
- make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
- VMANIP_FLAG_DUNGEON_INSIDE);
+ wasliquid = isliquid;
+ vm->m_area.add_y(em, i, -1);
}
- else
- {
- make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
- VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
- make_hole1(vmanip, p, ndef);
- /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
- VMANIP_FLAG_DUNGEON_INSIDE);*/
- }
-
- p0 = p;
- }
- else
- {
- // Can't go here, turn away
- dir = turn_xz(dir, random.range(0,1));
- make_stairs = -make_stairs;
- partcount = 0;
- partlength = random.range(1,length);
- continue;
- }
-
- partcount++;
- if(partcount >= partlength)
- {
- partcount = 0;
-
- dir = random_turn(random, dir);
-
- partlength = random.range(1,length);
-
- make_stairs = 0;
- if(random.next()%2 == 0 && partlength >= 3)
- make_stairs = random.next()%2 ? 1 : -1;
}
}
- result_place = p0;
- result_dir = dir;
}
-class RoomWalker
-{
-public:
- RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
- INodeDefManager *ndef):
- vmanip(vmanip_),
- m_pos(pos),
- m_random(random),
- m_ndef(ndef)
- {
- randomizeDir();
- }
+void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light) {
+ ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
+ VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
+ nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
- void randomizeDir()
- {
- m_dir = rand_ortho_dir(m_random);
+ for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
+ for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
+ u32 i = vm->m_area.index(a.MinEdge.X, y, z);
+ for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++)
+ vm->m_data[i].param1 = light;
+ }
}
+}
- void setPos(v3s16 pos)
- {
- m_pos = pos;
- }
- void setDir(v3s16 dir)
- {
- m_dir = dir;
- }
+void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) {
+ if (light <= 1 || !a.contains(p))
+ return;
+
+ u32 vi = vm->m_area.index(p);
+ MapNode &nn = vm->m_data[vi];
- bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
- {
- for(u32 i=0; i<100; i++)
- {
- v3s16 p = m_pos + m_dir;
- v3s16 p1 = p + v3s16(0,1,0);
- if(vmanip.m_area.contains(p) == false
- || vmanip.m_area.contains(p1) == false
- || i % 4 == 0)
- {
- randomizeDir();
- continue;
- }
- if(vmanip.getNodeNoExNoEmerge(p).getContent()
- == m_ndef->getId("mapgen_cobble")
- && vmanip.getNodeNoExNoEmerge(p1).getContent()
- == m_ndef->getId("mapgen_cobble"))
- {
- // Found wall, this is a good place!
- result_place = p;
- result_dir = m_dir;
- // Randomize next direction
- randomizeDir();
- return true;
- }
- /*
- Determine where to move next
- */
- // Jump one up if the actual space is there
- if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
- == m_ndef->getId("mapgen_cobble")
- && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
- == CONTENT_AIR
- && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
- == CONTENT_AIR)
- p += v3s16(0,1,0);
- // Jump one down if the actual space is there
- if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
- == m_ndef->getId("mapgen_cobble")
- && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
- == CONTENT_AIR
- && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
- == CONTENT_AIR)
- p += v3s16(0,-1,0);
- // Check if walking is now possible
- if(vmanip.getNodeNoExNoEmerge(p).getContent()
- != CONTENT_AIR
- || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
- != CONTENT_AIR)
- {
- // Cannot continue walking here
- randomizeDir();
+ light--;
+ // should probably compare masked, but doesn't seem to make a difference
+ if (light <= nn.param1 || !ndef->get(nn).light_propagates)
+ return;
+
+ nn.param1 = light;
+
+ lightSpread(a, p + v3s16(0, 0, 1), light);
+ lightSpread(a, p + v3s16(0, 1, 0), light);
+ lightSpread(a, p + v3s16(1, 0, 0), light);
+ lightSpread(a, p - v3s16(0, 0, 1), light);
+ lightSpread(a, p - v3s16(0, 1, 0), light);
+ lightSpread(a, p - v3s16(1, 0, 0), light);
+}
+
+
+void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) {
+ VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
+ nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
+ bool block_is_underground = (water_level >= nmax.Y);
+
+ ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
+ //TimeTaker t("updateLighting");
+
+ // first, send vertical rays of sunshine downward
+ v3s16 em = vm->m_area.getExtent();
+ for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
+ for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) {
+ // see if we can get a light value from the overtop
+ u32 i = vm->m_area.index(x, a.MaxEdge.Y + 1, z);
+ if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
+ if (block_is_underground)
+ continue;
+ } else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN) {
continue;
}
- // Move there
- m_pos = p;
- }
- return false;
- }
-
- bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
- v3s16 &result_doordir, v3s16 &result_roomplace)
- {
- for(s16 trycount=0; trycount<30; trycount++)
- {
- v3s16 doorplace;
- v3s16 doordir;
- bool r = findPlaceForDoor(doorplace, doordir);
- if(r == false)
- continue;
- v3s16 roomplace;
- // X east, Z north, Y up
-#if 1
- if(doordir == v3s16(1,0,0)) // X+
- roomplace = doorplace +
- v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
- if(doordir == v3s16(-1,0,0)) // X-
- roomplace = doorplace +
- v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
- if(doordir == v3s16(0,0,1)) // Z+
- roomplace = doorplace +
- v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
- if(doordir == v3s16(0,0,-1)) // Z-
- roomplace = doorplace +
- v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
-#endif
-#if 0
- if(doordir == v3s16(1,0,0)) // X+
- roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
- if(doordir == v3s16(-1,0,0)) // X-
- roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
- if(doordir == v3s16(0,0,1)) // Z+
- roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
- if(doordir == v3s16(0,0,-1)) // Z-
- roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
-#endif
+ vm->m_area.add_y(em, i, -1);
- // Check fit
- bool fits = true;
- for(s16 z=1; z<roomsize.Z-1; z++)
- for(s16 y=1; y<roomsize.Y-1; y++)
- for(s16 x=1; x<roomsize.X-1; x++)
- {
- v3s16 p = roomplace + v3s16(x,y,z);
- if(vmanip.m_area.contains(p) == false)
- {
- fits = false;
- break;
- }
- if(vmanip.m_flags[vmanip.m_area.index(p)]
- & VMANIP_FLAG_DUNGEON_INSIDE)
- {
- fits = false;
+ for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) {
+ MapNode &n = vm->m_data[i];
+ if (!ndef->get(n).sunlight_propagates)
break;
- }
- }
- if(fits == false)
- {
- // Find new place
- continue;
+ n.param1 = LIGHT_SUN;
+ vm->m_area.add_y(em, i, -1);
}
- result_doorplace = doorplace;
- result_doordir = doordir;
- result_roomplace = roomplace;
- return true;
}
- return false;
}
-
-private:
- VoxelManipulator &vmanip;
- v3s16 m_pos;
- v3s16 m_dir;
- PseudoRandom &m_random;
- INodeDefManager *m_ndef;
-};
-
-static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
- INodeDefManager *ndef)
-{
- v3s16 areasize = vmanip.m_area.getExtent();
- v3s16 roomsize;
- v3s16 roomplace;
-
- /*
- Find place for first room
- */
- bool fits = false;
- for(u32 i=0; i<100; i++)
- {
- roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
- roomplace = vmanip.m_area.MinEdge + v3s16(
- random.range(0,areasize.X-roomsize.X-1),
- random.range(0,areasize.Y-roomsize.Y-1),
- random.range(0,areasize.Z-roomsize.Z-1));
- /*
- Check that we're not putting the room to an unknown place,
- otherwise it might end up floating in the air
- */
- fits = true;
- for(s16 z=1; z<roomsize.Z-1; z++)
- for(s16 y=1; y<roomsize.Y-1; y++)
- for(s16 x=1; x<roomsize.X-1; x++)
- {
- v3s16 p = roomplace + v3s16(x,y,z);
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
- {
- fits = false;
- break;
- }
- if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
- {
- fits = false;
- break;
+
+ // now spread the sunlight and light up any sources
+ for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
+ for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
+ u32 i = vm->m_area.index(a.MinEdge.X, y, z);
+ for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++) {
+ MapNode &n = vm->m_data[i];
+ if (n.getContent() == CONTENT_IGNORE ||
+ !ndef->get(n).light_propagates)
+ continue;
+
+ u8 light_produced = ndef->get(n).light_source & 0x0F;
+ if (light_produced)
+ n.param1 = light_produced;
+
+ u8 light = n.param1 & 0x0F;
+ if (light) {
+ lightSpread(a, v3s16(x, y, z + 1), light);
+ lightSpread(a, v3s16(x, y + 1, z ), light);
+ lightSpread(a, v3s16(x + 1, y, z ), light);
+ lightSpread(a, v3s16(x, y, z - 1), light);
+ lightSpread(a, v3s16(x, y - 1, z ), light);
+ lightSpread(a, v3s16(x - 1, y, z ), light);
+ }
}
}
- if(fits)
- break;
}
- // No place found
- if(fits == false)
- return;
-
- /*
- Stores the center position of the last room made, so that
- a new corridor can be started from the last room instead of
- the new room, if chosen so.
- */
- v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
-
- u32 room_count = random.range(2,7);
- for(u32 i=0; i<room_count; i++)
- {
- // Make a room to the determined place
- make_room1(vmanip, roomsize, roomplace, ndef);
-
- v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
-
- // Place torch at room center (for testing)
- //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
-
- // Quit if last room
- if(i == room_count-1)
- break;
-
- // Determine walker start position
-
- bool start_in_last_room = (random.range(0,2)!=0);
- //bool start_in_last_room = true;
-
- v3s16 walker_start_place;
-
- if(start_in_last_room)
- {
- walker_start_place = last_room_center;
- }
- else
- {
- walker_start_place = room_center;
- // Store center of current room as the last one
- last_room_center = room_center;
- }
+
+ //printf("updateLighting: %dms\n", t.stop());
+}
- // Create walker and find a place for a door
- RoomWalker walker(vmanip, walker_start_place, random, ndef);
- v3s16 doorplace;
- v3s16 doordir;
- bool r = walker.findPlaceForDoor(doorplace, doordir);
- if(r == false)
- return;
- if(random.range(0,1)==0)
- // Make the door
- make_door1(vmanip, doorplace, doordir, ndef);
- else
- // Don't actually make a door
- doorplace -= doordir;
+void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) {
+ enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
- // Make a random corridor starting from the door
- v3s16 corridor_end;
- v3s16 corridor_end_dir;
- make_corridor(vmanip, doorplace, doordir, corridor_end,
- corridor_end_dir, random, ndef);
+ VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
+ nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
+ bool block_is_underground = (water_level > nmax.Y);
+ bool sunlight = !block_is_underground;
- // Find a place for a random sized room
- roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
- walker.setPos(corridor_end);
- walker.setDir(corridor_end_dir);
- r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
- if(r == false)
- return;
+ ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
+
+ for (int i = 0; i < 2; i++) {
+ enum LightBank bank = banks[i];
+ std::set<v3s16> light_sources;
+ std::map<v3s16, u8> unlight_from;
- if(random.range(0,1)==0)
- // Make the door
- make_door1(vmanip, doorplace, doordir, ndef);
- else
- // Don't actually make a door
- roomplace -= doordir;
+ voxalgo::clearLightAndCollectSources(*vm, a, bank, ndef,
+ light_sources, unlight_from);
+ voxalgo::propagateSunlight(*vm, a, sunlight, light_sources, ndef);
+ vm->unspreadLight(bank, unlight_from, light_sources, ndef);
+ vm->spreadLight(bank, light_sources, ndef);
}
}
-#endif
-#if 0
-static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
- INodeDefManager *ndef)
-{
- v3s16 dir;
- u8 facedir_i = 0;
- s32 r = random.range(0, 3);
- if(r == 0){
- dir = v3s16( 1, 0, 0);
- facedir_i = 3;
- }
- if(r == 1){
- dir = v3s16(-1, 0, 0);
- facedir_i = 1;
- }
- if(r == 2){
- dir = v3s16( 0, 0, 1);
- facedir_i = 2;
- }
- if(r == 3){
- dir = v3s16( 0, 0,-1);
- facedir_i = 0;
- }
- v3s16 p = vmanip.m_area.MinEdge + v3s16(
- 16+random.range(0,15),
- 16+random.range(0,15),
- 16+random.range(0,15));
- vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
- u32 length = random.range(3,15);
- for(u32 j=0; j<length; j++)
- {
- p -= dir;
- vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
- }
-}
-#endif
-/*
- Noise functions. Make sure seed is mangled differently in each one.
-*/
+//////////////////////// Mapgen V6 parameter read/write
-#if 0
-/*
- Scaling the output of the noise function affects the overdrive of the
- contour function, which affects the shape of the output considerably.
-*/
-#define CAVE_NOISE_SCALE 12.0
-//#define CAVE_NOISE_SCALE 10.0
-//#define CAVE_NOISE_SCALE 7.5
-//#define CAVE_NOISE_SCALE 5.0
-//#define CAVE_NOISE_SCALE 1.0
+bool MapgenV6Params::readParams(Settings *settings) {
+ freq_desert = settings->getFloat("mgv6_freq_desert");
+ freq_beach = settings->getFloat("mgv6_freq_beach");
-//#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
-#define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
+ np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base");
+ np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
+ np_steepness = settings->getNoiseParams("mgv6_np_steepness");
+ np_height_select = settings->getNoiseParams("mgv6_np_height_select");
+ np_mud = settings->getNoiseParams("mgv6_np_mud");
+ np_beach = settings->getNoiseParams("mgv6_np_beach");
+ np_biome = settings->getNoiseParams("mgv6_np_biome");
+ np_cave = settings->getNoiseParams("mgv6_np_cave");
+ np_humidity = settings->getNoiseParams("mgv6_np_humidity");
+ np_trees = settings->getNoiseParams("mgv6_np_trees");
+ np_apple_trees = settings->getNoiseParams("mgv6_np_apple_trees");
-NoiseParams get_cave_noise1_params(u64 seed)
-{
- /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
- 200, CAVE_NOISE_SCALE);*/
- /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
- 100, CAVE_NOISE_SCALE);*/
- /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
- 100, CAVE_NOISE_SCALE);*/
- /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
- 100, CAVE_NOISE_SCALE);*/
- return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
- 50, CAVE_NOISE_SCALE);
- //return NoiseParams(NOISE_CONSTANT_ONE);
+ bool success =
+ np_terrain_base && np_terrain_higher && np_steepness &&
+ np_height_select && np_trees && np_mud &&
+ np_beach && np_biome && np_cave &&
+ np_humidity && np_apple_trees;
+ return success;
}
-NoiseParams get_cave_noise2_params(u64 seed)
-{
- /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
- 200, CAVE_NOISE_SCALE);*/
- /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
- 100, CAVE_NOISE_SCALE);*/
- /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
- 100, CAVE_NOISE_SCALE);*/
- return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
- 50, CAVE_NOISE_SCALE);
- //return NoiseParams(NOISE_CONSTANT_ONE);
-}
-NoiseParams get_ground_noise1_params(u64 seed)
-{
- return NoiseParams(NOISE_PERLIN, seed+983240, 4,
- 0.55, 80.0, 40.0);
+void MapgenV6Params::writeParams(Settings *settings) {
+ settings->setFloat("mgv6_freq_desert", freq_desert);
+ settings->setFloat("mgv6_freq_beach", freq_beach);
+
+ settings->setNoiseParams("mgv6_np_terrain_base", np_terrain_base);
+ settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
+ settings->setNoiseParams("mgv6_np_steepness", np_steepness);
+ settings->setNoiseParams("mgv6_np_height_select", np_height_select);
+ settings->setNoiseParams("mgv6_np_mud", np_mud);
+ settings->setNoiseParams("mgv6_np_beach", np_beach);
+ settings->setNoiseParams("mgv6_np_biome", np_biome);
+ settings->setNoiseParams("mgv6_np_cave", np_cave);
+ settings->setNoiseParams("mgv6_np_humidity", np_humidity);
+ settings->setNoiseParams("mgv6_np_trees", np_trees);
+ settings->setNoiseParams("mgv6_np_apple_trees", np_apple_trees);
}
-NoiseParams get_ground_crumbleness_params(u64 seed)
-{
- return NoiseParams(NOISE_PERLIN, seed+34413, 3,
- 1.3, 20.0, 1.0);
-}
-NoiseParams get_ground_wetness_params(u64 seed)
-{
- return NoiseParams(NOISE_PERLIN, seed+32474, 4,
- 1.1, 40.0, 1.0);
-}
+/////////////////////////////////// legacy static functions for farmesh
+
-bool is_cave(u64 seed, v3s16 p)
-{
- double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
- double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
- return d1*d2 > CAVE_NOISE_THRESHOLD;
+s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
+ //just need to return something
+ s16 level = 5;
+ return level;
}
-/*
- Ground density noise shall be interpreted by using this.
- TODO: No perlin noises here, they should be outsourced
- and buffered
- NOTE: The speed of these actually isn't terrible
-*/
-bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
-{
- //return ((double)p.Y < ground_noise1_val);
+bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
+ double sandnoise = noise2d_perlin(
+ 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
+ seed+59420, 3, 0.50);
- double f = 0.55 + noise2d_perlin(
- 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
- seed+920381, 3, 0.45);
- if(f < 0.01)
- f = 0.01;
- else if(f >= 1.0)
- f *= 1.6;
- double h = WATER_LEVEL + 10 * noise2d_perlin(
- 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
- seed+84174, 4, 0.5);
- /*double f = 1;
- double h = 0;*/
- return ((double)p.Y - h < ground_noise1_val * f);
+ return (sandnoise > 0.15);
}
-/*
- Queries whether a position is ground or not.
-*/
-bool is_ground(u64 seed, v3s16 p)
-{
- double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
- return val_is_ground(val1, p, seed);
-}
-#endif
-// Amount of trees per area in nodes
-double tree_amount_2d(u64 seed, v2s16 p)
-{
- /*double noise = noise2d_perlin(
- 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
- seed+2, 5, 0.66);*/
+double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
double noise = noise2d_perlin(
0.5+(float)p.X/125, 0.5+(float)p.Y/125,
seed+2, 4, 0.66);
@@ -956,1895 +408,3 @@ double tree_amount_2d(u64 seed, v2s16 p)
else
return 0.04 * (noise-zeroval) / (1.0-zeroval);
}
-
-#if 0
-double surface_humidity_2d(u64 seed, v2s16 p)
-{
- double noise = noise2d_perlin(
- 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
- seed+72384, 4, 0.66);
- noise = (noise + 1.0)/2.0;
- if(noise < 0.0)
- noise = 0.0;
- if(noise > 1.0)
- noise = 1.0;
- return noise;
-}
-
-/*
- Incrementally find ground level from 3d noise
-*/
-s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
-{
- // Start a bit fuzzy to make averaging lower precision values
- // more useful
- s16 level = myrand_range(-precision/2, precision/2);
- s16 dec[] = {31000, 100, 20, 4, 1, 0};
- s16 i;
- for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
- {
- // First find non-ground by going upwards
- // Don't stop in caves.
- {
- s16 max = level+dec[i-1]*2;
- v3s16 p(p2d.X, level, p2d.Y);
- for(; p.Y < max; p.Y += dec[i])
- {
- if(!is_ground(seed, p))
- {
- level = p.Y;
- break;
- }
- }
- }
- // Then find ground by going downwards from there.
- // Go in caves, too, when precision is 1.
- {
- s16 min = level-dec[i-1]*2;
- v3s16 p(p2d.X, level, p2d.Y);
- for(; p.Y>min; p.Y-=dec[i])
- {
- bool ground = is_ground(seed, p);
- /*if(dec[i] == 1 && is_cave(seed, p))
- ground = false;*/
- if(ground)
- {
- level = p.Y;
- break;
- }
- }
- }
- }
-
- // This is more like the actual ground level
- level += dec[i-1]/2;
-
- return level;
-}
-
-double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
-
-double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
-{
- v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
- v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
- double a = 0;
- a += find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_min.Y), p);
- a += find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_max.Y), p);
- a += find_ground_level_from_noise(seed,
- v2s16(node_max.X, node_max.Y), p);
- a += find_ground_level_from_noise(seed,
- v2s16(node_max.X, node_min.Y), p);
- a += find_ground_level_from_noise(seed,
- v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
- a /= 5;
- return a;
-}
-
-double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
-
-double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
-{
- v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
- v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
- double a = -31000;
- // Corners
- a = MYMAX(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_min.Y), p));
- a = MYMAX(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_max.Y), p));
- a = MYMAX(a, find_ground_level_from_noise(seed,
- v2s16(node_max.X, node_max.Y), p));
- a = MYMAX(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_min.Y), p));
- // Center
- a = MYMAX(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
- // Side middle points
- a = MYMAX(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
- a = MYMAX(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
- a = MYMAX(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
- a = MYMAX(a, find_ground_level_from_noise(seed,
- v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
- return a;
-}
-
-double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
-
-double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
-{
- v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
- v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
- double a = 31000;
- // Corners
- a = MYMIN(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_min.Y), p));
- a = MYMIN(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_max.Y), p));
- a = MYMIN(a, find_ground_level_from_noise(seed,
- v2s16(node_max.X, node_max.Y), p));
- a = MYMIN(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_min.Y), p));
- // Center
- a = MYMIN(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
- // Side middle points
- a = MYMIN(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
- a = MYMIN(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
- a = MYMIN(a, find_ground_level_from_noise(seed,
- v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
- a = MYMIN(a, find_ground_level_from_noise(seed,
- v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
- return a;
-}
-#endif
-
-// Required by mapgen.h
-bool block_is_underground(u64 seed, v3s16 blockpos)
-{
- /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
- seed, v2s16(blockpos.X, blockpos.Z));*/
- // Nah, this is just a heuristic, just return something
- s16 minimum_groundlevel = WATER_LEVEL;
-
- if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
- return true;
- else
- return false;
-}
-
-#define AVERAGE_MUD_AMOUNT 4
-
-double base_rock_level_2d(u64 seed, v2s16 p)
-{
- // The base ground level
- double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
- + 20. * noise2d_perlin(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed+82341, 5, 0.6);
-
- /*// A bit hillier one
- double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed+93413, 6, 0.69);
- if(base2 > base)
- base = base2;*/
-#if 1
- // Higher ground level
- double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
- 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
- seed+85039, 5, 0.6);
- //higher = 30; // For debugging
-
- // Limit higher to at least base
- if(higher < base)
- higher = base;
-
- // Steepness factor of cliffs
- double b = 0.85 + 0.5 * noise2d_perlin(
- 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
- seed-932, 5, 0.7);
- b = rangelim(b, 0.0, 1000.0);
- b = b*b*b*b*b*b*b;
- b *= 5;
- b = rangelim(b, 0.5, 1000.0);
- // Values 1.5...100 give quite horrible looking slopes
- if(b > 1.5 && b < 100.0){
- if(b < 10.0)
- b = 1.5;
- else
- b = 100.0;
- }
- //dstream<<"b="<<b<<std::endl;
- //double b = 20;
- //b = 0.25;
-
- // Offset to more low
- double a_off = -0.20;
- // High/low selector
- /*double a = 0.5 + b * (a_off + noise2d_perlin(
- 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
- seed+4213, 6, 0.7));*/
- double a = (double)0.5 + b * (a_off + noise2d_perlin(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed+4213, 5, 0.69));
- // Limit
- a = rangelim(a, 0.0, 1.0);
-
- //dstream<<"a="<<a<<std::endl;
-
- double h = base*(1.0-a) + higher*a;
-#else
- double h = base;
-#endif
- return h;
-}
-
-s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
-{
- return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
-}
-
-double get_mud_add_amount(u64 seed, v2s16 p)
-{
- return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
- 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
- seed+91013, 3, 0.55));
-}
-
-bool get_have_beach(u64 seed, v2s16 p2d)
-{
- // Determine whether to have sand here
- double sandnoise = noise2d_perlin(
- 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
- seed+59420, 3, 0.50);
-
- return (sandnoise > 0.15);
-}
-
-enum BiomeType
-{
- BT_NORMAL,
- BT_DESERT
-};
-
-BiomeType get_biome(u64 seed, v2s16 p2d)
-{
- // Just do something very simple as for now
- double d = noise2d_perlin(
- 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
- seed+9130, 3, 0.50);
- if(d > 0.45)
- return BT_DESERT;
- if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
- return BT_DESERT;
- return BT_NORMAL;
-};
-
-u32 get_blockseed(u64 seed, v3s16 p)
-{
- s32 x=p.X, y=p.Y, z=p.Z;
- return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
-}
-
-#define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
-
-void make_block(BlockMakeData *data)
-{
- if(data->no_op)
- {
- //dstream<<"makeBlock: no-op"<<std::endl;
- return;
- }
-
- assert(data->vmanip);
- assert(data->nodedef);
- assert(data->blockpos_requested.X >= data->blockpos_min.X &&
- data->blockpos_requested.Y >= data->blockpos_min.Y &&
- data->blockpos_requested.Z >= data->blockpos_min.Z);
- assert(data->blockpos_requested.X <= data->blockpos_max.X &&
- data->blockpos_requested.Y <= data->blockpos_max.Y &&
- data->blockpos_requested.Z <= data->blockpos_max.Z);
-
- INodeDefManager *ndef = data->nodedef;
-
- // Hack: use minimum block coordinates for old code that assumes
- // a single block
- v3s16 blockpos = data->blockpos_requested;
-
- /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
- <<blockpos.Z<<")"<<std::endl;*/
-
- v3s16 blockpos_min = data->blockpos_min;
- v3s16 blockpos_max = data->blockpos_max;
- v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
- v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
-
- ManualMapVoxelManipulator &vmanip = *(data->vmanip);
- // Area of central chunk
- v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
- v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
- // Full allocated area
- v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
- v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
-
- v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
-
- const s16 max_spread_amount = MAP_BLOCKSIZE;
-
- int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
- * (blockpos_max.Y - blockpos_min.Y + 1)
- * (blockpos_max.Z - blockpos_max.Z + 1);
-
- int volume_nodes = volume_blocks *
- MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
- // Generated surface area
- //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
-
- // Horribly wrong heuristic, but better than nothing
- bool block_is_underground = (WATER_LEVEL > node_max.Y);
-
- /*
- Create a block-specific seed
- */
- u32 blockseed = get_blockseed(data->seed, full_node_min);
-
- /*
- Cache some ground type values for speed
- */
-
-// Creates variables c_name=id and n_name=node
-#define CONTENT_VARIABLE(ndef, name)\
- content_t c_##name = ndef->getId("mapgen_" #name);\
- MapNode n_##name(c_##name);
-// Default to something else if was CONTENT_IGNORE
-#define CONTENT_VARIABLE_FALLBACK(name, dname)\
- if(c_##name == CONTENT_IGNORE){\
- c_##name = c_##dname;\
- n_##name = n_##dname;\
- }
-
- CONTENT_VARIABLE(ndef, stone);
- CONTENT_VARIABLE(ndef, air);
- CONTENT_VARIABLE(ndef, water_source);
- CONTENT_VARIABLE(ndef, dirt);
- CONTENT_VARIABLE(ndef, sand);
- CONTENT_VARIABLE(ndef, gravel);
- CONTENT_VARIABLE(ndef, clay);
- CONTENT_VARIABLE(ndef, lava_source);
- CONTENT_VARIABLE(ndef, cobble);
- CONTENT_VARIABLE(ndef, mossycobble);
- CONTENT_VARIABLE(ndef, dirt_with_grass);
- CONTENT_VARIABLE(ndef, junglegrass);
- CONTENT_VARIABLE(ndef, stone_with_coal);
- CONTENT_VARIABLE(ndef, stone_with_iron);
- CONTENT_VARIABLE(ndef, mese);
- CONTENT_VARIABLE(ndef, desert_sand);
- CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
- CONTENT_VARIABLE(ndef, desert_stone);
- CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
-
- // Maximum height of the stone surface and obstacles.
- // This is used to guide the cave generation
- s16 stone_surface_max_y = 0;
-
- /*
- Generate general ground level to full area
- */
- {
-#if 1
- TimeTaker timer1("Generating ground level");
-
- for(s16 x=node_min.X; x<=node_max.X; x++)
- for(s16 z=node_min.Z; z<=node_max.Z; z++)
- {
- // Node position
- v2s16 p2d = v2s16(x,z);
-
- /*
- Skip of already generated
- */
- /*{
- v3s16 p(p2d.X, node_min.Y, p2d.Y);
- if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
- continue;
- }*/
-
- // Ground height at this point
- float surface_y_f = 0.0;
-
- // Use perlin noise for ground height
- surface_y_f = base_rock_level_2d(data->seed, p2d);
-
- /*// Experimental stuff
- {
- float a = highlands_level_2d(data->seed, p2d);
- if(a > surface_y_f)
- surface_y_f = a;
- }*/
-
- // Convert to integer
- s16 surface_y = (s16)surface_y_f;
-
- // Log it
- if(surface_y > stone_surface_max_y)
- stone_surface_max_y = surface_y;
-
- BiomeType bt = get_biome(data->seed, p2d);
- /*
- Fill ground with stone
- */
- {
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
- for(s16 y=node_min.Y; y<=node_max.Y; y++)
- {
- if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
- if(y <= surface_y){
- if(y > WATER_LEVEL && bt == BT_DESERT)
- vmanip.m_data[i] = n_desert_stone;
- else
- vmanip.m_data[i] = n_stone;
- } else if(y <= WATER_LEVEL){
- vmanip.m_data[i] = MapNode(c_water_source);
- } else {
- vmanip.m_data[i] = MapNode(c_air);
- }
- }
- vmanip.m_area.add_y(em, i, 1);
- }
- }
- }
-#endif
-
- }//timer1
-
- // Limit dirt flow area by 1 because mud is flown into neighbors.
- assert(central_area_size.X == central_area_size.Z);
- s16 mudflow_minpos = 0-max_spread_amount+1;
- s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
-
- /*
- Loop this part, it will make stuff look older and newer nicely
- */
-
- const u32 age_loops = 2;
- for(u32 i_age=0; i_age<age_loops; i_age++)
- { // Aging loop
- /******************************
- BEGINNING OF AGING LOOP
- ******************************/
-
-#if 1
- {
- // 24ms @cs=8
- //TimeTaker timer1("caves");
-
- /*
- Make caves (this code is relatively horrible)
- */
- double cave_amount = 6.0 + 6.0 * noise2d_perlin(
- 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
- data->seed+34329, 3, 0.50);
- cave_amount = MYMAX(0.0, cave_amount);
- u32 caves_count = cave_amount * volume_nodes / 50000;
- u32 bruises_count = 1;
- PseudoRandom ps(blockseed+21343);
- PseudoRandom ps2(blockseed+1032);
- if(ps.range(1, 6) == 1)
- bruises_count = ps.range(0, ps.range(0, 2));
- if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
- caves_count /= 3;
- bruises_count /= 3;
- }
- for(u32 jj=0; jj<caves_count+bruises_count; jj++)
- {
- bool large_cave = (jj >= caves_count);
- s16 min_tunnel_diameter = 2;
- s16 max_tunnel_diameter = ps.range(2,6);
- int dswitchint = ps.range(1,14);
- u16 tunnel_routepoints = 0;
- int part_max_length_rs = 0;
- if(large_cave){
- part_max_length_rs = ps.range(2,4);
- tunnel_routepoints = ps.range(5, ps.range(15,30));
- min_tunnel_diameter = 5;
- max_tunnel_diameter = ps.range(7, ps.range(8,24));
- } else {
- part_max_length_rs = ps.range(2,9);
- tunnel_routepoints = ps.range(10, ps.range(15,30));
- }
- bool large_cave_is_flat = (ps.range(0,1) == 0);
-
- v3f main_direction(0,0,0);
-
- // Allowed route area size in nodes
- v3s16 ar = central_area_size;
-
- // Area starting point in nodes
- v3s16 of = node_min;
-
- // Allow a bit more
- //(this should be more than the maximum radius of the tunnel)
- //s16 insure = 5; // Didn't work with max_d = 20
- s16 insure = 10;
- s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
- ar += v3s16(1,0,1) * more * 2;
- of -= v3s16(1,0,1) * more;
-
- s16 route_y_min = 0;
- // Allow half a diameter + 7 over stone surface
- s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
-
- /*// If caves, don't go through surface too often
- if(large_cave == false)
- route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
-
- // Limit maximum to area
- route_y_max = rangelim(route_y_max, 0, ar.Y-1);
-
- if(large_cave)
- {
- /*// Minimum is at y=0
- route_y_min = -of.Y - 0;*/
- // Minimum is at y=max_tunnel_diameter/4
- //route_y_min = -of.Y + max_tunnel_diameter/4;
- //s16 min = -of.Y + max_tunnel_diameter/4;
- //s16 min = -of.Y + 0;
- s16 min = 0;
- if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
- {
- min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
- route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
- }
- route_y_min = ps.range(min, min + max_tunnel_diameter);
- route_y_min = rangelim(route_y_min, 0, route_y_max);
- }
-
- /*dstream<<"route_y_min = "<<route_y_min
- <<", route_y_max = "<<route_y_max<<std::endl;*/
-
- s16 route_start_y_min = route_y_min;
- s16 route_start_y_max = route_y_max;
-
- // Start every 4th cave from surface when applicable
- /*bool coming_from_surface = false;
- if(node_min.Y <= 0 && node_max.Y >= 0){
- coming_from_surface = (jj % 4 == 0 && large_cave == false);
- if(coming_from_surface)
- route_start_y_min = -of.Y + stone_surface_max_y + 10;
- }*/
-
- route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
- route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
-
- // Randomize starting position
- v3f orp(
- (float)(ps.next()%ar.X)+0.5,
- (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
- (float)(ps.next()%ar.Z)+0.5
- );
-
- v3s16 startp(orp.X, orp.Y, orp.Z);
- startp += of;
-
- MapNode airnode(CONTENT_AIR);
- MapNode waternode(c_water_source);
- MapNode lavanode(c_lava_source);
-
- /*
- Generate some tunnel starting from orp
- */
-
- for(u16 j=0; j<tunnel_routepoints; j++)
- {
- if(j%dswitchint==0 && large_cave == false)
- {
- main_direction = v3f(
- ((float)(ps.next()%20)-(float)10)/10,
- ((float)(ps.next()%20)-(float)10)/30,
- ((float)(ps.next()%20)-(float)10)/10
- );
- main_direction *= (float)ps.range(0, 10)/10;
- }
-
- // Randomize size
- s16 min_d = min_tunnel_diameter;
- s16 max_d = max_tunnel_diameter;
- s16 rs = ps.range(min_d, max_d);
-
- // Every second section is rough
- bool randomize_xz = (ps2.range(1,2) == 1);
-
- v3s16 maxlen;
- if(large_cave)
- {
- maxlen = v3s16(
- rs*part_max_length_rs,
- rs*part_max_length_rs/2,
- rs*part_max_length_rs
- );
- }
- else
- {
- maxlen = v3s16(
- rs*part_max_length_rs,
- ps.range(1, rs*part_max_length_rs),
- rs*part_max_length_rs
- );
- }
-
- v3f vec;
-
- vec = v3f(
- (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
- (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
- (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
- );
-
- // Jump downward sometimes
- if(!large_cave && ps.range(0,12) == 0)
- {
- vec = v3f(
- (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
- (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
- (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
- );
- }
-
- /*if(large_cave){
- v3f p = orp + vec;
- s16 h = find_ground_level_clever(vmanip,
- v2s16(p.X, p.Z), ndef);
- route_y_min = h - rs/3;
- route_y_max = h + rs;
- }*/
-
- vec += main_direction;
-
- v3f rp = orp + vec;
- if(rp.X < 0)
- rp.X = 0;
- else if(rp.X >= ar.X)
- rp.X = ar.X-1;
- if(rp.Y < route_y_min)
- rp.Y = route_y_min;
- else if(rp.Y >= route_y_max)
- rp.Y = route_y_max-1;
- if(rp.Z < 0)
- rp.Z = 0;
- else if(rp.Z >= ar.Z)
- rp.Z = ar.Z-1;
- vec = rp - orp;
-
- for(float f=0; f<1.0; f+=1.0/vec.getLength())
- {
- v3f fp = orp + vec * f;
- fp.X += 0.1*ps.range(-10,10);
- fp.Z += 0.1*ps.range(-10,10);
- v3s16 cp(fp.X, fp.Y, fp.Z);
-
- s16 d0 = -rs/2;
- s16 d1 = d0 + rs;
- if(randomize_xz){
- d0 += ps.range(-1,1);
- d1 += ps.range(-1,1);
- }
- for(s16 z0=d0; z0<=d1; z0++)
- {
- s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
- for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
- {
- s16 maxabsxz = MYMAX(abs(x0), abs(z0));
- s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
- for(s16 y0=-si2; y0<=si2; y0++)
- {
- /*// Make better floors in small caves
- if(y0 <= -rs/2 && rs<=7)
- continue;*/
- if(large_cave_is_flat){
- // Make large caves not so tall
- if(rs > 7 && abs(y0) >= rs/3)
- continue;
- }
-
- s16 z = cp.Z + z0;
- s16 y = cp.Y + y0;
- s16 x = cp.X + x0;
- v3s16 p(x,y,z);
- p += of;
-
- if(vmanip.m_area.contains(p) == false)
- continue;
-
- u32 i = vmanip.m_area.index(p);
-
- if(large_cave)
- {
- if(full_node_min.Y < WATER_LEVEL &&
- full_node_max.Y > WATER_LEVEL){
- if(p.Y <= WATER_LEVEL)
- vmanip.m_data[i] = waternode;
- else
- vmanip.m_data[i] = airnode;
- } else if(full_node_max.Y < WATER_LEVEL){
- if(p.Y < startp.Y - 2)
- vmanip.m_data[i] = lavanode;
- else
- vmanip.m_data[i] = airnode;
- } else {
- vmanip.m_data[i] = airnode;
- }
- } else {
- // Don't replace air or water or lava or ignore
- if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
- vmanip.m_data[i].getContent() == CONTENT_AIR ||
- vmanip.m_data[i].getContent() == c_water_source ||
- vmanip.m_data[i].getContent() == c_lava_source)
- continue;
-
- vmanip.m_data[i] = airnode;
-
- // Set tunnel flag
- vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
- }
- }
- }
- }
- }
-
- orp = rp;
- }
-
- }
-
- }//timer1
-#endif
-
-#if 1
- {
- // 15ms @cs=8
- TimeTaker timer1("add mud");
-
- /*
- Add mud to the central chunk
- */
-
- for(s16 x=node_min.X; x<=node_max.X; x++)
- for(s16 z=node_min.Z; z<=node_max.Z; z++)
- {
- // Node position in 2d
- v2s16 p2d = v2s16(x,z);
-
- // Randomize mud amount
- s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
-
- // Find ground level
- s16 surface_y = find_stone_level(vmanip, p2d, ndef);
- // Handle area not found
- if(surface_y == vmanip.m_area.MinEdge.Y - 1)
- continue;
-
- MapNode addnode(c_dirt);
- BiomeType bt = get_biome(data->seed, p2d);
-
- if(bt == BT_DESERT)
- addnode = MapNode(c_desert_sand);
-
- if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
- addnode = MapNode(c_sand);
- } else if(mud_add_amount <= 0){
- mud_add_amount = 1 - mud_add_amount;
- addnode = MapNode(c_gravel);
- } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
- surface_y + mud_add_amount <= WATER_LEVEL+2){
- addnode = MapNode(c_sand);
- }
-
- if(bt == BT_DESERT){
- if(surface_y > 20){
- mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
- }
- }
-
- /*
- If topmost node is grass, change it to mud.
- It might be if it was flown to there from a neighboring
- chunk and then converted.
- */
- {
- u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
- MapNode *n = &vmanip.m_data[i];
- if(n->getContent() == c_dirt_with_grass)
- *n = MapNode(c_dirt);
- }
-
- /*
- Add mud on ground
- */
- {
- s16 mudcount = 0;
- v3s16 em = vmanip.m_area.getExtent();
- s16 y_start = surface_y+1;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
- for(s16 y=y_start; y<=node_max.Y; y++)
- {
- if(mudcount >= mud_add_amount)
- break;
-
- MapNode &n = vmanip.m_data[i];
- n = addnode;
- mudcount++;
-
- vmanip.m_area.add_y(em, i, 1);
- }
- }
-
- }
-
- }//timer1
-#endif
-
- /*
- Add blobs of dirt and gravel underground
- */
- if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
- {
- PseudoRandom pr(blockseed+983);
- for(int i=0; i<volume_nodes/10/10/10; i++)
- {
- bool only_fill_cave = (myrand_range(0,1) != 0);
- v3s16 size(
- pr.range(1, 8),
- pr.range(1, 8),
- pr.range(1, 8)
- );
- v3s16 p0(
- pr.range(node_min.X, node_max.X)-size.X/2,
- pr.range(node_min.Y, node_max.Y)-size.Y/2,
- pr.range(node_min.Z, node_max.Z)-size.Z/2
- );
- MapNode n1;
- if(p0.Y > -32 && pr.range(0,1) == 0)
- n1 = MapNode(c_dirt);
- else
- n1 = MapNode(c_gravel);
- for(int x1=0; x1<size.X; x1++)
- for(int y1=0; y1<size.Y; y1++)
- for(int z1=0; z1<size.Z; z1++)
- {
- v3s16 p = p0 + v3s16(x1,y1,z1);
- u32 i = vmanip.m_area.index(p);
- if(!vmanip.m_area.contains(i))
- continue;
- // Cancel if not stone and not cave air
- if(vmanip.m_data[i].getContent() != c_stone &&
- !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
- continue;
- if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
- continue;
- vmanip.m_data[i] = n1;
- }
- }
- }
-
-#if 1
- {
- // 340ms @cs=8
- TimeTaker timer1("flow mud");
-
- /*
- Flow mud away from steep edges
- */
-
- // Iterate a few times
- for(s16 k=0; k<3; k++)
- {
-
- for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
- for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
- {
- // Invert coordinates every 2nd iteration
- if(k%2 == 0)
- {
- x = mudflow_maxpos - (x-mudflow_minpos);
- z = mudflow_maxpos - (z-mudflow_minpos);
- }
-
- // Node position in 2d
- v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
-
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
- s16 y=node_max.Y;
-
- while(y >= node_min.Y)
- {
-
- for(;; y--)
- {
- MapNode *n = NULL;
- // Find mud
- for(; y>=node_min.Y; y--)
- {
- n = &vmanip.m_data[i];
- //if(content_walkable(n->d))
- // break;
- if(n->getContent() == c_dirt ||
- n->getContent() == c_dirt_with_grass ||
- n->getContent() == c_gravel)
- break;
-
- vmanip.m_area.add_y(em, i, -1);
- }
-
- // Stop if out of area
- //if(vmanip.m_area.contains(i) == false)
- if(y < node_min.Y)
- break;
-
- /*// If not mud, do nothing to it
- MapNode *n = &vmanip.m_data[i];
- if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
- continue;*/
-
- if(n->getContent() == c_dirt ||
- n->getContent() == c_dirt_with_grass)
- {
- // Make it exactly mud
- n->setContent(c_dirt);
-
- /*
- Don't flow it if the stuff under it is not mud
- */
- {
- u32 i2 = i;
- vmanip.m_area.add_y(em, i2, -1);
- // Cancel if out of area
- if(vmanip.m_area.contains(i2) == false)
- continue;
- MapNode *n2 = &vmanip.m_data[i2];
- if(n2->getContent() != c_dirt &&
- n2->getContent() != c_dirt_with_grass)
- continue;
- }
- }
-
- /*s16 recurse_count = 0;
- mudflow_recurse:*/
-
- v3s16 dirs4[4] = {
- v3s16(0,0,1), // back
- v3s16(1,0,0), // right
- v3s16(0,0,-1), // front
- v3s16(-1,0,0), // left
- };
-
- // Theck that upper is air or doesn't exist.
- // Cancel dropping if upper keeps it in place
- u32 i3 = i;
- vmanip.m_area.add_y(em, i3, 1);
- if(vmanip.m_area.contains(i3) == true
- && ndef->get(vmanip.m_data[i3]).walkable)
- {
- continue;
- }
-
- // Drop mud on side
-
- for(u32 di=0; di<4; di++)
- {
- v3s16 dirp = dirs4[di];
- u32 i2 = i;
- // Move to side
- vmanip.m_area.add_p(em, i2, dirp);
- // Fail if out of area
- if(vmanip.m_area.contains(i2) == false)
- continue;
- // Check that side is air
- MapNode *n2 = &vmanip.m_data[i2];
- if(ndef->get(*n2).walkable)
- continue;
- // Check that under side is air
- vmanip.m_area.add_y(em, i2, -1);
- if(vmanip.m_area.contains(i2) == false)
- continue;
- n2 = &vmanip.m_data[i2];
- if(ndef->get(*n2).walkable)
- continue;
- /*// Check that under that is air (need a drop of 2)
- vmanip.m_area.add_y(em, i2, -1);
- if(vmanip.m_area.contains(i2) == false)
- continue;
- n2 = &vmanip.m_data[i2];
- if(content_walkable(n2->d))
- continue;*/
- // Loop further down until not air
- bool dropped_to_unknown = false;
- do{
- vmanip.m_area.add_y(em, i2, -1);
- n2 = &vmanip.m_data[i2];
- // if out of known area
- if(vmanip.m_area.contains(i2) == false
- || n2->getContent() == CONTENT_IGNORE){
- dropped_to_unknown = true;
- break;
- }
- }while(ndef->get(*n2).walkable == false);
- // Loop one up so that we're in air
- vmanip.m_area.add_y(em, i2, 1);
- n2 = &vmanip.m_data[i2];
-
- bool old_is_water = (n->getContent() == c_water_source);
- // Move mud to new place
- if(!dropped_to_unknown) {
- *n2 = *n;
- // Set old place to be air (or water)
- if(old_is_water)
- *n = MapNode(c_water_source);
- else
- *n = MapNode(CONTENT_AIR);
- }
-
- // Done
- break;
- }
- }
- }
- }
-
- }
-
- }//timer1
-#endif
-
- } // Aging loop
- /***********************
- END OF AGING LOOP
- ************************/
-
- /*
- Add top and bottom side of water to transforming_liquid queue
- */
-
- for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
- for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
- {
- // Node position
- v2s16 p2d(x,z);
- {
- bool water_found = false;
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
- for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
- {
- if(y == full_node_max.Y){
- water_found =
- (vmanip.m_data[i].getContent() == c_water_source ||
- vmanip.m_data[i].getContent() == c_lava_source);
- }
- else if(water_found == false)
- {
- if(vmanip.m_data[i].getContent() == c_water_source ||
- vmanip.m_data[i].getContent() == c_lava_source)
- {
- v3s16 p = v3s16(p2d.X, y, p2d.Y);
- data->transforming_liquid.push_back(p);
- water_found = true;
- }
- }
- else
- {
- // This can be done because water_found can only
- // turn to true and end up here after going through
- // a single block.
- if(vmanip.m_data[i+1].getContent() != c_water_source ||
- vmanip.m_data[i+1].getContent() != c_lava_source)
- {
- v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
- data->transforming_liquid.push_back(p);
- water_found = false;
- }
- }
-
- vmanip.m_area.add_y(em, i, -1);
- }
- }
- }
-
- /*
- Grow grass
- */
-
- for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
- for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
- {
- // Node position in 2d
- v2s16 p2d = v2s16(x,z);
-
- /*
- Find the lowest surface to which enough light ends up
- to make grass grow.
-
- Basically just wait until not air and not leaves.
- */
- s16 surface_y = 0;
- {
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
- s16 y;
- // Go to ground level
- for(y=node_max.Y; y>=full_node_min.Y; y--)
- {
- MapNode &n = vmanip.m_data[i];
- if(ndef->get(n).param_type != CPT_LIGHT
- || ndef->get(n).liquid_type != LIQUID_NONE)
- break;
- vmanip.m_area.add_y(em, i, -1);
- }
- if(y >= full_node_min.Y)
- surface_y = y;
- else
- surface_y = full_node_min.Y;
- }
-
- u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
- MapNode *n = &vmanip.m_data[i];
- if(n->getContent() == c_dirt){
- // Well yeah, this can't be overground...
- if(surface_y < WATER_LEVEL - 20)
- continue;
- n->setContent(c_dirt_with_grass);
- }
- }
-
- /*
- Generate some trees
- */
- assert(central_area_size.X == central_area_size.Z);
- {
- PseudoRandom ps (blockseed);
- // Divide area into parts
- s16 div = 8;
- s16 sidelen = central_area_size.X / div;
- double area = sidelen * sidelen;
- for(s16 x0=0; x0<div; x0++)
- for(s16 z0=0; z0<div; z0++)
- {
- // Center position of part of division
- v2s16 p2d_center(
- node_min.X + sidelen/2 + sidelen*x0,
- node_min.Z + sidelen/2 + sidelen*z0
- );
- // Minimum edge of part of division
- v2s16 p2d_min(
- node_min.X + sidelen*x0,
- node_min.Z + sidelen*z0
- );
- // Maximum edge of part of division
- v2s16 p2d_max(
- node_min.X + sidelen + sidelen*x0 - 1,
- node_min.Z + sidelen + sidelen*z0 - 1
- );
- // Amount of trees
- u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
- // Put trees in random places on part of division
- for(u32 i=0; i<tree_count; i++)
- {
- s16 x = ps.range(p2d_min.X, p2d_max.X);
- s16 z = ps.range(p2d_min.Y, p2d_max.Y);
- s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
- // Don't make a tree under water level
- if(y < WATER_LEVEL)
- continue;
- // Don't make a tree so high that it doesn't fit
- if(y > node_max.Y - 6)
- continue;
- v3s16 p(x,y,z);
- /*
- Trees grow only on mud and grass
- */
- {
- u32 i = vmanip.m_area.index(v3s16(p));
- MapNode *n = &vmanip.m_data[i];
- if(n->getContent() != c_dirt
- && n->getContent() != c_dirt_with_grass)
- continue;
- }
- p.Y++;
- // Make a tree
- treegen::make_tree(vmanip, p, false, ndef, ps.next());
- }
- }
- }
-
-#if 0
- /*
- Make base ground level
- */
-
- for(s16 x=node_min.X; x<=node_max.X; x++)
- for(s16 z=node_min.Z; z<=node_max.Z; z++)
- {
- // Node position
- v2s16 p2d(x,z);
- {
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
- for(s16 y=node_min.Y; y<=node_max.Y; y++)
- {
- // Only modify places that have no content
- if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
- {
- // First priority: make air and water.
- // This avoids caves inside water.
- if(all_is_ground_except_caves == false
- && val_is_ground(noisebuf_ground.get(x,y,z),
- v3s16(x,y,z), data->seed) == false)
- {
- if(y <= WATER_LEVEL)
- vmanip.m_data[i] = n_water_source;
- else
- vmanip.m_data[i] = n_air;
- }
- else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
- vmanip.m_data[i] = n_air;
- else
- vmanip.m_data[i] = n_stone;
- }
-
- vmanip->m_area.add_y(em, i, 1);
- }
- }
- }
-
- /*
- Add mud and sand and others underground (in place of stone)
- */
-
- for(s16 x=node_min.X; x<=node_max.X; x++)
- for(s16 z=node_min.Z; z<=node_max.Z; z++)
- {
- // Node position
- v2s16 p2d(x,z);
- {
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
- for(s16 y=node_max.Y; y>=node_min.Y; y--)
- {
- if(vmanip.m_data[i].getContent() == c_stone)
- {
- if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
- {
- if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
- vmanip.m_data[i] = n_dirt;
- else
- vmanip.m_data[i] = n_sand;
- }
- else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
- {
- if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
- vmanip.m_data[i] = n_gravel;
- }
- else if(noisebuf_ground_crumbleness.get(x,y,z) <
- -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
- {
- vmanip.m_data[i] = n_lava_source;
- for(s16 x1=-1; x1<=1; x1++)
- for(s16 y1=-1; y1<=1; y1++)
- for(s16 z1=-1; z1<=1; z1++)
- data->transforming_liquid.push_back(
- v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
- }
- }
-
- vmanip->m_area.add_y(em, i, -1);
- }
- }
- }
-
- /*
- Add dungeons
- */
-
- //if(node_min.Y < approx_groundlevel)
- //if(myrand() % 3 == 0)
- //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
- //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
- //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
- float dungeon_rarity = 0.02;
- if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
- < dungeon_rarity
- && node_min.Y < approx_groundlevel)
- {
- // Dungeon generator doesn't modify places which have this set
- vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
- | VMANIP_FLAG_DUNGEON_PRESERVE);
-
- // Set all air and water to be untouchable to make dungeons open
- // to caves and open air
- for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
- for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
- {
- // Node position
- v2s16 p2d(x,z);
- {
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
- for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
- {
- if(vmanip.m_data[i].getContent() == CONTENT_AIR)
- vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
- else if(vmanip.m_data[i].getContent() == c_water_source)
- vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
- vmanip->m_area.add_y(em, i, -1);
- }
- }
- }
-
- PseudoRandom random(blockseed+2);
-
- // Add it
- make_dungeon1(vmanip, random, ndef);
-
- // Convert some cobble to mossy cobble
- for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
- for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
- {
- // Node position
- v2s16 p2d(x,z);
- {
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
- for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
- {
- // (noisebuf not used because it doesn't contain the
- // full area)
- double wetness = noise3d_param(
- get_ground_wetness_params(data->seed), x,y,z);
- double d = noise3d_perlin((float)x/2.5,
- (float)y/2.5,(float)z/2.5,
- blockseed, 2, 1.4);
- if(vmanip.m_data[i].getContent() == c_cobble)
- {
- if(d < wetness/3.0)
- {
- vmanip.m_data[i].setContent(c_mossycobble);
- }
- }
- /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
- {
- if(wetness > 1.2)
- vmanip.m_data[i].setContent(c_dirt);
- }*/
- vmanip->m_area.add_y(em, i, -1);
- }
- }
- }
- }
-
- /*
- Add NC
- */
- {
- PseudoRandom ncrandom(blockseed+9324342);
- if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
- {
- make_nc(vmanip, ncrandom, ndef);
- }
- }
-
- /*
- Add top and bottom side of water to transforming_liquid queue
- */
-
- for(s16 x=node_min.X; x<=node_max.X; x++)
- for(s16 z=node_min.Z; z<=node_max.Z; z++)
- {
- // Node position
- v2s16 p2d(x,z);
- {
- bool water_found = false;
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
- for(s16 y=node_max.Y; y>=node_min.Y; y--)
- {
- if(water_found == false)
- {
- if(vmanip.m_data[i].getContent() == c_water_source)
- {
- v3s16 p = v3s16(p2d.X, y, p2d.Y);
- data->transforming_liquid.push_back(p);
- water_found = true;
- }
- }
- else
- {
- // This can be done because water_found can only
- // turn to true and end up here after going through
- // a single block.
- if(vmanip.m_data[i+1].getContent() != c_water_source)
- {
- v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
- data->transforming_liquid.push_back(p);
- water_found = false;
- }
- }
-
- vmanip->m_area.add_y(em, i, -1);
- }
- }
- }
-
- /*
- If close to ground level
- */
-
- //if(abs(approx_ground_depth) < 30)
- if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
- {
- /*
- Add grass and mud
- */
-
- for(s16 x=node_min.X; x<=node_max.X; x++)
- for(s16 z=node_min.Z; z<=node_max.Z; z++)
- {
- // Node position
- v2s16 p2d(x,z);
- {
- bool possibly_have_sand = get_have_beach(data->seed, p2d);
- bool have_sand = false;
- u32 current_depth = 0;
- bool air_detected = false;
- bool water_detected = false;
- bool have_clay = false;
-
- // Use fast index incrementing
- s16 start_y = node_max.Y+2;
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
- for(s16 y=start_y; y>=node_min.Y-3; y--)
- {
- if(vmanip.m_data[i].getContent() == c_water_source)
- water_detected = true;
- if(vmanip.m_data[i].getContent() == CONTENT_AIR)
- air_detected = true;
-
- if((vmanip.m_data[i].getContent() == c_stone
- || vmanip.m_data[i].getContent() == c_dirt_with_grass
- || vmanip.m_data[i].getContent() == c_dirt
- || vmanip.m_data[i].getContent() == c_sand
- || vmanip.m_data[i].getContent() == c_gravel
- ) && (air_detected || water_detected))
- {
- if(current_depth == 0 && y <= WATER_LEVEL+2
- && possibly_have_sand)
- have_sand = true;
-
- if(current_depth < 4)
- {
- if(have_sand)
- {
- vmanip.m_data[i] = MapNode(c_sand);
- }
- #if 1
- else if(current_depth==0 && !water_detected
- && y >= WATER_LEVEL && air_detected)
- vmanip.m_data[i] = MapNode(c_dirt_with_grass);
- #endif
- else
- vmanip.m_data[i] = MapNode(c_dirt);
- }
- else
- {
- if(vmanip.m_data[i].getContent() == c_dirt
- || vmanip.m_data[i].getContent() == c_dirt_with_grass)
- vmanip.m_data[i] = MapNode(c_stone);
- }
-
- current_depth++;
-
- if(current_depth >= 8)
- break;
- }
- else if(current_depth != 0)
- break;
-
- vmanip->m_area.add_y(em, i, -1);
- }
- }
- }
-
- /*
- Calculate some stuff
- */
-
- float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
- bool is_jungle = surface_humidity > 0.75;
- // Amount of trees
- u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
- if(is_jungle)
- tree_count *= 5;
-
- /*
- Add trees
- */
- PseudoRandom treerandom(blockseed);
- // Put trees in random places on part of division
- for(u32 i=0; i<tree_count; i++)
- {
- s16 x = treerandom.range(node_min.X, node_max.X);
- s16 z = treerandom.range(node_min.Z, node_max.Z);
- //s16 y = find_ground_level(vmanip, v2s16(x,z));
- s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
- // Don't make a tree under water level
- if(y < WATER_LEVEL)
- continue;
- // Make sure tree fits (only trees whose starting point is
- // at this block are added)
- if(y < node_min.Y || y > node_max.Y)
- continue;
- /*
- Find exact ground level
- */
- v3s16 p(x,y+6,z);
- bool found = false;
- for(; p.Y >= y-6; p.Y--)
- {
- u32 i = vmanip->m_area.index(p);
- MapNode *n = &vmanip->m_data[i];
- if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
- {
- found = true;
- break;
- }
- }
- // If not found, handle next one
- if(found == false)
- continue;
-
- {
- u32 i = vmanip->m_area.index(p);
- MapNode *n = &vmanip->m_data[i];
-
- if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
- continue;
-
- // Papyrus grows only on mud and in water
- if(n->getContent() == c_dirt && y <= WATER_LEVEL)
- {
- p.Y++;
- make_papyrus(vmanip, p, ndef);
- }
- // Trees grow only on mud and grass, on land
- else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
- {
- p.Y++;
- //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
- if(is_jungle == false)
- {
- bool is_apple_tree;
- if(myrand_range(0,4) != 0)
- is_apple_tree = false;
- else
- is_apple_tree = noise2d_perlin(
- 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
- data->seed+342902, 3, 0.45) > 0.2;
- make_tree(vmanip, p, is_apple_tree, ndef);
- }
- else
- make_jungletree(vmanip, p, ndef);
- }
- // Cactii grow only on sand, on land
- else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
- {
- p.Y++;
- make_cactus(vmanip, p, ndef);
- }
- }
- }
-
- /*
- Add jungle grass
- */
- if(is_jungle)
- {
- PseudoRandom grassrandom(blockseed);
- for(u32 i=0; i<surface_humidity*5*tree_count; i++)
- {
- s16 x = grassrandom.range(node_min.X, node_max.X);
- s16 z = grassrandom.range(node_min.Z, node_max.Z);
- s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
- if(y < WATER_LEVEL)
- continue;
- if(y < node_min.Y || y > node_max.Y)
- continue;
- /*
- Find exact ground level
- */
- v3s16 p(x,y+6,z);
- bool found = false;
- for(; p.Y >= y-6; p.Y--)
- {
- u32 i = vmanip->m_area.index(p);
- MapNode *n = &vmanip->m_data[i];
- if(data->nodedef->get(*n).is_ground_content)
- {
- found = true;
- break;
- }
- }
- // If not found, handle next one
- if(found == false)
- continue;
- p.Y++;
- if(vmanip.m_area.contains(p) == false)
- continue;
- if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
- continue;
- /*p.Y--;
- if(vmanip.m_area.contains(p))
- vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
- p.Y++;*/
- if(vmanip.m_area.contains(p))
- vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
- }
- }
-
-#if 0
- /*
- Add some kind of random stones
- */
-
- u32 random_stone_count = gen_area_nodes *
- randomstone_amount_2d(data->seed, p2d_center);
- // Put in random places on part of division
- for(u32 i=0; i<random_stone_count; i++)
- {
- s16 x = myrand_range(node_min.X, node_max.X);
- s16 z = myrand_range(node_min.Z, node_max.Z);
- s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
- // Don't add under water level
- /*if(y < WATER_LEVEL)
- continue;*/
- // Don't add if doesn't belong to this block
- if(y < node_min.Y || y > node_max.Y)
- continue;
- v3s16 p(x,y,z);
- // Filter placement
- /*{
- u32 i = vmanip->m_area.index(v3s16(p));
- MapNode *n = &vmanip->m_data[i];
- if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
- continue;
- }*/
- // Will be placed one higher
- p.Y++;
- // Add it
- make_randomstone(vmanip, p);
- }
-#endif
-
-#if 0
- /*
- Add larger stones
- */
-
- u32 large_stone_count = gen_area_nodes *
- largestone_amount_2d(data->seed, p2d_center);
- //u32 large_stone_count = 1;
- // Put in random places on part of division
- for(u32 i=0; i<large_stone_count; i++)
- {
- s16 x = myrand_range(node_min.X, node_max.X);
- s16 z = myrand_range(node_min.Z, node_max.Z);
- s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
- // Don't add under water level
- /*if(y < WATER_LEVEL)
- continue;*/
- // Don't add if doesn't belong to this block
- if(y < node_min.Y || y > node_max.Y)
- continue;
- v3s16 p(x,y,z);
- // Filter placement
- /*{
- u32 i = vmanip->m_area.index(v3s16(p));
- MapNode *n = &vmanip->m_data[i];
- if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
- continue;
- }*/
- // Will be placed one lower
- p.Y--;
- // Add it
- make_largestone(vmanip, p);
- }
-#endif
- }
-
- /*
- Add minerals
- */
-
- {
- PseudoRandom mineralrandom(blockseed);
-
- /*
- Add meseblocks
- */
- for(s16 i=0; i<approx_ground_depth/4; i++)
- {
- if(mineralrandom.next()%50 == 0)
- {
- s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
- s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
- s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
- for(u16 i=0; i<27; i++)
- {
- v3s16 p = v3s16(x,y,z) + g_27dirs[i];
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() == c_stone)
- if(mineralrandom.next()%8 == 0)
- vmanip.m_data[vi] = MapNode(c_mese);
- }
-
- }
- }
- /*
- Add others
- */
- {
- u16 a = mineralrandom.range(0,15);
- a = a*a*a;
- u16 amount = 20 * a/1000;
- for(s16 i=0; i<amount; i++)
- {
- s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
- s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
- s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
-
- u8 base_content = c_stone;
- MapNode new_content(CONTENT_IGNORE);
- u32 sparseness = 6;
-
- if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
- {
- new_content = MapNode(c_stone_with_coal);
- }
- else
- {
- if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
- new_content = MapNode(c_stone_with_iron);
- /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
- vmanip.m_data[i] = MapNode(c_dirt);
- else
- vmanip.m_data[i] = MapNode(c_sand);*/
- }
- /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
- {
- }*/
-
- if(new_content.getContent() != CONTENT_IGNORE)
- {
- for(u16 i=0; i<27; i++)
- {
- v3s16 p = v3s16(x,y,z) + g_27dirs[i];
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() == base_content)
- {
- if(mineralrandom.next()%sparseness == 0)
- vmanip.m_data[vi] = new_content;
- }
- }
- }
- }
- }
- /*
- Add coal
- */
- //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
- //for(s16 i=0; i<50; i++)
- u16 coal_amount = 30;
- u16 coal_rareness = 60 / coal_amount;
- if(coal_rareness == 0)
- coal_rareness = 1;
- if(mineralrandom.next()%coal_rareness == 0)
- {
- u16 a = mineralrandom.next() % 16;
- u16 amount = coal_amount * a*a*a / 1000;
- for(s16 i=0; i<amount; i++)
- {
- s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
- s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
- s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
- for(u16 i=0; i<27; i++)
- {
- v3s16 p = v3s16(x,y,z) + g_27dirs[i];
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() == c_stone)
- if(mineralrandom.next()%8 == 0)
- vmanip.m_data[vi] = MapNode(c_stone_with_coal);
- }
- }
- }
- /*
- Add iron
- */
- u16 iron_amount = 8;
- u16 iron_rareness = 60 / iron_amount;
- if(iron_rareness == 0)
- iron_rareness = 1;
- if(mineralrandom.next()%iron_rareness == 0)
- {
- u16 a = mineralrandom.next() % 16;
- u16 amount = iron_amount * a*a*a / 1000;
- for(s16 i=0; i<amount; i++)
- {
- s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
- s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
- s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
- for(u16 i=0; i<27; i++)
- {
- v3s16 p = v3s16(x,y,z) + g_27dirs[i];
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() == c_stone)
- if(mineralrandom.next()%8 == 0)
- vmanip.m_data[vi] = MapNode(c_stone_with_iron);
- }
- }
- }
- }
-#endif
-
- /*
- Calculate lighting
- */
- {
- ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
- SPT_AVG);
- //VoxelArea a(node_min, node_max);
- VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
- node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
- /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
- node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
- enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
- for(int i=0; i<2; i++)
- {
- enum LightBank bank = banks[i];
-
- core::map<v3s16, bool> light_sources;
- core::map<v3s16, u8> unlight_from;
-
- voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
- light_sources, unlight_from);
-
- bool inexistent_top_provides_sunlight = !block_is_underground;
- voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
- vmanip, a, inexistent_top_provides_sunlight,
- light_sources, ndef);
- // TODO: Do stuff according to bottom_sunlight_valid
-
- vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
-
- vmanip.spreadLight(bank, light_sources, ndef);
- }
- }
-}
-
-#endif ///BIG COMMENT
-
diff --git a/src/mapgen.h b/src/mapgen.h
index 911e87537..a900985da 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MG_TREES 0x01
#define MG_CAVES 0x02
#define MG_DUNGEONS 0x04
-#define MGV6_FORESTS 0x08
+#define MGV6_JUNGLES 0x08
#define MGV6_BIOME_BLEND 0x10
#define MG_FLAT 0x20
@@ -45,7 +45,8 @@ class MapBlock;
class ManualMapVoxelManipulator;
class VoxelManipulator;
class INodeDefManager;
-class BlockMakeData;
+struct BlockMakeData;
+class VoxelArea;
struct MapgenParams {
std::string mg_name;
@@ -72,6 +73,14 @@ public:
int water_level;
bool generating;
int id;
+ ManualMapVoxelManipulator *vm;
+ INodeDefManager *ndef;
+
+ void updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax);
+ void setLighting(v3s16 nmin, v3s16 nmax, u8 light);
+ void lightSpread(VoxelArea &a, v3s16 p, u8 light);
+ void calcLighting(v3s16 nmin, v3s16 nmax);
+ void calcLightingOld(v3s16 nmin, v3s16 nmax);
virtual void makeChunk(BlockMakeData *data) {};
virtual int getGroundLevelAtPoint(v2s16 p) = 0;
@@ -88,5 +97,48 @@ struct MapgenFactory {
virtual MapgenParams *createMapgenParams() = 0;
};
+enum OreType {
+ ORE_SCATTER,
+ ORE_SHEET,
+ ORE_CLAYLIKE
+};
+
+class Ore {
+public:
+ std::string ore_name;
+ std::string wherein_name;
+
+ content_t ore;
+ content_t wherein; // the node to be replaced
+ s16 clust_scarcity; //
+ s16 clust_num_ores; // how many ore nodes are in a chunk
+ s16 clust_size; // how large (in nodes) a chunk of ore is
+ s16 height_min;
+ s16 height_max;
+ float nthresh; // threshhold for noise at which an ore is placed
+ NoiseParams *np; // noise for distribution of clusters (NULL for uniform scattering)
+ Noise *noise;
+
+ Ore() {
+ ore = CONTENT_IGNORE;
+ wherein = CONTENT_IGNORE;
+ np = NULL;
+ noise = NULL;
+ }
+
+ void resolveNodeNames(INodeDefManager *ndef);
+ virtual void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) = 0;
+};
+
+class OreScatter : public Ore {
+ void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+};
+
+class OreSheet : public Ore {
+ void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+};
+
+Ore *createOre(OreType type);
+
#endif
diff --git a/src/mapgen_indev.cpp b/src/mapgen_indev.cpp
new file mode 100644
index 000000000..5d455827a
--- /dev/null
+++ b/src/mapgen_indev.cpp
@@ -0,0 +1,371 @@
+/*
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "mapgen_indev.h"
+#include "constants.h"
+#include "map.h"
+#include "main.h"
+#include "log.h"
+
+/////////////////// Mapgen Indev perlin noise (default values - not used, from config or defaultsettings)
+
+NoiseIndevParams nparams_indev_def;
+
+/*
+NoiseIndevParams nparams_indev_def_terrain_base;
+// (-AVERAGE_MUD_AMOUNT, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6, 1);
+NoiseIndevParams nparams_indev_def_terrain_higher;
+// (20.0, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6, 1);
+NoiseIndevParams nparams_indev_def_steepness;
+// (0.85, 0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7, 1);
+NoiseIndevParams nparams_indev_def_mud;
+// (AVERAGE_MUD_AMOUNT, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55, 1);
+NoiseIndevParams nparams_indev_def_float_islands;
+// (1, 10.0, v3f(500.0, 500.0, 500.0), 32451, 5, 0.6, 1);
+NoiseIndevParams nparams_indev_def_biome;
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+
+void NoiseIndev::init(NoiseIndevParams *np, int seed, int sx, int sy, int sz) {
+ Noise::init((NoiseParams*)np, seed, sx, sy, sz);
+ this->npindev = np;
+}
+
+NoiseIndev::NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy) : Noise(np, seed, sx, sy) {
+ init(np, seed, sx, sy, 1);
+}
+
+NoiseIndev::NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy, int sz) : Noise(np, seed, sx, sy, sz) {
+ init(np, seed, sx, sy, sz);
+}
+
+float farscale(float scale, float z) {
+ return ( 1 + ( 1 - (MAP_GENERATION_LIMIT * 1 - (fabs(z)) ) / (MAP_GENERATION_LIMIT * 1) ) * (scale - 1) );
+}
+
+float farscale(float scale, float x, float z) {
+ return ( 1 + ( 1 - (MAP_GENERATION_LIMIT * 2 - (fabs(x) + fabs(z)) ) / (MAP_GENERATION_LIMIT * 2) ) * (scale - 1) );
+}
+
+float farscale(float scale, float x, float y, float z) {
+ return ( 1 + ( 1 - (MAP_GENERATION_LIMIT * 3 - (fabs(x) + fabs(y) + fabs(z)) ) / (MAP_GENERATION_LIMIT * 3) ) * (scale - 1) );
+}
+
+void NoiseIndev::transformNoiseMapFarScale(float xx, float yy, float zz) {
+ int i = 0;
+ for (int z = 0; z != sz; z++) {
+ for (int y = 0; y != sy; y++) {
+ for (int x = 0; x != sx; x++) {
+ result[i] = result[i] * npindev->scale * farscale(npindev->farscale, xx, yy, zz) + npindev->offset;
+ i++;
+ }
+ }
+ }
+}
+
+MapgenIndev::MapgenIndev(int mapgenid, MapgenIndevParams *params, EmergeManager *emerge)
+ : MapgenV6(mapgenid, params, emerge)
+{
+ noiseindev_terrain_base = new NoiseIndev(params->npindev_terrain_base, seed, csize.X, csize.Z);
+ noiseindev_terrain_higher = new NoiseIndev(params->npindev_terrain_higher, seed, csize.X, csize.Z);
+ noiseindev_steepness = new NoiseIndev(params->npindev_steepness, seed, csize.X, csize.Z);
+// noise_height_select = new Noise(params->np_height_select, seed, csize.X, csize.Y);
+// noise_trees = new Noise(params->np_trees, seed, csize.X, csize.Y);
+ noiseindev_mud = new NoiseIndev(params->npindev_mud, seed, csize.X, csize.Z);
+// noise_beach = new Noise(params->np_beach, seed, csize.X, csize.Y);
+ noiseindev_float_islands1 = new NoiseIndev(params->npindev_float_islands1, seed, csize.X, csize.Y, csize.Z);
+ noiseindev_float_islands2 = new NoiseIndev(params->npindev_float_islands2, seed, csize.X, csize.Y, csize.Z);
+ noiseindev_float_islands3 = new NoiseIndev(params->npindev_float_islands3, seed, csize.X, csize.Z);
+ noiseindev_biome = new NoiseIndev(params->npindev_biome, seed, csize.X, csize.Z);
+}
+
+MapgenIndev::~MapgenIndev() {
+ delete noiseindev_terrain_base;
+ delete noiseindev_terrain_higher;
+ delete noiseindev_steepness;
+ //delete noise_height_select;
+ //delete noise_trees;
+ delete noiseindev_mud;
+ //delete noise_beach;
+ delete noiseindev_float_islands1;
+ delete noiseindev_float_islands2;
+ delete noiseindev_float_islands3;
+ delete noiseindev_biome;
+}
+
+void MapgenIndev::calculateNoise() {
+ int x = node_min.X;
+ int y = node_min.Y;
+ int z = node_min.Z;
+ // Need to adjust for the original implementation's +.5 offset...
+ if (!(flags & MG_FLAT)) {
+ noiseindev_terrain_base->perlinMap2D(
+ x + 0.5 * noiseindev_terrain_base->npindev->spread.X * farscale(noiseindev_terrain_base->npindev->farspread, x, z),
+ z + 0.5 * noiseindev_terrain_base->npindev->spread.Z * farscale(noiseindev_terrain_base->npindev->farspread, x, z));
+ noiseindev_terrain_base->transformNoiseMapFarScale(x, y, z);
+
+ noiseindev_terrain_higher->perlinMap2D(
+ x + 0.5 * noiseindev_terrain_higher->npindev->spread.X * farscale(noiseindev_terrain_higher->npindev->farspread, x, z),
+ z + 0.5 * noiseindev_terrain_higher->npindev->spread.Z * farscale(noiseindev_terrain_higher->npindev->farspread, x, z));
+ noiseindev_terrain_higher->transformNoiseMapFarScale(x, y, z);
+
+ noiseindev_steepness->perlinMap2D(
+ x + 0.5 * noiseindev_steepness->npindev->spread.X * farscale(noiseindev_steepness->npindev->farspread, x, z),
+ z + 0.5 * noiseindev_steepness->npindev->spread.Z * farscale(noiseindev_steepness->npindev->farspread, x, z));
+ noiseindev_steepness->transformNoiseMapFarScale(x, y, z);
+
+ noise_height_select->perlinMap2D(
+ x + 0.5 * noise_height_select->np->spread.X,
+ z + 0.5 * noise_height_select->np->spread.Z);
+
+ noiseindev_float_islands1->perlinMap3D(
+ x + 0.33 * noiseindev_float_islands1->npindev->spread.X * farscale(noiseindev_float_islands1->npindev->farspread, x, y, z),
+ y + 0.33 * noiseindev_float_islands1->npindev->spread.Y * farscale(noiseindev_float_islands1->npindev->farspread, x, y, z),
+ z + 0.33 * noiseindev_float_islands1->npindev->spread.Z * farscale(noiseindev_float_islands1->npindev->farspread, x, y, z)
+ );
+ noiseindev_float_islands1->transformNoiseMapFarScale(x, y, z);
+
+ noiseindev_float_islands2->perlinMap3D(
+ x + 0.33 * noiseindev_float_islands2->npindev->spread.X * farscale(noiseindev_float_islands2->npindev->farspread, x, y, z),
+ y + 0.33 * noiseindev_float_islands2->npindev->spread.Y * farscale(noiseindev_float_islands2->npindev->farspread, x, y, z),
+ z + 0.33 * noiseindev_float_islands2->npindev->spread.Z * farscale(noiseindev_float_islands2->npindev->farspread, x, y, z)
+ );
+ noiseindev_float_islands2->transformNoiseMapFarScale(x, y, z);
+
+ noiseindev_float_islands3->perlinMap2D(
+ x + 0.5 * noiseindev_float_islands3->npindev->spread.X * farscale(noiseindev_float_islands3->npindev->farspread, x, z),
+ z + 0.5 * noiseindev_float_islands3->npindev->spread.Z * farscale(noiseindev_float_islands3->npindev->farspread, x, z));
+ noiseindev_float_islands3->transformNoiseMapFarScale(x, y, z);
+
+ }
+
+ if (!(flags & MG_FLAT)) {
+ noiseindev_mud->perlinMap2D(
+ x + 0.5 * noiseindev_mud->npindev->spread.X * farscale(noiseindev_mud->npindev->farspread, x, y, z),
+ z + 0.5 * noiseindev_mud->npindev->spread.Z * farscale(noiseindev_mud->npindev->farspread, x, y, z));
+ noiseindev_mud->transformNoiseMapFarScale(x, y, z);
+ }
+ noise_beach->perlinMap2D(
+ x + 0.2 * noise_beach->np->spread.X,
+ z + 0.7 * noise_beach->np->spread.Z);
+
+ noise_biome->perlinMap2D(
+ x + 0.6 * noiseindev_biome->npindev->spread.X * farscale(noiseindev_biome->npindev->farspread, x, z),
+ z + 0.2 * noiseindev_biome->npindev->spread.Z * farscale(noiseindev_biome->npindev->farspread, x, z));
+}
+
+bool MapgenIndevParams::readParams(Settings *settings) {
+ freq_desert = settings->getFloat("mgv6_freq_desert");
+ freq_beach = settings->getFloat("mgv6_freq_beach");
+
+ npindev_terrain_base = settings->getNoiseIndevParams("mgindev_np_terrain_base");
+ npindev_terrain_higher = settings->getNoiseIndevParams("mgindev_np_terrain_higher");
+ npindev_steepness = settings->getNoiseIndevParams("mgindev_np_steepness");
+ np_height_select = settings->getNoiseParams("mgv6_np_height_select");
+ np_trees = settings->getNoiseParams("mgv6_np_trees");
+ npindev_mud = settings->getNoiseIndevParams("mgindev_np_mud");
+ np_beach = settings->getNoiseParams("mgv6_np_beach");
+ npindev_biome = settings->getNoiseIndevParams("mgindev_np_biome");
+ np_cave = settings->getNoiseParams("mgv6_np_cave");
+ npindev_float_islands1 = settings->getNoiseIndevParams("mgindev_np_float_islands1");
+ npindev_float_islands2 = settings->getNoiseIndevParams("mgindev_np_float_islands2");
+ npindev_float_islands3 = settings->getNoiseIndevParams("mgindev_np_float_islands3");
+
+ bool success =
+ npindev_terrain_base && npindev_terrain_higher && npindev_steepness &&
+ np_height_select && np_trees && npindev_mud &&
+ np_beach && np_biome && np_cave &&
+ npindev_float_islands1 && npindev_float_islands2 && npindev_float_islands3;
+ return success;
+}
+
+void MapgenIndevParams::writeParams(Settings *settings) {
+ settings->setFloat("mgv6_freq_desert", freq_desert);
+ settings->setFloat("mgv6_freq_beach", freq_beach);
+
+ settings->setNoiseIndevParams("mgindev_np_terrain_base", npindev_terrain_base);
+ settings->setNoiseIndevParams("mgindev_np_terrain_higher", npindev_terrain_higher);
+ settings->setNoiseIndevParams("mgindev_np_steepness", npindev_steepness);
+ settings->setNoiseParams("mgv6_np_height_select", np_height_select);
+ settings->setNoiseParams("mgv6_np_trees", np_trees);
+ settings->setNoiseIndevParams("mgindev_np_mud", npindev_mud);
+ settings->setNoiseParams("mgv6_np_beach", np_beach);
+ settings->setNoiseIndevParams("mgindev_np_biome", npindev_biome);
+ settings->setNoiseParams("mgv6_np_cave", np_cave);
+ settings->setNoiseIndevParams("mgindev_np_float_islands1", npindev_float_islands1);
+ settings->setNoiseIndevParams("mgindev_np_float_islands2", npindev_float_islands2);
+ settings->setNoiseIndevParams("mgindev_np_float_islands3", npindev_float_islands3);
+}
+
+
+float MapgenIndev::baseTerrainLevelFromNoise(v2s16 p) {
+ if (flags & MG_FLAT)
+ return water_level;
+
+ float terrain_base = NoisePerlin2DPosOffset(noiseindev_terrain_base->npindev,
+ p.X, 0.5, p.Y, 0.5, seed);
+ float terrain_higher = NoisePerlin2DPosOffset(noiseindev_terrain_higher->npindev,
+ p.X, 0.5, p.Y, 0.5, seed);
+ float steepness = NoisePerlin2DPosOffset(noiseindev_steepness->npindev,
+ p.X, 0.5, p.Y, 0.5, seed);
+ float height_select = NoisePerlin2DNoTxfmPosOffset(noise_height_select->np,
+ p.X, 0.5, p.Y, 0.5, seed);
+
+ return baseTerrainLevel(terrain_base, terrain_higher,
+ steepness, height_select);
+}
+
+float MapgenIndev::baseTerrainLevelFromMap(int index) {
+ if (flags & MG_FLAT)
+ return water_level;
+
+ float terrain_base = noiseindev_terrain_base->result[index];
+ float terrain_higher = noiseindev_terrain_higher->result[index];
+ float steepness = noiseindev_steepness->result[index];
+ float height_select = noise_height_select->result[index];
+
+ return baseTerrainLevel(terrain_base, terrain_higher,
+ steepness, height_select);
+}
+
+float MapgenIndev::getMudAmount(int index) {
+ if (flags & MG_FLAT)
+ return AVERAGE_MUD_AMOUNT;
+
+ /*return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
+ 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
+ seed+91013, 3, 0.55));*/
+
+ return noiseindev_mud->result[index];
+}
+
+void MapgenIndev::defineCave(Cave & cave, PseudoRandom ps, v3s16 node_min, bool large_cave) {
+ cave.min_tunnel_diameter = 2;
+ cave.max_tunnel_diameter = ps.range(2,6);
+ cave.dswitchint = ps.range(1,14);
+ cave.flooded = large_cave && ps.range(0,4);
+ if(large_cave){
+ cave.part_max_length_rs = ps.range(2,4);
+ if (node_min.Y < -100 && !ps.range(0, farscale(0.2, node_min.X,node_min.Y,node_min.Z)*30)) { //huge
+ cave.flooded = !ps.range(0, 3);
+ cave.tunnel_routepoints = ps.range(5, 20);
+ cave.min_tunnel_diameter = 30;
+ cave.max_tunnel_diameter = ps.range(40, ps.range(80,120));
+ } else {
+ cave.tunnel_routepoints = ps.range(5, ps.range(15,30));
+ cave.min_tunnel_diameter = 5;
+ cave.max_tunnel_diameter = ps.range(7, ps.range(8,24));
+ }
+ } else {
+ cave.part_max_length_rs = ps.range(2,9);
+ cave.tunnel_routepoints = ps.range(10, ps.range(15,30));
+ }
+ cave.large_cave_is_flat = (ps.range(0,1) == 0);
+}
+
+/*
+// version with one perlin3d. use with good params like
+settings->setDefault("mgindev_np_float_islands1", "-9.5, 10, (20, 50, 50 ), 45123, 5, 0.6, 1.5, 5");
+void MapgenIndev::generateFloatIslands(int min_y) {
+ if (node_min.Y < min_y) return;
+ v3s16 p0(node_min.X, node_min.Y, node_min.Z);
+ MapNode n1(c_stone), n2(c_desert_stone);
+ int xl = node_max.X - node_min.X;
+ int yl = node_max.Y - node_min.Y;
+ int zl = node_max.Z - node_min.Z;
+ u32 index = 0;
+ for (int x1 = 0; x1 <= xl; x1++)
+ {
+ //int x = x1 + node_min.Y;
+ for (int z1 = 0; z1 <= zl; z1++)
+ {
+ //int z = z1 + node_min.Z;
+ for (int y1 = 0; y1 <= yl; y1++, index++)
+ {
+ //int y = y1 + node_min.Y;
+ float noise = noiseindev_float_islands1->result[index];
+ //dstream << " y1="<<y1<< " x1="<<x1<<" z1="<<z1<< " noise="<<noise << std::endl;
+ if (noise > 0 ) {
+ v3s16 p = p0 + v3s16(x1, y1, z1);
+ u32 i = vm->m_area.index(p);
+ if (!vm->m_area.contains(i))
+ continue;
+ // Cancel if not air
+ if (vm->m_data[i].getContent() != CONTENT_AIR)
+ continue;
+ vm->m_data[i] = noise > 1 ? n1 : n2;
+ }
+ }
+ }
+ }
+}
+*/
+
+void MapgenIndev::generateFloatIslands(int min_y) {
+ if (node_min.Y < min_y) return;
+ PseudoRandom pr(blockseed + 985);
+ // originally from http://forum.minetest.net/viewtopic.php?id=4776
+ float RAR = 0.8 * farscale(0.4, node_min.Y); // 0.4; // Island rarity in chunk layer. -0.4 = thick layer with holes, 0 = 50%, 0.4 = desert rarity, 0.7 = very rare.
+ float AMPY = 24; // 24; // Amplitude of island centre y variation.
+ float TGRAD = 24; // 24; // Noise gradient to create top surface. Tallness of island top.
+ float BGRAD = 24; // 24; // Noise gradient to create bottom surface. Tallness of island bottom.
+
+ v3s16 p0(node_min.X, node_min.Y, node_min.Z);
+ MapNode n1(c_stone);
+
+ float xl = node_max.X - node_min.X;
+ float yl = node_max.Y - node_min.Y;
+ float zl = node_max.Z - node_min.Z;
+ float midy = node_min.Y + yl * 0.5;
+ u32 index = 0, index2d = 0;
+ for (int x1 = 0; x1 <= xl; ++x1)
+ {
+ for (int z1 = 0; z1 <= zl; ++z1, ++index2d)
+ {
+ float noise3 = noiseindev_float_islands3->result[index2d];
+ float pmidy = midy + noise3 / 1.5 * AMPY;
+ for (int y1 = 0; y1 <= yl; ++y1, ++index)
+ {
+ int y = y1 + node_min.Y;
+ float noise1 = noiseindev_float_islands1->result[index];
+ float offset = y > pmidy ? (y - pmidy) / TGRAD : (pmidy - y) / BGRAD;
+ float noise1off = noise1 - offset - RAR;
+ if (noise1off > 0 && noise1off < 0.7) {
+ float noise2 = noiseindev_float_islands2->result[index];
+ if (noise2 - noise1off > -0.7){
+ v3s16 p = p0 + v3s16(x1, y1, z1);
+ u32 i = vm->m_area.index(p);
+ if (!vm->m_area.contains(i))
+ continue;
+ // Cancel if not air
+ if (vm->m_data[i].getContent() != CONTENT_AIR)
+ continue;
+ vm->m_data[i] = n1;
+ }
+ }
+ }
+ }
+ }
+}
+
+void MapgenIndev::generateSomething() {
+ int float_islands = g_settings->getS16("mgindev_float_islands");
+ if(float_islands) generateFloatIslands(float_islands);
+}
diff --git a/src/mapgen_indev.h b/src/mapgen_indev.h
new file mode 100644
index 000000000..fdac1ba20
--- /dev/null
+++ b/src/mapgen_indev.h
@@ -0,0 +1,152 @@
+/*
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef MAPGENINDEV_HEADER
+#define MAPGENINDEV_HEADER
+
+#include "mapgen.h"
+#include "mapgen_v6.h"
+
+float farscale(float scale, float z);
+float farscale(float scale, float x, float z);
+float farscale(float scale, float x, float y, float z);
+
+struct NoiseIndevParams : public NoiseParams {
+ float farscale;
+ float farspread;
+
+ NoiseIndevParams(){}
+ NoiseIndevParams(float offset_, float scale_, v3f spread_, int seed_, int octaves_, float persist_, float farscale_ = 1, float farspread_ = 1)
+ {
+ offset = offset_;
+ scale = scale_;
+ spread = spread_;
+ seed = seed_;
+ octaves = octaves_;
+ persist = persist_;
+
+ farscale = farscale_;
+ farspread = farspread_;
+ }
+
+};
+
+#define getNoiseIndevParams(x) getStruct<NoiseIndevParams>((x), "f,f,v3,s32,s32,f,f,f")
+#define setNoiseIndevParams(x, y) setStruct((x), "f,f,v3,s32,s32,f,f,f", (y))
+
+class NoiseIndev : public Noise {
+ public:
+ NoiseIndevParams *npindev;
+
+ //NoiseIndev() {};
+ NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy);
+ NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy, int sz);
+ void init(NoiseIndevParams *np, int seed, int sx, int sy, int sz);
+ void transformNoiseMapFarScale(float xx = 0, float yy = 0, float zz = 0);
+};
+
+extern NoiseIndevParams nparams_indev_def;
+/*
+extern NoiseIndevParams nparams_indev_def_terrain_base;
+extern NoiseIndevParams nparams_indev_def_terrain_higher;
+extern NoiseIndevParams nparams_indev_def_steepness;
+//extern NoiseIndevParams nparams_indev_def_height_select;
+//extern NoiseIndevParams nparams_indev_def_trees;
+extern NoiseIndevParams nparams_indev_def_mud;
+//extern NoiseIndevParams nparams_indev_def_beach;
+extern NoiseIndevParams nparams_indev_def_biome;
+//extern NoiseIndevParams nparams_indev_def_cave;
+extern NoiseIndevParams nparams_indev_def_float_islands;
+*/
+
+struct MapgenIndevParams : public MapgenV6Params {
+ NoiseIndevParams *npindev_terrain_base;
+ NoiseIndevParams *npindev_terrain_higher;
+ NoiseIndevParams *npindev_steepness;
+ //NoiseParams *np_height_select;
+ //NoiseParams *np_trees;
+ NoiseIndevParams *npindev_mud;
+ //NoiseParams *np_beach;
+ NoiseIndevParams *npindev_biome;
+ //NoiseParams *np_cave;
+ NoiseIndevParams *npindev_float_islands1;
+ NoiseIndevParams *npindev_float_islands2;
+ NoiseIndevParams *npindev_float_islands3;
+
+ MapgenIndevParams() {
+ //freq_desert = 0.45;
+ //freq_beach = 0.15;
+ npindev_terrain_base = &nparams_indev_def; //&nparams_indev_def_terrain_base;
+ npindev_terrain_higher = &nparams_indev_def; //&nparams_indev_def_terrain_higher;
+ npindev_steepness = &nparams_indev_def; //&nparams_indev_def_steepness;
+ //np_height_select = &nparams_v6_def_height_select;
+ //np_trees = &nparams_v6_def_trees;
+ npindev_mud = &nparams_indev_def; //&nparams_indev_def_mud;
+ //np_beach = &nparams_v6_def_beach;
+ npindev_biome = &nparams_indev_def; //&nparams_indev_def_biome;
+ //np_cave = &nparams_v6_def_cave;
+ npindev_float_islands1 = &nparams_indev_def; //&nparams_indev_def_float_islands;
+ npindev_float_islands2 = &nparams_indev_def; //&nparams_indev_def_float_islands;
+ npindev_float_islands3 = &nparams_indev_def; //&nparams_indev_def_float_islands;
+
+ }
+
+ bool readParams(Settings *settings);
+ void writeParams(Settings *settings);
+};
+
+class MapgenIndev : public MapgenV6 {
+ public:
+ NoiseIndev *noiseindev_terrain_base;
+ NoiseIndev *noiseindev_terrain_higher;
+ NoiseIndev *noiseindev_steepness;
+ //NoiseIndev *noise_height_select;
+ //NoiseIndev *noise_trees;
+ NoiseIndev *noiseindev_mud;
+ //NoiseIndev *noise_beach;
+ NoiseIndev *noiseindev_biome;
+ //NoiseIndevParams *np_cave;
+ NoiseIndev *noiseindev_float_islands1;
+ NoiseIndev *noiseindev_float_islands2;
+ NoiseIndev *noiseindev_float_islands3;
+
+ MapgenIndev(int mapgenid, MapgenIndevParams *params, EmergeManager *emerge);
+ ~MapgenIndev();
+ void calculateNoise();
+
+ float baseTerrainLevelFromNoise(v2s16 p);
+ float baseTerrainLevelFromMap(int index);
+ float getMudAmount(int index);
+ void defineCave(Cave & cave, PseudoRandom ps, v3s16 node_min, bool large_cave);
+ void generateSomething();
+
+ void generateFloatIslands(int min_y);
+};
+
+struct MapgenFactoryIndev : public MapgenFactoryV6 {
+ Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
+ return new MapgenIndev(mgid, (MapgenIndevParams *)params, emerge);
+ };
+
+ MapgenParams *createMapgenParams() {
+ return new MapgenIndevParams();
+ };
+};
+
+#endif
diff --git a/src/mapgen_singlenode.cpp b/src/mapgen_singlenode.cpp
new file mode 100644
index 000000000..22b756abb
--- /dev/null
+++ b/src/mapgen_singlenode.cpp
@@ -0,0 +1,102 @@
+/*
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "mapgen_singlenode.h"
+#include "voxel.h"
+#include "mapblock.h"
+#include "mapnode.h"
+#include "map.h"
+#include "nodedef.h"
+#include "voxelalgorithms.h"
+#include "profiler.h"
+#include "settings.h" // For g_settings
+#include "main.h" // For g_profiler
+#include "emerge.h"
+
+//////////////////////// Mapgen Singlenode parameter read/write
+
+bool MapgenSinglenodeParams::readParams(Settings *settings) {
+ return true;
+}
+
+
+void MapgenSinglenodeParams::writeParams(Settings *settings) {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+MapgenSinglenode::MapgenSinglenode(int mapgenid, MapgenSinglenodeParams *params) {
+}
+
+
+MapgenSinglenode::~MapgenSinglenode() {
+}
+
+//////////////////////// Map generator
+
+void MapgenSinglenode::makeChunk(BlockMakeData *data) {
+ assert(data->vmanip);
+ assert(data->nodedef);
+ assert(data->blockpos_requested.X >= data->blockpos_min.X &&
+ data->blockpos_requested.Y >= data->blockpos_min.Y &&
+ data->blockpos_requested.Z >= data->blockpos_min.Z);
+ assert(data->blockpos_requested.X <= data->blockpos_max.X &&
+ data->blockpos_requested.Y <= data->blockpos_max.Y &&
+ data->blockpos_requested.Z <= data->blockpos_max.Z);
+
+ this->generating = true;
+ this->vm = data->vmanip;
+ this->ndef = data->nodedef;
+
+ v3s16 blockpos_min = data->blockpos_min;
+ v3s16 blockpos_max = data->blockpos_max;
+
+ // Area of central chunk
+ v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
+ v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
+
+ content_t c_node = ndef->getId("mapgen_singlenode");
+ if (c_node == CONTENT_IGNORE)
+ c_node = CONTENT_AIR;
+
+ MapNode n_node(c_node);
+
+ for (s16 z = node_min.Z; z <= node_max.Z; z++)
+ for (s16 y = node_min.Y; y <= node_max.Y; y++) {
+ u32 i = vm->m_area.index(node_min.X, y, z);
+ for (s16 x = node_min.X; x <= node_max.X; x++) {
+ if (vm->m_data[i].getContent() == CONTENT_IGNORE)
+ vm->m_data[i] = n_node;
+ i++;
+ }
+ }
+
+ // Add top and bottom side of water to transforming_liquid queue
+ updateLiquid(&data->transforming_liquid, node_min, node_max);
+
+ // Calculate lighting
+ calcLighting(node_min, node_max);
+
+ this->generating = false;
+}
+
+int MapgenSinglenode::getGroundLevelAtPoint(v2s16 p) {
+ return 0;
+}
+
diff --git a/src/mapgen_singlenode.h b/src/mapgen_singlenode.h
new file mode 100644
index 000000000..b86c9a77f
--- /dev/null
+++ b/src/mapgen_singlenode.h
@@ -0,0 +1,53 @@
+/*
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef MAPGEN_SINGLENODE_HEADER
+#define MAPGEN_SINGLENODE_HEADER
+
+#include "mapgen.h"
+
+struct MapgenSinglenodeParams : public MapgenParams {
+
+ MapgenSinglenodeParams() {
+ }
+
+ bool readParams(Settings *settings);
+ void writeParams(Settings *settings);
+};
+
+class MapgenSinglenode : public Mapgen {
+public:
+ MapgenSinglenode(int mapgenid, MapgenSinglenodeParams *params);
+ ~MapgenSinglenode();
+
+ void makeChunk(BlockMakeData *data);
+ int getGroundLevelAtPoint(v2s16 p);
+};
+
+struct MapgenFactorySinglenode : public MapgenFactory {
+ Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
+ return new MapgenSinglenode(mgid, (MapgenSinglenodeParams *)params);
+ };
+
+ MapgenParams *createMapgenParams() {
+ return new MapgenSinglenodeParams();
+ };
+};
+
+#endif
diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp
index d5405876e..0b419617d 100644
--- a/src/mapgen_v6.cpp
+++ b/src/mapgen_v6.cpp
@@ -32,6 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" // For g_settings
#include "main.h" // For g_profiler
#include "emerge.h"
+#include "dungeongen.h"
+#include "treegen.h"
#include "mapgen_v6.h"
/////////////////// Mapgen V6 perlin noise default values
@@ -43,8 +45,6 @@ NoiseParams nparams_v6_def_steepness =
{0.85, 0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7};
NoiseParams nparams_v6_def_height_select =
{0.5, 1.0, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69};
-NoiseParams nparams_v6_def_trees =
- {0.0, 1.0, v3f(125.0, 125.0, 125.0), 2, 4, 0.66};
NoiseParams nparams_v6_def_mud =
{AVERAGE_MUD_AMOUNT, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55};
NoiseParams nparams_v6_def_beach =
@@ -53,14 +53,21 @@ NoiseParams nparams_v6_def_biome =
{0.0, 1.0, v3f(250.0, 250.0, 250.0), 9130, 3, 0.50};
NoiseParams nparams_v6_def_cave =
{6.0, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50};
+NoiseParams nparams_v6_def_humidity =
+ {0.5, 0.5, v3f(500.0, 500.0, 500.0), 72384, 4, 0.66};
+NoiseParams nparams_v6_def_trees =
+ {0.0, 1.0, v3f(125.0, 125.0, 125.0), 2, 4, 0.66};
+NoiseParams nparams_v6_def_apple_trees =
+ {0.0, 1.0, v3f(100.0, 100.0, 100.0), 342902, 3, 0.45};
///////////////////////////////////////////////////////////////////////////////
-MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params) {
+MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge) {
this->generating = false;
this->id = mapgenid;
+ this->emerge = emerge;
this->seed = (int)params->seed;
this->water_level = params->water_level;
@@ -72,25 +79,18 @@ MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params) {
this->ystride = csize.X; //////fix this
- np_cave = params->np_cave;
+ np_cave = params->np_cave;
+ np_humidity = params->np_humidity;
+ np_trees = params->np_trees;
+ np_apple_trees = params->np_apple_trees;
noise_terrain_base = new Noise(params->np_terrain_base, seed, csize.X, csize.Y);
noise_terrain_higher = new Noise(params->np_terrain_higher, seed, csize.X, csize.Y);
noise_steepness = new Noise(params->np_steepness, seed, csize.X, csize.Y);
noise_height_select = new Noise(params->np_height_select, seed, csize.X, csize.Y);
- noise_trees = new Noise(params->np_trees, seed, csize.X, csize.Y);
noise_mud = new Noise(params->np_mud, seed, csize.X, csize.Y);
noise_beach = new Noise(params->np_beach, seed, csize.X, csize.Y);
noise_biome = new Noise(params->np_biome, seed, csize.X, csize.Y);
-
- map_terrain_base = noise_terrain_base->result;
- map_terrain_higher = noise_terrain_higher->result;
- map_steepness = noise_steepness->result;
- map_height_select = noise_height_select->result;
- map_trees = noise_trees->result;
- map_mud = noise_mud->result;
- map_beach = noise_beach->result;
- map_biome = noise_biome->result;
}
@@ -99,169 +99,53 @@ MapgenV6::~MapgenV6() {
delete noise_terrain_higher;
delete noise_steepness;
delete noise_height_select;
- delete noise_trees;
delete noise_mud;
delete noise_beach;
delete noise_biome;
}
-/*
- Some helper functions for the map generator
-*/
+//////////////////////// Some helper functions for the map generator
-#if 1
// Returns Y one under area minimum if not found
-s16 MapgenV6::find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
- INodeDefManager *ndef)
-{
- v3s16 em = vmanip.m_area.getExtent();
- s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
- s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
+s16 MapgenV6::find_ground_level(v2s16 p2d) {
+ v3s16 em = vm->m_area.getExtent();
+ s16 y_nodes_max = vm->m_area.MaxEdge.Y;
+ s16 y_nodes_min = vm->m_area.MinEdge.Y;
+ u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
s16 y;
- for(y=y_nodes_max; y>=y_nodes_min; y--)
- {
- MapNode &n = vmanip.m_data[i];
+
+ for (y = y_nodes_max; y >= y_nodes_min; y--) {
+ MapNode &n = vm->m_data[i];
if(ndef->get(n).walkable)
break;
- vmanip.m_area.add_y(em, i, -1);
+ vm->m_area.add_y(em, i, -1);
}
- if(y >= y_nodes_min)
- return y;
- else
- return y_nodes_min - 1;
+ return (y >= y_nodes_min) ? y : y_nodes_min - 1;
}
// Returns Y one under area minimum if not found
-s16 MapgenV6::find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
- INodeDefManager *ndef)
-{
- v3s16 em = vmanip.m_area.getExtent();
- s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
- s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
+s16 MapgenV6::find_stone_level(v2s16 p2d) {
+ v3s16 em = vm->m_area.getExtent();
+ s16 y_nodes_max = vm->m_area.MaxEdge.Y;
+ s16 y_nodes_min = vm->m_area.MinEdge.Y;
+ u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
s16 y;
- content_t c_stone = ndef->getId("mapgen_stone");
- content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
- for(y=y_nodes_max; y>=y_nodes_min; y--)
- {
- MapNode &n = vmanip.m_data[i];
+
+ for (y = y_nodes_max; y >= y_nodes_min; y--) {
+ MapNode &n = vm->m_data[i];
content_t c = n.getContent();
- if(c != CONTENT_IGNORE && (
- c == c_stone || c == c_desert_stone))
+ if (c != CONTENT_IGNORE && (
+ c == c_stone || c == c_desert_stone))
break;
- vmanip.m_area.add_y(em, i, -1);
- }
- if(y >= y_nodes_min)
- return y;
- else
- return y_nodes_min - 1;
-}
-#endif
-
-void MapgenV6::make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
- bool is_apple_tree, INodeDefManager *ndef)
-{
- MapNode treenode(ndef->getId("mapgen_tree"));
- MapNode leavesnode(ndef->getId("mapgen_leaves"));
- MapNode applenode(ndef->getId("mapgen_apple"));
-
- s16 trunk_h = myrand_range(4, 5);
- v3s16 p1 = p0;
- for(s16 ii=0; ii<trunk_h; ii++)
- {
- if(vmanip.m_area.contains(p1))
- vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
- p1.Y++;
- }
-
- // p1 is now the last piece of the trunk
- p1.Y -= 1;
-
- VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
- //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
- Buffer<u8> leaves_d(leaves_a.getVolume());
- for(s32 i=0; i<leaves_a.getVolume(); i++)
- leaves_d[i] = 0;
-
- // Force leaves at near the end of the trunk
- {
- s16 d = 1;
- for(s16 z=-d; z<=d; z++)
- for(s16 y=-d; y<=d; y++)
- for(s16 x=-d; x<=d; x++)
- {
- leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
- }
- }
-
- // Add leaves randomly
- for(u32 iii=0; iii<7; iii++)
- {
- s16 d = 1;
-
- v3s16 p(
- myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
- myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
- myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
- );
-
- for(s16 z=0; z<=d; z++)
- for(s16 y=0; y<=d; y++)
- for(s16 x=0; x<=d; x++)
- {
- leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
- }
- }
-
- // Blit leaves to vmanip
- for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
- for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
- for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
- {
- v3s16 p(x,y,z);
- p += p1;
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() != CONTENT_AIR
- && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
- continue;
- u32 i = leaves_a.index(x,y,z);
- if(leaves_d[i] == 1) {
- bool is_apple = myrand_range(0,99) < 10;
- if(is_apple_tree && is_apple) {
- vmanip.m_data[vi] = applenode;
- } else {
- vmanip.m_data[vi] = leavesnode;
- }
- }
+ vm->m_area.add_y(em, i, -1);
}
+ return (y >= y_nodes_min) ? y : y_nodes_min - 1;
}
-/*
- Noise functions. Make sure seed is mangled differently in each one.
-*/
-
-
-// Amount of trees per area in nodes
-double MapgenV6::tree_amount_2d(u64 seed, v2s16 p)
-{
- /*double noise = noise2d_perlin(
- 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
- seed+2, 4, 0.66);*/
- double noise = map_trees[(p.Y - node_min.Z) * ystride + (p.X - node_min.X)];
- double zeroval = -0.39;
- if(noise < zeroval)
- return 0;
- else
- return 0.04 * (noise-zeroval) / (1.0-zeroval);
-}
-
// Required by mapgen.h
bool MapgenV6::block_is_underground(u64 seed, v3s16 blockpos)
{
@@ -277,105 +161,148 @@ bool MapgenV6::block_is_underground(u64 seed, v3s16 blockpos)
}
-double MapgenV6::base_rock_level_2d(u64 seed, v2s16 p)
-{
- if (flags & MG_FLAT)
- return water_level;
-
- int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
-
- // The base ground level
- /*double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
- + 20. * noise2d_perlin(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed+82341, 5, 0.6);*/
- double base = water_level + map_terrain_base[index];
+//////////////////////// Base terrain height functions
- // Higher ground level
- /*double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
- 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
- seed+85039, 5, 0.6);*/
- double higher = water_level + map_terrain_higher[index];
+float MapgenV6::baseTerrainLevel(float terrain_base, float terrain_higher,
+ float steepness, float height_select) {
+ float base = water_level + terrain_base;
+ float higher = water_level + terrain_higher;
- // Limit higher to at least base
+ // Limit higher ground level to at least base
if(higher < base)
higher = base;
// Steepness factor of cliffs
- /*double b = 0.85 + 0.5 * noise2d_perlin(
- 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
- seed-932, 5, 0.7);*/
- double b = map_steepness[index];
+ float b = steepness;
b = rangelim(b, 0.0, 1000.0);
- b = pow(b, 7);
- b *= 5;
+ b = 5 * b * b * b * b * b * b * b;
b = rangelim(b, 0.5, 1000.0);
// Values 1.5...100 give quite horrible looking slopes
- if(b > 1.5 && b < 100.0){
- if(b < 10.0)
- b = 1.5;
- else
- b = 100.0;
- }
+ if (b > 1.5 && b < 100.0)
+ b = (b < 10.0) ? 1.5 : 100.0;
- // Offset to more low
- double a_off = -0.20;
+ float a_off = -0.20; // Offset to more low
+ float a = 0.5 + b * (a_off + height_select);
+ a = rangelim(a, 0.0, 1.0); // Limit
+
+ return base * (1.0 - a) + higher * a;
+}
- // High/low selector
- /*double a = (double)0.5 + b * (a_off + noise2d_perlin(
- 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
- seed+4213, 5, 0.69));*/
- double a = 0.5 + b * (a_off + map_height_select[index]);
- // Limit
- a = rangelim(a, 0.0, 1.0);
+float MapgenV6::baseTerrainLevelFromNoise(v2s16 p) {
+ if (flags & MG_FLAT)
+ return water_level;
+
+ float terrain_base = NoisePerlin2DPosOffset(noise_terrain_base->np,
+ p.X, 0.5, p.Y, 0.5, seed);
+ float terrain_higher = NoisePerlin2DPosOffset(noise_terrain_higher->np,
+ p.X, 0.5, p.Y, 0.5, seed);
+ float steepness = NoisePerlin2DPosOffset(noise_steepness->np,
+ p.X, 0.5, p.Y, 0.5, seed);
+ float height_select = NoisePerlin2DNoTxfmPosOffset(noise_height_select->np,
+ p.X, 0.5, p.Y, 0.5, seed);
+
+ return baseTerrainLevel(terrain_base, terrain_higher,
+ steepness, height_select);
+}
- double h = base*(1.0-a) + higher*a;
- return h;
+float MapgenV6::baseTerrainLevelFromMap(v2s16 p) {
+ int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
+ return baseTerrainLevelFromMap(index);
}
-double MapgenV6::baseRockLevelFromNoise(v2s16 p) {
+
+float MapgenV6::baseTerrainLevelFromMap(int index) {
if (flags & MG_FLAT)
return water_level;
- double base = water_level +
- NoisePerlin2DPosOffset(noise_terrain_base->np, p.X, 0.5, p.Y, 0.5, seed);
- double higher = water_level +
- NoisePerlin2DPosOffset(noise_terrain_higher->np, p.X, 0.5, p.Y, 0.5, seed);
+ float terrain_base = noise_terrain_base->result[index];
+ float terrain_higher = noise_terrain_higher->result[index];
+ float steepness = noise_steepness->result[index];
+ float height_select = noise_height_select->result[index];
+
+ return baseTerrainLevel(terrain_base, terrain_higher,
+ steepness, height_select);
+}
- if (higher < base)
- higher = base;
- double b = NoisePerlin2DPosOffset(noise_steepness->np, p.X, 0.5, p.Y, 0.5, seed);
- b = rangelim(b, 0.0, 1000.0);
- b = b*b*b*b*b*b*b;
- b *= 5;
- b = rangelim(b, 0.5, 1000.0);
+s16 MapgenV6::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
+ return baseTerrainLevelFromNoise(p2d) + AVERAGE_MUD_AMOUNT;
+}
- if(b > 1.5 && b < 100.0){
- if(b < 10.0)
- b = 1.5;
- else
- b = 100.0;
- }
-
- double a_off = -0.20;
- double a = 0.5 + b * (a_off + NoisePerlin2DNoTxfmPosOffset(
- noise_height_select->np, p.X, 0.5, p.Y, 0.5, seed));
- a = rangelim(a, 0.0, 1.0);
- return base * (1.0 - a) + higher * a;
+int MapgenV6::getGroundLevelAtPoint(v2s16 p) {
+ return baseTerrainLevelFromNoise(p) + AVERAGE_MUD_AMOUNT;
}
-s16 MapgenV6::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
+//////////////////////// Noise functions
+
+float MapgenV6::getMudAmount(v2s16 p) {
+ int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
+ return getMudAmount(index);
+}
+
+
+bool MapgenV6::getHaveBeach(v2s16 p) {
+ int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
+ return getHaveBeach(index);
+}
+
+
+BiomeType MapgenV6::getBiome(v2s16 p) {
+ int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
+ return getBiome(index, p);
+}
+
+
+float MapgenV6::getHumidity(v2s16 p)
{
- return baseRockLevelFromNoise(p2d) + AVERAGE_MUD_AMOUNT;
+ /*double noise = noise2d_perlin(
+ 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
+ seed+72384, 4, 0.66);
+ noise = (noise + 1.0)/2.0;*/
+
+ float noise = NoisePerlin2D(np_humidity, p.X, p.Y, seed);
+
+ if (noise < 0.0)
+ noise = 0.0;
+ if (noise > 1.0)
+ noise = 1.0;
+ return noise;
}
-double MapgenV6::get_mud_add_amount(u64 seed, v2s16 p)
+
+float MapgenV6::getTreeAmount(v2s16 p)
+{
+ /*double noise = noise2d_perlin(
+ 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
+ seed+2, 4, 0.66);*/
+
+ float noise = NoisePerlin2D(np_trees, p.X, p.Y, seed);
+ float zeroval = -0.39;
+ if (noise < zeroval)
+ return 0;
+ else
+ return 0.04 * (noise-zeroval) / (1.0-zeroval);
+}
+
+
+bool MapgenV6::getHaveAppleTree(v2s16 p)
+{
+ /*is_apple_tree = noise2d_perlin(
+ 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
+ data->seed+342902, 3, 0.45) > 0.2;*/
+
+ float noise = NoisePerlin2D(np_apple_trees, p.X, p.Y, seed);
+
+ return noise > 0.2;
+}
+
+
+float MapgenV6::getMudAmount(int index)
{
if (flags & MG_FLAT)
return AVERAGE_MUD_AMOUNT;
@@ -383,39 +310,42 @@ double MapgenV6::get_mud_add_amount(u64 seed, v2s16 p)
/*return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
0.5+(float)p.X/200, 0.5+(float)p.Y/200,
seed+91013, 3, 0.55));*/
- int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
- return map_mud[index];
+
+ return noise_mud->result[index];
}
-bool MapgenV6::get_have_beach(u64 seed, v2s16 p2d)
+
+bool MapgenV6::getHaveBeach(int index)
{
// Determine whether to have sand here
/*double sandnoise = noise2d_perlin(
0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
seed+59420, 3, 0.50);*/
- int index = (p2d.Y - node_min.Z) * ystride + (p2d.X - node_min.X);
- double sandnoise = map_beach[index];
-
+
+ float sandnoise = noise_beach->result[index];
return (sandnoise > freq_beach);
}
-BiomeType MapgenV6::get_biome(u64 seed, v2s16 p2d)
+
+BiomeType MapgenV6::getBiome(int index, v2s16 p)
{
// Just do something very simple as for now
/*double d = noise2d_perlin(
0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
seed+9130, 3, 0.50);*/
- int index = (p2d.Y - node_min.Z) * ystride + (p2d.X - node_min.X);
- double d = map_biome[index];
- if(d > freq_desert)
+
+ float d = noise_biome->result[index];
+ if (d > freq_desert)
return BT_DESERT;
- if (flags & MGV6_BIOME_BLEND) {
- if(d > freq_desert - 0.10 &&
- (noise2d(p2d.X, p2d.Y, seed) + 1.0) > (freq_desert - d) * 20.0)
- return BT_DESERT;
- }
+
+ if ((flags & MGV6_BIOME_BLEND) &&
+ (d > freq_desert - 0.10) &&
+ ((noise2d(p.X, p.Y, seed) + 1.0) > (freq_desert - d) * 20.0))
+ return BT_DESERT;
+
return BT_NORMAL;
-};
+}
+
u32 MapgenV6::get_blockseed(u64 seed, v3s16 p)
{
@@ -424,275 +354,622 @@ u32 MapgenV6::get_blockseed(u64 seed, v3s16 p)
}
-int MapgenV6::getGroundLevelAtPoint(v2s16 p) {
- return baseRockLevelFromNoise(p) + AVERAGE_MUD_AMOUNT;
-}
-
-#define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
-
-void MapgenV6::makeChunk(BlockMakeData *data)
-{
- this->generating = true;
+//////////////////////// Map generator
+void MapgenV6::makeChunk(BlockMakeData *data) {
assert(data->vmanip);
assert(data->nodedef);
assert(data->blockpos_requested.X >= data->blockpos_min.X &&
- data->blockpos_requested.Y >= data->blockpos_min.Y &&
- data->blockpos_requested.Z >= data->blockpos_min.Z);
+ data->blockpos_requested.Y >= data->blockpos_min.Y &&
+ data->blockpos_requested.Z >= data->blockpos_min.Z);
assert(data->blockpos_requested.X <= data->blockpos_max.X &&
- data->blockpos_requested.Y <= data->blockpos_max.Y &&
- data->blockpos_requested.Z <= data->blockpos_max.Z);
-
- INodeDefManager *ndef = data->nodedef;
-
- // Hack: use minimum block coordinates for old code that assumes
- // a single block
+ data->blockpos_requested.Y <= data->blockpos_max.Y &&
+ data->blockpos_requested.Z <= data->blockpos_max.Z);
+
+ this->generating = true;
+ this->vm = data->vmanip;
+ this->ndef = data->nodedef;
+
+ // Hack: use minimum block coords for old code that assumes a single block
v3s16 blockpos = data->blockpos_requested;
-
- /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
- <<blockpos.Z<<")"<<std::endl;*/
-
v3s16 blockpos_min = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max;
v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
- ManualMapVoxelManipulator &vmanip = *(data->vmanip);
// Area of central chunk
node_min = blockpos_min*MAP_BLOCKSIZE;
node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
+
// Full allocated area
- v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
- v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
+ full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
+ full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
- v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
+ central_area_size = node_max - node_min + v3s16(1,1,1);
+ assert(central_area_size.X == central_area_size.Z);
+
+ int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
+ * (blockpos_max.Y - blockpos_min.Y + 1)
+ * (blockpos_max.Z - blockpos_max.Z + 1);
+
+ volume_nodes = volume_blocks *
+ MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
+
+ // Create a block-specific seed
+ blockseed = get_blockseed(data->seed, full_node_min);
+
+ // Make some noise
+ calculateNoise();
+
+ c_stone = ndef->getId("mapgen_stone");
+ c_dirt = ndef->getId("mapgen_dirt");
+ c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass");
+ c_sand = ndef->getId("mapgen_sand");
+ c_water_source = ndef->getId("mapgen_water_source");
+ c_lava_source = ndef->getId("mapgen_lava_source");
+ c_gravel = ndef->getId("mapgen_gravel");
+ c_cobble = ndef->getId("mapgen_cobble");
+ c_desert_sand = ndef->getId("mapgen_desert_sand");
+ c_desert_stone = ndef->getId("mapgen_desert_stone");
+ if (c_desert_sand == CONTENT_IGNORE)
+ c_desert_sand = c_sand;
+ if (c_desert_stone == CONTENT_IGNORE)
+ c_desert_stone = c_stone;
+
+ // Maximum height of the stone surface and obstacles.
+ // This is used to guide the cave generation
+ s16 stone_surface_max_y;
+
+ // Generate general ground level to full area
+ stone_surface_max_y = generateGround();
+
+ generateSomething();
const s16 max_spread_amount = MAP_BLOCKSIZE;
+ // Limit dirt flow area by 1 because mud is flown into neighbors.
+ s16 mudflow_minpos = -max_spread_amount + 1;
+ s16 mudflow_maxpos = central_area_size.X + max_spread_amount - 2;
- int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
- * (blockpos_max.Y - blockpos_min.Y + 1)
- * (blockpos_max.Z - blockpos_max.Z + 1);
-
- int volume_nodes = volume_blocks *
- MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
- // Generated surface area
- //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
-
- // Horribly wrong heuristic, but better than nothing
- bool block_is_underground = (water_level > node_max.Y);
-
- /*
- Create a block-specific seed
- */
- u32 blockseed = get_blockseed(data->seed, full_node_min);
-
- /*
- Make some noise
- */
- {
- int x = node_min.X;
- int z = node_min.Z;
-
- // Need to adjust for the original implementation's +.5 offset...
- if (!(flags & MG_FLAT)) {
- noise_terrain_base->perlinMap2D(
- x + 0.5 * noise_terrain_base->np->spread.X,
- z + 0.5 * noise_terrain_base->np->spread.Z);
- noise_terrain_base->transformNoiseMap();
-
- noise_terrain_higher->perlinMap2D(
- x + 0.5 * noise_terrain_higher->np->spread.X,
- z + 0.5 * noise_terrain_higher->np->spread.Z);
- noise_terrain_higher->transformNoiseMap();
-
- noise_steepness->perlinMap2D(
- x + 0.5 * noise_steepness->np->spread.X,
- z + 0.5 * noise_steepness->np->spread.Z);
- noise_steepness->transformNoiseMap();
-
- noise_height_select->perlinMap2D(
- x + 0.5 * noise_height_select->np->spread.X,
- z + 0.5 * noise_height_select->np->spread.Z);
- }
-
- noise_trees->perlinMap2D(
- x + 0.5 * noise_trees->np->spread.X,
- z + 0.5 * noise_trees->np->spread.Z);
-
- if (!(flags & MG_FLAT)) {
- noise_mud->perlinMap2D(
- x + 0.5 * noise_mud->np->spread.X,
- z + 0.5 * noise_mud->np->spread.Z);
- noise_mud->transformNoiseMap();
- }
- noise_beach->perlinMap2D(
- x + 0.2 * noise_beach->np->spread.X,
- z + 0.7 * noise_beach->np->spread.Z);
+ // Loop this part, it will make stuff look older and newer nicely
+ const u32 age_loops = 2;
+ for (u32 i_age = 0; i_age < age_loops; i_age++) { // Aging loop
+ // Make caves (this code is relatively horrible)
+ if (flags & MG_CAVES)
+ generateCaves(stone_surface_max_y);
+
+ // Add mud to the central chunk
+ addMud();
- noise_biome->perlinMap2D(
- x + 0.6 * noise_biome->np->spread.X,
- z + 0.2 * noise_biome->np->spread.Z);
+ // Add blobs of dirt and gravel underground
+ addDirtGravelBlobs();
+
+ // Flow mud away from steep edges
+ flowMud(mudflow_minpos, mudflow_maxpos);
+
+ }
+
+ // Add dungeons
+ if (flags & MG_DUNGEONS) {
+ DungeonGen dgen(ndef, data->seed, water_level);
+ dgen.generate(vm, blockseed, full_node_min, full_node_max);
}
+
+ // Add top and bottom side of water to transforming_liquid queue
+ updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
+ // Grow grass
+ growGrass();
- /*
- Cache some ground type values for speed
- */
+ // Generate some trees, and add grass, if a jungle
+ if (flags & MG_TREES)
+ placeTreesAndJungleGrass();
-// Creates variables c_name=id and n_name=node
-#define CONTENT_VARIABLE(ndef, name)\
- content_t c_##name = ndef->getId("mapgen_" #name);\
- MapNode n_##name(c_##name);
-// Default to something else if was CONTENT_IGNORE
-#define CONTENT_VARIABLE_FALLBACK(name, dname)\
- if(c_##name == CONTENT_IGNORE){\
- c_##name = c_##dname;\
- n_##name = n_##dname;\
+ // Generate the registered ores
+ for (unsigned int i = 0; i != emerge->ores.size(); i++) {
+ Ore *ore = emerge->ores[i];
+ ore->generate(this, blockseed + i, node_min, node_max);
}
- CONTENT_VARIABLE(ndef, stone);
- CONTENT_VARIABLE(ndef, air);
- CONTENT_VARIABLE(ndef, water_source);
- CONTENT_VARIABLE(ndef, dirt);
- CONTENT_VARIABLE(ndef, sand);
- CONTENT_VARIABLE(ndef, gravel);
- CONTENT_VARIABLE(ndef, clay);
- CONTENT_VARIABLE(ndef, lava_source);
- CONTENT_VARIABLE(ndef, cobble);
- CONTENT_VARIABLE(ndef, mossycobble);
- CONTENT_VARIABLE(ndef, dirt_with_grass);
- CONTENT_VARIABLE(ndef, junglegrass);
- CONTENT_VARIABLE(ndef, stone_with_coal);
- CONTENT_VARIABLE(ndef, stone_with_iron);
- CONTENT_VARIABLE(ndef, mese);
- CONTENT_VARIABLE(ndef, desert_sand);
- CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
- CONTENT_VARIABLE(ndef, desert_stone);
- CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
+ // Calculate lighting
+ calcLighting(node_min, node_max);
+
+ this->generating = false;
+}
- // Maximum height of the stone surface and obstacles.
- // This is used to guide the cave generation
- s16 stone_surface_max_y = 0;
- /*
- Generate general ground level to full area
- */
- {
-#if 1
- TimeTaker timer1("Generating ground level");
+void MapgenV6::calculateNoise() {
+ int x = node_min.X;
+ int z = node_min.Z;
- for(s16 x=node_min.X; x<=node_max.X; x++)
- for(s16 z=node_min.Z; z<=node_max.Z; z++)
- {
- // Node position
- v2s16 p2d = v2s16(x,z);
+ // Need to adjust for the original implementation's +.5 offset...
+ if (!(flags & MG_FLAT)) {
+ noise_terrain_base->perlinMap2D(
+ x + 0.5 * noise_terrain_base->np->spread.X,
+ z + 0.5 * noise_terrain_base->np->spread.Z);
+ noise_terrain_base->transformNoiseMap();
- /*
- Skip of already generated
- */
- /*{
- v3s16 p(p2d.X, node_min.Y, p2d.Y);
- if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
- continue;
- }*/
+ noise_terrain_higher->perlinMap2D(
+ x + 0.5 * noise_terrain_higher->np->spread.X,
+ z + 0.5 * noise_terrain_higher->np->spread.Z);
+ noise_terrain_higher->transformNoiseMap();
- // Ground height at this point
- float surface_y_f = 0.0;
+ noise_steepness->perlinMap2D(
+ x + 0.5 * noise_steepness->np->spread.X,
+ z + 0.5 * noise_steepness->np->spread.Z);
+ noise_steepness->transformNoiseMap();
- // Use perlin noise for ground height
- surface_y_f = base_rock_level_2d(data->seed, p2d);
+ noise_height_select->perlinMap2D(
+ x + 0.5 * noise_height_select->np->spread.X,
+ z + 0.5 * noise_height_select->np->spread.Z);
- /*// Experimental stuff
- {
- float a = highlands_level_2d(data->seed, p2d);
- if(a > surface_y_f)
- surface_y_f = a;
- }*/
+ noise_mud->perlinMap2D(
+ x + 0.5 * noise_mud->np->spread.X,
+ z + 0.5 * noise_mud->np->spread.Z);
+ noise_mud->transformNoiseMap();
+ }
- // Convert to integer
- s16 surface_y = (s16)surface_y_f;
+ noise_beach->perlinMap2D(
+ x + 0.2 * noise_beach->np->spread.X,
+ z + 0.7 * noise_beach->np->spread.Z);
+ noise_biome->perlinMap2D(
+ x + 0.6 * noise_biome->np->spread.X,
+ z + 0.2 * noise_biome->np->spread.Z);
+}
+
+
+int MapgenV6::generateGround() {
+ //TimeTaker timer1("Generating ground level");
+ MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
+ MapNode n_stone(c_stone), n_desert_stone(c_desert_stone);
+ int stone_surface_max_y = -MAP_GENERATION_LIMIT;
+ u32 index = 0;
+
+ for (s16 z = node_min.Z; z <= node_max.Z; z++)
+ for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
+ // Surface height
+ s16 surface_y = (s16)baseTerrainLevelFromMap(index);
+
// Log it
- if(surface_y > stone_surface_max_y)
+ if (surface_y > stone_surface_max_y)
stone_surface_max_y = surface_y;
- BiomeType bt = get_biome(data->seed, p2d);
- /*
- Fill ground with stone
- */
- {
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
- for(s16 y=node_min.Y; y<=node_max.Y; y++)
+ BiomeType bt = getBiome(index, v2s16(x, z));
+
+ // Fill ground with stone
+ v3s16 em = vm->m_area.getExtent();
+ u32 i = vm->m_area.index(x, node_min.Y, z);
+ for (s16 y = node_min.Y; y <= node_max.Y; y++) {
+ if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
+ if (y <= surface_y) {
+ vm->m_data[i] = (y > water_level && bt == BT_DESERT) ?
+ n_desert_stone : n_stone;
+ } else if (y <= water_level) {
+ vm->m_data[i] = n_water_source;
+ } else {
+ vm->m_data[i] = n_air;
+ }
+ }
+ vm->m_area.add_y(em, i, 1);
+ }
+ }
+
+ return stone_surface_max_y;
+}
+
+
+void MapgenV6::addMud() {
+ // 15ms @cs=8
+ //TimeTaker timer1("add mud");
+ MapNode n_dirt(c_dirt), n_gravel(c_gravel);
+ MapNode n_sand(c_sand), n_desert_sand(c_desert_sand);
+ MapNode addnode;
+
+ u32 index = 0;
+ for (s16 z = node_min.Z; z <= node_max.Z; z++)
+ for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
+ // Randomize mud amount
+ s16 mud_add_amount = getMudAmount(index) / 2.0 + 0.5;
+
+ // Find ground level
+ s16 surface_y = find_stone_level(v2s16(x, z)); /////////////////optimize this!
+
+ // Handle area not found
+ if (surface_y == vm->m_area.MinEdge.Y - 1)
+ continue;
+
+ BiomeType bt = getBiome(index, v2s16(x, z));
+ addnode = (bt == BT_DESERT) ? n_desert_sand : n_dirt;
+
+ if (bt == BT_DESERT && surface_y + mud_add_amount <= water_level + 1) {
+ addnode = n_sand;
+ } else if (mud_add_amount <= 0) {
+ mud_add_amount = 1 - mud_add_amount;
+ addnode = n_gravel;
+ } else if (bt == BT_NORMAL && getHaveBeach(index) &&
+ surface_y + mud_add_amount <= water_level + 2) {
+ addnode = n_sand;
+ }
+
+ if (bt == BT_DESERT && surface_y > 20)
+ mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20) / 5);
+
+ // If topmost node is grass, change it to mud. It might be if it was
+ // flown to there from a neighboring chunk and then converted.
+ u32 i = vm->m_area.index(x, surface_y, z);
+ if (vm->m_data[i].getContent() == c_dirt_with_grass)
+ vm->m_data[i] = n_dirt;
+
+ // Add mud on ground
+ s16 mudcount = 0;
+ v3s16 em = vm->m_area.getExtent();
+ s16 y_start = surface_y + 1;
+ i = vm->m_area.index(x, y_start, z);
+ for (s16 y = y_start; y <= node_max.Y; y++) {
+ if (mudcount >= mud_add_amount)
+ break;
+
+ vm->m_data[i] = addnode;
+ mudcount++;
+
+ vm->m_area.add_y(em, i, 1);
+ }
+ }
+}
+
+
+void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos) {
+ // 340ms @cs=8
+ TimeTaker timer1("flow mud");
+
+ // Iterate a few times
+ for(s16 k = 0; k < 3; k++) {
+ for (s16 z = mudflow_minpos; z <= mudflow_maxpos; z++)
+ for (s16 x = mudflow_minpos; x <= mudflow_maxpos; x++) {
+ // Invert coordinates every 2nd iteration
+ if (k % 2 == 0) {
+ x = mudflow_maxpos - (x - mudflow_minpos);
+ z = mudflow_maxpos - (z - mudflow_minpos);
+ }
+
+ // Node position in 2d
+ v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x, z);
+
+ v3s16 em = vm->m_area.getExtent();
+ u32 i = vm->m_area.index(p2d.X, node_max.Y, p2d.Y);
+ s16 y = node_max.Y;
+
+ while(y >= node_min.Y)
+ {
+
+ for(;; y--)
{
- if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
- if(y <= surface_y){
- if(y > water_level && bt == BT_DESERT)
- vmanip.m_data[i] = n_desert_stone;
+ MapNode *n = NULL;
+ // Find mud
+ for(; y >= node_min.Y; y--) {
+ n = &vm->m_data[i];
+ if (n->getContent() == c_dirt ||
+ n->getContent() == c_dirt_with_grass ||
+ n->getContent() == c_gravel)
+ break;
+
+ vm->m_area.add_y(em, i, -1);
+ }
+
+ // Stop if out of area
+ //if(vmanip.m_area.contains(i) == false)
+ if (y < node_min.Y)
+ break;
+
+ if (n->getContent() == c_dirt ||
+ n->getContent() == c_dirt_with_grass)
+ {
+ // Make it exactly mud
+ n->setContent(c_dirt);
+
+ // Don't flow it if the stuff under it is not mud
+ {
+ u32 i2 = i;
+ vm->m_area.add_y(em, i2, -1);
+ // Cancel if out of area
+ if(vm->m_area.contains(i2) == false)
+ continue;
+ MapNode *n2 = &vm->m_data[i2];
+ if (n2->getContent() != c_dirt &&
+ n2->getContent() != c_dirt_with_grass)
+ continue;
+ }
+ }
+
+ v3s16 dirs4[4] = {
+ v3s16(0,0,1), // back
+ v3s16(1,0,0), // right
+ v3s16(0,0,-1), // front
+ v3s16(-1,0,0), // left
+ };
+
+ // Check that upper is air or doesn't exist.
+ // Cancel dropping if upper keeps it in place
+ u32 i3 = i;
+ vm->m_area.add_y(em, i3, 1);
+ if (vm->m_area.contains(i3) == true &&
+ ndef->get(vm->m_data[i3]).walkable)
+ continue;
+
+ // Drop mud on side
+ for(u32 di=0; di<4; di++) {
+ v3s16 dirp = dirs4[di];
+ u32 i2 = i;
+ // Move to side
+ vm->m_area.add_p(em, i2, dirp);
+ // Fail if out of area
+ if (vm->m_area.contains(i2) == false)
+ continue;
+ // Check that side is air
+ MapNode *n2 = &vm->m_data[i2];
+ if (ndef->get(*n2).walkable)
+ continue;
+ // Check that under side is air
+ vm->m_area.add_y(em, i2, -1);
+ if (vm->m_area.contains(i2) == false)
+ continue;
+ n2 = &vm->m_data[i2];
+ if (ndef->get(*n2).walkable)
+ continue;
+ // Loop further down until not air
+ bool dropped_to_unknown = false;
+ do {
+ vm->m_area.add_y(em, i2, -1);
+ n2 = &vm->m_data[i2];
+ // if out of known area
+ if(vm->m_area.contains(i2) == false ||
+ n2->getContent() == CONTENT_IGNORE) {
+ dropped_to_unknown = true;
+ break;
+ }
+ } while (ndef->get(*n2).walkable == false);
+ // Loop one up so that we're in air
+ vm->m_area.add_y(em, i2, 1);
+ n2 = &vm->m_data[i2];
+
+ bool old_is_water = (n->getContent() == c_water_source);
+ // Move mud to new place
+ if (!dropped_to_unknown) {
+ *n2 = *n;
+ // Set old place to be air (or water)
+ if(old_is_water)
+ *n = MapNode(c_water_source);
else
- vmanip.m_data[i] = n_stone;
- } else if(y <= water_level){
- vmanip.m_data[i] = MapNode(c_water_source);
- } else {
- vmanip.m_data[i] = MapNode(c_air);
+ *n = MapNode(CONTENT_AIR);
}
+
+ // Done
+ break;
}
- vmanip.m_area.add_y(em, i, 1);
+ }
}
}
}
-#endif
+}
- }//timer1
- // Limit dirt flow area by 1 because mud is flown into neighbors.
- assert(central_area_size.X == central_area_size.Z);
- s16 mudflow_minpos = 0-max_spread_amount+1;
- s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
+void MapgenV6::addDirtGravelBlobs() {
+ if (getBiome(v2s16(node_min.X, node_min.Z)) != BT_NORMAL)
+ return;
+
+ PseudoRandom pr(blockseed + 983);
+ for (int i = 0; i < volume_nodes/10/10/10; i++) {
+ bool only_fill_cave = (myrand_range(0,1) != 0);
+ v3s16 size(
+ pr.range(1, 8),
+ pr.range(1, 8),
+ pr.range(1, 8)
+ );
+ v3s16 p0(
+ pr.range(node_min.X, node_max.X) - size.X / 2,
+ pr.range(node_min.Y, node_max.Y) - size.Y / 2,
+ pr.range(node_min.Z, node_max.Z) - size.Z / 2
+ );
+
+ MapNode n1((p0.Y > -32 && !pr.range(0, 1)) ? c_dirt : c_gravel);
+ for (int z1 = 0; z1 < size.Z; z1++)
+ for (int y1 = 0; y1 < size.Y; y1++)
+ for (int x1 = 0; x1 < size.X; x1++) {
+ v3s16 p = p0 + v3s16(x1, y1, z1);
+ u32 i = vm->m_area.index(p);
+ if (!vm->m_area.contains(i))
+ continue;
+ // Cancel if not stone and not cave air
+ if (vm->m_data[i].getContent() != c_stone &&
+ !(vm->m_flags[i] & VMANIP_FLAG_CAVE))
+ continue;
+ if (only_fill_cave && !(vm->m_flags[i] & VMANIP_FLAG_CAVE))
+ continue;
+ vm->m_data[i] = n1;
+ }
+ }
+}
- /*
- Loop this part, it will make stuff look older and newer nicely
- */
- /*double cave_amount = 6.0 + 6.0 * noise2d_perlin(
- 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
- data->seed+34329, 3, 0.50);*/
+void MapgenV6::placeTreesAndJungleGrass() {
+ //TimeTaker t("placeTrees");
+ if (node_max.Y < water_level)
+ return;
+
+ PseudoRandom grassrandom(blockseed + 53);
+ content_t c_junglegrass = ndef->getId("mapgen_junglegrass");
+ // if we don't have junglegrass, don't place cignore... that's bad
+ if (c_junglegrass == CONTENT_IGNORE)
+ c_junglegrass = CONTENT_AIR;
+ MapNode n_junglegrass(c_junglegrass);
+ v3s16 em = vm->m_area.getExtent();
+
+ // Divide area into parts
+ s16 div = 8;
+ s16 sidelen = central_area_size.X / div;
+ double area = sidelen * sidelen;
+
+ // N.B. We must add jungle grass first, since tree leaves will
+ // obstruct the ground, giving us a false ground level
+ for (s16 z0 = 0; z0 < div; z0++)
+ for (s16 x0 = 0; x0 < div; x0++) {
+ // Center position of part of division
+ v2s16 p2d_center(
+ node_min.X + sidelen / 2 + sidelen * x0,
+ node_min.Z + sidelen / 2 + sidelen * z0
+ );
+ // Minimum edge of part of division
+ v2s16 p2d_min(
+ node_min.X + sidelen * x0,
+ node_min.Z + sidelen * z0
+ );
+ // Maximum edge of part of division
+ v2s16 p2d_max(
+ node_min.X + sidelen + sidelen * x0 - 1,
+ node_min.Z + sidelen + sidelen * z0 - 1
+ );
+
+ // Amount of trees, jungle area
+ u32 tree_count = area * getTreeAmount(p2d_center);
+
+ float humidity;
+ bool is_jungle = false;
+ if (flags & MGV6_JUNGLES) {
+ humidity = getHumidity(p2d_center);
+ if (humidity > 0.75) {
+ is_jungle = true;
+ tree_count *= 4;
+ }
+ }
+
+ // Add jungle grass
+ if (is_jungle) {
+ u32 grass_count = 5 * humidity * tree_count;
+ for (u32 i = 0; i < grass_count; i++) {
+ s16 x = grassrandom.range(p2d_min.X, p2d_max.X);
+ s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y);
+
+ s16 y = find_ground_level(v2s16(x, z)); ////////////////optimize this!
+ if (y < water_level || y < node_min.Y || y > node_max.Y)
+ continue;
+
+ u32 vi = vm->m_area.index(x, y, z);
+ // place on dirt_with_grass, since we know it is exposed to sunlight
+ if (vm->m_data[vi].getContent() == c_dirt_with_grass) {
+ vm->m_area.add_y(em, vi, 1);
+ vm->m_data[vi] = n_junglegrass;
+ }
+ }
+ }
+
+ // Put trees in random places on part of division
+ for (u32 i = 0; i < tree_count; i++) {
+ s16 x = myrand_range(p2d_min.X, p2d_max.X);
+ s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
+ s16 y = find_ground_level(v2s16(x, z)); ////////////////////optimize this!
+ // Don't make a tree under water level
+ // Don't make a tree so high that it doesn't fit
+ if(y < water_level || y > node_max.Y - 6)
+ continue;
+
+ v3s16 p(x,y,z);
+ // Trees grow only on mud and grass
+ {
+ u32 i = vm->m_area.index(p);
+ MapNode *n = &vm->m_data[i];
+ if (n->getContent() != c_dirt &&
+ n->getContent() != c_dirt_with_grass)
+ continue;
+ }
+ p.Y++;
+
+ // Make a tree
+ if (is_jungle) {
+ treegen::make_jungletree(*vm, p, ndef, myrand());
+ } else {
+ bool is_apple_tree = (myrand_range(0, 3) == 0) &&
+ getHaveAppleTree(v2s16(x, z));
+ treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand());
+ }
+ }
+ }
+ //printf("placeTreesAndJungleGrass: %dms\n", t.stop());
+}
- double cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, data->seed);
- const u32 age_loops = 2;
- for(u32 i_age=0; i_age<age_loops; i_age++)
- { // Aging loop
- /******************************
- BEGINNING OF AGING LOOP
- ******************************/
-
-#if 1
- {
+void MapgenV6::growGrass() {
+ for (s16 z = full_node_min.Z; z <= full_node_max.Z; z++)
+ for (s16 x = full_node_min.X; x <= full_node_max.X; x++) {
+ // Find the lowest surface to which enough light ends up to make
+ // grass grow. Basically just wait until not air and not leaves.
+ s16 surface_y = 0;
+ {
+ v3s16 em = vm->m_area.getExtent();
+ u32 i = vm->m_area.index(x, node_max.Y, z);
+ s16 y;
+ // Go to ground level
+ for (y = node_max.Y; y >= full_node_min.Y; y--) {
+ MapNode &n = vm->m_data[i];
+ if (ndef->get(n).param_type != CPT_LIGHT ||
+ ndef->get(n).liquid_type != LIQUID_NONE)
+ break;
+ vm->m_area.add_y(em, i, -1);
+ }
+ surface_y = (y >= full_node_min.Y) ? y : full_node_min.Y;
+ }
+
+ u32 i = vm->m_area.index(x, surface_y, z);
+ MapNode *n = &vm->m_data[i];
+ if (n->getContent() == c_dirt && surface_y >= water_level - 20)
+ n->setContent(c_dirt_with_grass);
+ }
+}
+
+
+void MapgenV6::defineCave(Cave &cave, PseudoRandom ps,
+ v3s16 node_min, bool large_cave) {
+ cave.min_tunnel_diameter = 2;
+ cave.max_tunnel_diameter = ps.range(2,6);
+ cave.dswitchint = ps.range(1,14);
+ cave.flooded = true; //large_cave && ps.range(0,4);
+ if(large_cave){
+ cave.part_max_length_rs = ps.range(2,4);
+ cave.tunnel_routepoints = ps.range(5, ps.range(15,30));
+ cave.min_tunnel_diameter = 5;
+ cave.max_tunnel_diameter = ps.range(7, ps.range(8,24));
+ } else {
+ cave.part_max_length_rs = ps.range(2,9);
+ cave.tunnel_routepoints = ps.range(10, ps.range(15,30));
+ }
+ cave.large_cave_is_flat = (ps.range(0,1) == 0);
+}
+
+
+void MapgenV6::generateCaves(int max_stone_y) {
// 24ms @cs=8
//TimeTaker timer1("caves");
+
+ /*double cave_amount = 6.0 + 6.0 * noise2d_perlin(
+ 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
+ data->seed+34329, 3, 0.50);*/
+ const s16 max_spread_amount = MAP_BLOCKSIZE;
+ float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed);
- /*
- Make caves (this code is relatively horrible)
- */
cave_amount = MYMAX(0.0, cave_amount);
u32 caves_count = cave_amount * volume_nodes / 50000;
u32 bruises_count = 1;
- PseudoRandom ps(blockseed+21343);
- PseudoRandom ps2(blockseed+1032);
- if(ps.range(1, 6) == 1)
+ PseudoRandom ps(blockseed + 21343);
+ PseudoRandom ps2(blockseed + 1032);
+
+ if (ps.range(1, 6) == 1)
bruises_count = ps.range(0, ps.range(0, 2));
- if(get_biome(data->seed, v2s16(node_min.X, node_min.Z)) == BT_DESERT){
- caves_count /= 3;
+
+ if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
+ caves_count /= 3;
bruises_count /= 3;
}
- for(u32 jj=0; jj<caves_count+bruises_count; jj++)
- {
- if (!(flags & MG_CAVES))
- continue;
-
+
+ for(u32 jj = 0; jj < caves_count + bruises_count; jj++) {
/*int avg_height = (int)
((base_rock_level_2d(data->seed, v2s16(node_min.X, node_min.Z)) +
base_rock_level_2d(data->seed, v2s16(node_max.X, node_max.Z))) / 2);
@@ -700,21 +977,9 @@ void MapgenV6::makeChunk(BlockMakeData *data)
break;*/
bool large_cave = (jj >= caves_count);
- s16 min_tunnel_diameter = 2;
- s16 max_tunnel_diameter = ps.range(2,6);
- int dswitchint = ps.range(1,14);
- u16 tunnel_routepoints = 0;
- int part_max_length_rs = 0;
- if(large_cave){
- part_max_length_rs = ps.range(2,4);
- tunnel_routepoints = ps.range(5, ps.range(15,30));
- min_tunnel_diameter = 5;
- max_tunnel_diameter = ps.range(7, ps.range(8,24));
- } else {
- part_max_length_rs = ps.range(2,9);
- tunnel_routepoints = ps.range(10, ps.range(15,30));
- }
- bool large_cave_is_flat = (ps.range(0,1) == 0);
+
+ Cave cave;
+ defineCave(cave, ps, node_min, large_cave);
v3f main_direction(0,0,0);
@@ -727,13 +992,13 @@ void MapgenV6::makeChunk(BlockMakeData *data)
// Allow a bit more
//(this should be more than the maximum radius of the tunnel)
s16 insure = 10;
- s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
+ s16 more = max_spread_amount - cave.max_tunnel_diameter / 2 - insure;
ar += v3s16(1,0,1) * more * 2;
of -= v3s16(1,0,1) * more;
s16 route_y_min = 0;
// Allow half a diameter + 7 over stone surface
- s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
+ s16 route_y_max = -of.Y + max_stone_y + cave.max_tunnel_diameter/2 + 7;
// Limit maximum to area
route_y_max = rangelim(route_y_max, 0, ar.Y-1);
@@ -743,10 +1008,10 @@ void MapgenV6::makeChunk(BlockMakeData *data)
s16 min = 0;
if(node_min.Y < water_level && node_max.Y > water_level)
{
- min = water_level - max_tunnel_diameter/3 - of.Y;
- route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
+ min = water_level - cave.max_tunnel_diameter/3 - of.Y;
+ route_y_max = water_level + cave.max_tunnel_diameter/3 - of.Y;
}
- route_y_min = ps.range(min, min + max_tunnel_diameter);
+ route_y_min = ps.range(min, min + cave.max_tunnel_diameter);
route_y_min = rangelim(route_y_min, 0, route_y_max);
}
@@ -774,9 +1039,9 @@ void MapgenV6::makeChunk(BlockMakeData *data)
Generate some tunnel starting from orp
*/
- for(u16 j=0; j<tunnel_routepoints; j++)
+ for(u16 j=0; j<cave.tunnel_routepoints; j++)
{
- if(j%dswitchint==0 && large_cave == false)
+ if(j%cave.dswitchint==0 && large_cave == false)
{
main_direction = v3f(
((float)(ps.next()%20)-(float)10)/10,
@@ -787,8 +1052,8 @@ void MapgenV6::makeChunk(BlockMakeData *data)
}
// Randomize size
- s16 min_d = min_tunnel_diameter;
- s16 max_d = max_tunnel_diameter;
+ s16 min_d = cave.min_tunnel_diameter;
+ s16 max_d = cave.max_tunnel_diameter;
s16 rs = ps.range(min_d, max_d);
// Every second section is rough
@@ -798,17 +1063,17 @@ void MapgenV6::makeChunk(BlockMakeData *data)
if(large_cave)
{
maxlen = v3s16(
- rs*part_max_length_rs,
- rs*part_max_length_rs/2,
- rs*part_max_length_rs
+ rs*cave.part_max_length_rs,
+ rs*cave.part_max_length_rs/2,
+ rs*cave.part_max_length_rs
);
}
else
{
maxlen = v3s16(
- rs*part_max_length_rs,
- ps.range(1, rs*part_max_length_rs),
- rs*part_max_length_rs
+ rs*cave.part_max_length_rs,
+ ps.range(1, rs*cave.part_max_length_rs),
+ rs*cave.part_max_length_rs
);
}
@@ -880,9 +1145,9 @@ void MapgenV6::makeChunk(BlockMakeData *data)
/*// Make better floors in small caves
if(y0 <= -rs/2 && rs<=7)
continue;*/
- if(large_cave_is_flat){
+ if (cave.large_cave_is_flat) {
// Make large caves not so tall
- if(rs > 7 && abs(y0) >= rs/3)
+ if (rs > 7 && abs(y0) >= rs/3)
continue;
}
@@ -892,543 +1157,44 @@ void MapgenV6::makeChunk(BlockMakeData *data)
v3s16 p(x,y,z);
p += of;
- if(vmanip.m_area.contains(p) == false)
+ if(vm->m_area.contains(p) == false)
continue;
- u32 i = vmanip.m_area.index(p);
+ u32 i = vm->m_area.index(p);
- if(large_cave)
- {
- if(full_node_min.Y < water_level &&
- full_node_max.Y > water_level){
- if(p.Y <= water_level)
- vmanip.m_data[i] = waternode;
+ if(large_cave) {
+ if (cave.flooded && full_node_min.Y < water_level &&
+ full_node_max.Y > water_level) {
+ if (p.Y <= water_level)
+ vm->m_data[i] = waternode;
else
- vmanip.m_data[i] = airnode;
- } else if(full_node_max.Y < water_level){
- if(p.Y < startp.Y - 2)
- vmanip.m_data[i] = lavanode;
+ vm->m_data[i] = airnode;
+ } else if (cave.flooded && full_node_max.Y < water_level) {
+ if (p.Y < startp.Y - 2)
+ vm->m_data[i] = lavanode;
else
- vmanip.m_data[i] = airnode;
+ vm->m_data[i] = airnode;
} else {
- vmanip.m_data[i] = airnode;
+ vm->m_data[i] = airnode;
}
} else {
// Don't replace air or water or lava or ignore
- if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
- vmanip.m_data[i].getContent() == CONTENT_AIR ||
- vmanip.m_data[i].getContent() == c_water_source ||
- vmanip.m_data[i].getContent() == c_lava_source)
+ if (vm->m_data[i].getContent() == CONTENT_IGNORE ||
+ vm->m_data[i].getContent() == CONTENT_AIR ||
+ vm->m_data[i].getContent() == c_water_source ||
+ vm->m_data[i].getContent() == c_lava_source)
continue;
- vmanip.m_data[i] = airnode;
+ vm->m_data[i] = airnode;
// Set tunnel flag
- vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
+ vm->m_flags[i] |= VMANIP_FLAG_CAVE;
}
}
}
}
}
-
orp = rp;
}
-
}
-
- }//timer1
-#endif
-
-#if 1
- {
- // 15ms @cs=8
- TimeTaker timer1("add mud");
-
- /*
- Add mud to the central chunk
- */
-
- for(s16 x=node_min.X; x<=node_max.X; x++)
- for(s16 z=node_min.Z; z<=node_max.Z; z++)
- {
- // Node position in 2d
- v2s16 p2d = v2s16(x,z);
-
- // Randomize mud amount
- s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
-
- // Find ground level
- s16 surface_y = find_stone_level(vmanip, p2d, ndef);
- // Handle area not found
- if(surface_y == vmanip.m_area.MinEdge.Y - 1)
- continue;
-
- MapNode addnode(c_dirt);
- BiomeType bt = get_biome(data->seed, p2d);
-
- if(bt == BT_DESERT)
- addnode = MapNode(c_desert_sand);
-
- if(bt == BT_DESERT && surface_y + mud_add_amount <= water_level+1){
- addnode = MapNode(c_sand);
- } else if(mud_add_amount <= 0){
- mud_add_amount = 1 - mud_add_amount;
- addnode = MapNode(c_gravel);
- } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
- surface_y + mud_add_amount <= water_level+2){
- addnode = MapNode(c_sand);
- }
-
- if(bt == BT_DESERT){
- if(surface_y > 20){
- mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
- }
- }
-
- /*
- If topmost node is grass, change it to mud.
- It might be if it was flown to there from a neighboring
- chunk and then converted.
- */
- {
- u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
- MapNode *n = &vmanip.m_data[i];
- if(n->getContent() == c_dirt_with_grass)
- *n = MapNode(c_dirt);
- }
-
- /*
- Add mud on ground
- */
- {
- s16 mudcount = 0;
- v3s16 em = vmanip.m_area.getExtent();
- s16 y_start = surface_y+1;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
- for(s16 y=y_start; y<=node_max.Y; y++)
- {
- if(mudcount >= mud_add_amount)
- break;
-
- MapNode &n = vmanip.m_data[i];
- n = addnode;
- mudcount++;
-
- vmanip.m_area.add_y(em, i, 1);
- }
- }
-
- }
-
- }//timer1
-#endif
-
- /*
- Add blobs of dirt and gravel underground
- */
- if(get_biome(data->seed, v2s16(node_min.X, node_min.Z)) == BT_NORMAL)
- {
- PseudoRandom pr(blockseed+983);
- for(int i=0; i<volume_nodes/10/10/10; i++)
- {
- bool only_fill_cave = (myrand_range(0,1) != 0);
- v3s16 size(
- pr.range(1, 8),
- pr.range(1, 8),
- pr.range(1, 8)
- );
- v3s16 p0(
- pr.range(node_min.X, node_max.X)-size.X/2,
- pr.range(node_min.Y, node_max.Y)-size.Y/2,
- pr.range(node_min.Z, node_max.Z)-size.Z/2
- );
- MapNode n1;
- if(p0.Y > -32 && pr.range(0,1) == 0)
- n1 = MapNode(c_dirt);
- else
- n1 = MapNode(c_gravel);
- for(int x1=0; x1<size.X; x1++)
- for(int y1=0; y1<size.Y; y1++)
- for(int z1=0; z1<size.Z; z1++)
- {
- v3s16 p = p0 + v3s16(x1,y1,z1);
- u32 i = vmanip.m_area.index(p);
- if(!vmanip.m_area.contains(i))
- continue;
- // Cancel if not stone and not cave air
- if(vmanip.m_data[i].getContent() != c_stone &&
- !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
- continue;
- if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
- continue;
- vmanip.m_data[i] = n1;
- }
- }
- }
-
-#if 1
- {
- // 340ms @cs=8
- TimeTaker timer1("flow mud");
-
- /*
- Flow mud away from steep edges
- */
-
- // Iterate a few times
- for(s16 k=0; k<3; k++)
- {
-
- for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
- for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
- {
- // Invert coordinates every 2nd iteration
- if(k%2 == 0)
- {
- x = mudflow_maxpos - (x-mudflow_minpos);
- z = mudflow_maxpos - (z-mudflow_minpos);
- }
-
- // Node position in 2d
- v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
-
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
- s16 y=node_max.Y;
-
- while(y >= node_min.Y)
- {
-
- for(;; y--)
- {
- MapNode *n = NULL;
- // Find mud
- for(; y>=node_min.Y; y--)
- {
- n = &vmanip.m_data[i];
- //if(content_walkable(n->d))
- // break;
- if(n->getContent() == c_dirt ||
- n->getContent() == c_dirt_with_grass ||
- n->getContent() == c_gravel)
- break;
-
- vmanip.m_area.add_y(em, i, -1);
- }
-
- // Stop if out of area
- //if(vmanip.m_area.contains(i) == false)
- if(y < node_min.Y)
- break;
-
- /*// If not mud, do nothing to it
- MapNode *n = &vmanip.m_data[i];
- if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
- continue;*/
-
- if(n->getContent() == c_dirt ||
- n->getContent() == c_dirt_with_grass)
- {
- // Make it exactly mud
- n->setContent(c_dirt);
-
- /*
- Don't flow it if the stuff under it is not mud
- */
- {
- u32 i2 = i;
- vmanip.m_area.add_y(em, i2, -1);
- // Cancel if out of area
- if(vmanip.m_area.contains(i2) == false)
- continue;
- MapNode *n2 = &vmanip.m_data[i2];
- if(n2->getContent() != c_dirt &&
- n2->getContent() != c_dirt_with_grass)
- continue;
- }
- }
-
- /*s16 recurse_count = 0;
- mudflow_recurse:*/
-
- v3s16 dirs4[4] = {
- v3s16(0,0,1), // back
- v3s16(1,0,0), // right
- v3s16(0,0,-1), // front
- v3s16(-1,0,0), // left
- };
-
- // Theck that upper is air or doesn't exist.
- // Cancel dropping if upper keeps it in place
- u32 i3 = i;
- vmanip.m_area.add_y(em, i3, 1);
- if(vmanip.m_area.contains(i3) == true
- && ndef->get(vmanip.m_data[i3]).walkable)
- {
- continue;
- }
-
- // Drop mud on side
-
- for(u32 di=0; di<4; di++)
- {
- v3s16 dirp = dirs4[di];
- u32 i2 = i;
- // Move to side
- vmanip.m_area.add_p(em, i2, dirp);
- // Fail if out of area
- if(vmanip.m_area.contains(i2) == false)
- continue;
- // Check that side is air
- MapNode *n2 = &vmanip.m_data[i2];
- if(ndef->get(*n2).walkable)
- continue;
- // Check that under side is air
- vmanip.m_area.add_y(em, i2, -1);
- if(vmanip.m_area.contains(i2) == false)
- continue;
- n2 = &vmanip.m_data[i2];
- if(ndef->get(*n2).walkable)
- continue;
- /*// Check that under that is air (need a drop of 2)
- vmanip.m_area.add_y(em, i2, -1);
- if(vmanip.m_area.contains(i2) == false)
- continue;
- n2 = &vmanip.m_data[i2];
- if(content_walkable(n2->d))
- continue;*/
- // Loop further down until not air
- bool dropped_to_unknown = false;
- do{
- vmanip.m_area.add_y(em, i2, -1);
- n2 = &vmanip.m_data[i2];
- // if out of known area
- if(vmanip.m_area.contains(i2) == false
- || n2->getContent() == CONTENT_IGNORE){
- dropped_to_unknown = true;
- break;
- }
- }while(ndef->get(*n2).walkable == false);
- // Loop one up so that we're in air
- vmanip.m_area.add_y(em, i2, 1);
- n2 = &vmanip.m_data[i2];
-
- bool old_is_water = (n->getContent() == c_water_source);
- // Move mud to new place
- if(!dropped_to_unknown) {
- *n2 = *n;
- // Set old place to be air (or water)
- if(old_is_water)
- *n = MapNode(c_water_source);
- else
- *n = MapNode(CONTENT_AIR);
- }
-
- // Done
- break;
- }
- }
- }
- }
-
- }
-
- }//timer1
-#endif
-
- } // Aging loop
- /***********************
- END OF AGING LOOP
- ************************/
-
- /*
- Add top and bottom side of water to transforming_liquid queue
- */
-
- for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
- for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
- {
- // Node position
- v2s16 p2d(x,z);
- {
- bool water_found = false;
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
- for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
- {
- if(y == full_node_max.Y){
- water_found =
- (vmanip.m_data[i].getContent() == c_water_source ||
- vmanip.m_data[i].getContent() == c_lava_source);
- }
- else if(water_found == false)
- {
- if(vmanip.m_data[i].getContent() == c_water_source ||
- vmanip.m_data[i].getContent() == c_lava_source)
- {
- v3s16 p = v3s16(p2d.X, y, p2d.Y);
- data->transforming_liquid.push_back(p);
- water_found = true;
- }
- }
- else
- {
- // This can be done because water_found can only
- // turn to true and end up here after going through
- // a single block.
- if(vmanip.m_data[i+1].getContent() != c_water_source ||
- vmanip.m_data[i+1].getContent() != c_lava_source)
- {
- v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
- data->transforming_liquid.push_back(p);
- water_found = false;
- }
- }
-
- vmanip.m_area.add_y(em, i, -1);
- }
- }
- }
-
- /*
- Grow grass
- */
-
- for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
- for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
- {
- // Node position in 2d
- v2s16 p2d = v2s16(x,z);
-
- /*
- Find the lowest surface to which enough light ends up
- to make grass grow.
-
- Basically just wait until not air and not leaves.
- */
- s16 surface_y = 0;
- {
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
- s16 y;
- // Go to ground level
- for(y=node_max.Y; y>=full_node_min.Y; y--)
- {
- MapNode &n = vmanip.m_data[i];
- if(ndef->get(n).param_type != CPT_LIGHT
- || ndef->get(n).liquid_type != LIQUID_NONE)
- break;
- vmanip.m_area.add_y(em, i, -1);
- }
- if(y >= full_node_min.Y)
- surface_y = y;
- else
- surface_y = full_node_min.Y;
- }
-
- u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
- MapNode *n = &vmanip.m_data[i];
- if(n->getContent() == c_dirt){
- // Well yeah, this can't be overground...
- if(surface_y < water_level - 20)
- continue;
- n->setContent(c_dirt_with_grass);
- }
- }
-
- /*
- Generate some trees
- */
- assert(central_area_size.X == central_area_size.Z);
- if (flags & MG_TREES) {
- // Divide area into parts
- s16 div = 8;
- s16 sidelen = central_area_size.X / div;
- double area = sidelen * sidelen;
- for(s16 x0=0; x0<div; x0++)
- for(s16 z0=0; z0<div; z0++)
- {
- // Center position of part of division
- v2s16 p2d_center(
- node_min.X + sidelen/2 + sidelen*x0,
- node_min.Z + sidelen/2 + sidelen*z0
- );
- // Minimum edge of part of division
- v2s16 p2d_min(
- node_min.X + sidelen*x0,
- node_min.Z + sidelen*z0
- );
- // Maximum edge of part of division
- v2s16 p2d_max(
- node_min.X + sidelen + sidelen*x0 - 1,
- node_min.Z + sidelen + sidelen*z0 - 1
- );
- // Amount of trees
- u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
- // Put trees in random places on part of division
- for(u32 i=0; i<tree_count; i++)
- {
- s16 x = myrand_range(p2d_min.X, p2d_max.X);
- s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
- s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
- // Don't make a tree under water level
- if(y < water_level)
- continue;
- // Don't make a tree so high that it doesn't fit
- if(y > node_max.Y - 6)
- continue;
- v3s16 p(x,y,z);
- /*
- Trees grow only on mud and grass
- */
- {
- u32 i = vmanip.m_area.index(v3s16(p));
- MapNode *n = &vmanip.m_data[i];
- if(n->getContent() != c_dirt
- && n->getContent() != c_dirt_with_grass)
- continue;
- }
- p.Y++;
- // Make a tree
- make_tree(vmanip, p, false, ndef);
- }
- }
- }
-
-
- /*
- Calculate lighting
- */
- {
- ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
- SPT_AVG);
- //VoxelArea a(node_min, node_max);
- VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
- node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
- /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
- node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
- enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
- for(int i=0; i<2; i++)
- {
- enum LightBank bank = banks[i];
-
- core::map<v3s16, bool> light_sources;
- core::map<v3s16, u8> unlight_from;
-
- voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
- light_sources, unlight_from);
-
- bool inexistent_top_provides_sunlight = !block_is_underground;
- voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
- vmanip, a, inexistent_top_provides_sunlight,
- light_sources, ndef);
- // TODO: Do stuff according to bottom_sunlight_valid
-
- vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
-
- vmanip.spreadLight(bank, light_sources, ndef);
- }
- }
- this->generating = false;
}
diff --git a/src/mapgen_v6.h b/src/mapgen_v6.h
index d2f05252b..d37e406cb 100644
--- a/src/mapgen_v6.h
+++ b/src/mapgen_v6.h
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h"
#define AVERAGE_MUD_AMOUNT 4
+#define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
enum BiomeType
{
@@ -34,11 +35,23 @@ extern NoiseParams nparams_v6_def_terrain_base;
extern NoiseParams nparams_v6_def_terrain_higher;
extern NoiseParams nparams_v6_def_steepness;
extern NoiseParams nparams_v6_def_height_select;
-extern NoiseParams nparams_v6_def_trees;
extern NoiseParams nparams_v6_def_mud;
extern NoiseParams nparams_v6_def_beach;
extern NoiseParams nparams_v6_def_biome;
extern NoiseParams nparams_v6_def_cave;
+extern NoiseParams nparams_v6_def_humidity;
+extern NoiseParams nparams_v6_def_trees;
+extern NoiseParams nparams_v6_def_apple_trees;
+
+struct Cave {
+ s16 min_tunnel_diameter;
+ s16 max_tunnel_diameter;
+ int dswitchint;
+ u16 tunnel_routepoints;
+ int part_max_length_rs;
+ bool large_cave_is_flat;
+ bool flooded;
+};
struct MapgenV6Params : public MapgenParams {
float freq_desert;
@@ -47,12 +60,14 @@ struct MapgenV6Params : public MapgenParams {
NoiseParams *np_terrain_higher;
NoiseParams *np_steepness;
NoiseParams *np_height_select;
- NoiseParams *np_trees;
NoiseParams *np_mud;
NoiseParams *np_beach;
NoiseParams *np_biome;
NoiseParams *np_cave;
-
+ NoiseParams *np_humidity;
+ NoiseParams *np_trees;
+ NoiseParams *np_apple_trees;
+
MapgenV6Params() {
freq_desert = 0.45;
freq_beach = 0.15;
@@ -60,11 +75,14 @@ struct MapgenV6Params : public MapgenParams {
np_terrain_higher = &nparams_v6_def_terrain_higher;
np_steepness = &nparams_v6_def_steepness;
np_height_select = &nparams_v6_def_height_select;
- np_trees = &nparams_v6_def_trees;
np_mud = &nparams_v6_def_mud;
np_beach = &nparams_v6_def_beach;
np_biome = &nparams_v6_def_biome;
np_cave = &nparams_v6_def_cave;
+ np_humidity = &nparams_v6_def_humidity;
+ np_trees = &nparams_v6_def_trees;
+ np_apple_trees = &nparams_v6_def_apple_trees;
+
}
bool readParams(Settings *settings);
@@ -73,64 +91,90 @@ struct MapgenV6Params : public MapgenParams {
class MapgenV6 : public Mapgen {
public:
- //ManualMapVoxelManipulator &vmanip;
+ EmergeManager *emerge;
int ystride;
v3s16 csize;
+ u32 flags;
+ u32 blockseed;
v3s16 node_min;
v3s16 node_max;
+ v3s16 full_node_min;
+ v3s16 full_node_max;
+ v3s16 central_area_size;
+ int volume_nodes;
Noise *noise_terrain_base;
Noise *noise_terrain_higher;
Noise *noise_steepness;
Noise *noise_height_select;
- Noise *noise_trees;
Noise *noise_mud;
Noise *noise_beach;
Noise *noise_biome;
-
- float *map_terrain_base;
- float *map_terrain_higher;
- float *map_steepness;
- float *map_height_select;
- float *map_trees;
- float *map_mud;
- float *map_beach;
- float *map_biome;
-
NoiseParams *np_cave;
-
- u32 flags;
+ NoiseParams *np_humidity;
+ NoiseParams *np_trees;
+ NoiseParams *np_apple_trees;
float freq_desert;
float freq_beach;
-
- MapgenV6(int mapgenid, MapgenV6Params *params);
+
+ content_t c_stone;
+ content_t c_dirt;
+ content_t c_dirt_with_grass;
+ content_t c_sand;
+ content_t c_water_source;
+ content_t c_lava_source;
+ content_t c_gravel;
+ content_t c_cobble;
+ content_t c_desert_sand;
+ content_t c_desert_stone;
+
+ MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge);
~MapgenV6();
void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p);
- double baseRockLevelFromNoise(v2s16 p);
- static s16 find_ground_level(VoxelManipulator &vmanip,
- v2s16 p2d, INodeDefManager *ndef);
- static s16 find_stone_level(VoxelManipulator &vmanip,
- v2s16 p2d, INodeDefManager *ndef);
- void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
- bool is_apple_tree, INodeDefManager *ndef);
- double tree_amount_2d(u64 seed, v2s16 p);
+ float baseTerrainLevel(float terrain_base, float terrain_higher,
+ float steepness, float height_select);
+ virtual float baseTerrainLevelFromNoise(v2s16 p);
+ virtual float baseTerrainLevelFromMap(v2s16 p);
+ virtual float baseTerrainLevelFromMap(int index);
+
+ s16 find_ground_level(v2s16 p2d);
+ s16 find_stone_level(v2s16 p2d);
bool block_is_underground(u64 seed, v3s16 blockpos);
- double base_rock_level_2d(u64 seed, v2s16 p);
s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision);
- double get_mud_add_amount(u64 seed, v2s16 p);
- bool get_have_beach(u64 seed, v2s16 p2d);
- BiomeType get_biome(u64 seed, v2s16 p2d);
+
+ float getHumidity(v2s16 p);
+ float getTreeAmount(v2s16 p);
+ bool getHaveAppleTree(v2s16 p);
+ float getMudAmount(v2s16 p);
+ virtual float getMudAmount(int index);
+ bool getHaveBeach(v2s16 p);
+ bool getHaveBeach(int index);
+ BiomeType getBiome(v2s16 p);
+ BiomeType getBiome(int index, v2s16 p);
+
u32 get_blockseed(u64 seed, v3s16 p);
+
+ virtual void calculateNoise();
+ int generateGround();
+ void addMud();
+ void flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos);
+ void addDirtGravelBlobs();
+ void growGrass();
+ void placeTreesAndJungleGrass();
+ virtual void defineCave(Cave &cave, PseudoRandom ps,
+ v3s16 node_min, bool large_cave);
+ void generateCaves(int max_stone_y);
+ virtual void generateSomething() {}; //for next mapgen
};
struct MapgenFactoryV6 : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
- return new MapgenV6(mgid, (MapgenV6Params *)params);
+ return new MapgenV6(mgid, (MapgenV6Params *)params, emerge);
};
MapgenParams *createMapgenParams() {
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 0513e688c..bba845fcc 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -107,7 +107,7 @@ u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
{
const ContentFeatures &f = nodemgr->get(*this);
if(f.param_type_2 == CPT2_FACEDIR)
- return getParam2() & 0x03;
+ return getParam2() & 0x1F;
return 0;
}
@@ -140,29 +140,131 @@ static std::vector<aabb3f> transformNodeBox(const MapNode &n,
{
const std::vector<aabb3f> &fixed = nodebox.fixed;
int facedir = n.getFaceDir(nodemgr);
+ u8 axisdir = facedir>>2;
+ facedir&=0x03;
for(std::vector<aabb3f>::const_iterator
i = fixed.begin();
i != fixed.end(); i++)
{
aabb3f box = *i;
- if(facedir == 1)
+ switch (axisdir)
{
- box.MinEdge.rotateXZBy(-90);
- box.MaxEdge.rotateXZBy(-90);
- box.repair();
- }
- else if(facedir == 2)
- {
- box.MinEdge.rotateXZBy(180);
- box.MaxEdge.rotateXZBy(180);
- box.repair();
- }
- else if(facedir == 3)
- {
- box.MinEdge.rotateXZBy(90);
- box.MaxEdge.rotateXZBy(90);
- box.repair();
+ case 0:
+ if(facedir == 1)
+ {
+ box.MinEdge.rotateXZBy(-90);
+ box.MaxEdge.rotateXZBy(-90);
+ }
+ else if(facedir == 2)
+ {
+ box.MinEdge.rotateXZBy(180);
+ box.MaxEdge.rotateXZBy(180);
+ }
+ else if(facedir == 3)
+ {
+ box.MinEdge.rotateXZBy(90);
+ box.MaxEdge.rotateXZBy(90);
+ }
+ break;
+ case 1: // z+
+ box.MinEdge.rotateYZBy(90);
+ box.MaxEdge.rotateYZBy(90);
+ if(facedir == 1)
+ {
+ box.MinEdge.rotateXYBy(90);
+ box.MaxEdge.rotateXYBy(90);
+ }
+ else if(facedir == 2)
+ {
+ box.MinEdge.rotateXYBy(180);
+ box.MaxEdge.rotateXYBy(180);
+ }
+ else if(facedir == 3)
+ {
+ box.MinEdge.rotateXYBy(-90);
+ box.MaxEdge.rotateXYBy(-90);
+ }
+ break;
+ case 2: //z-
+ box.MinEdge.rotateYZBy(-90);
+ box.MaxEdge.rotateYZBy(-90);
+ if(facedir == 1)
+ {
+ box.MinEdge.rotateXYBy(-90);
+ box.MaxEdge.rotateXYBy(-90);
+ }
+ else if(facedir == 2)
+ {
+ box.MinEdge.rotateXYBy(180);
+ box.MaxEdge.rotateXYBy(180);
+ }
+ else if(facedir == 3)
+ {
+ box.MinEdge.rotateXYBy(90);
+ box.MaxEdge.rotateXYBy(90);
+ }
+ break;
+ case 3: //x+
+ box.MinEdge.rotateXYBy(-90);
+ box.MaxEdge.rotateXYBy(-90);
+ if(facedir == 1)
+ {
+ box.MinEdge.rotateYZBy(90);
+ box.MaxEdge.rotateYZBy(90);
+ }
+ else if(facedir == 2)
+ {
+ box.MinEdge.rotateYZBy(180);
+ box.MaxEdge.rotateYZBy(180);
+ }
+ else if(facedir == 3)
+ {
+ box.MinEdge.rotateYZBy(-90);
+ box.MaxEdge.rotateYZBy(-90);
+ }
+ break;
+ case 4: //x-
+ box.MinEdge.rotateXYBy(90);
+ box.MaxEdge.rotateXYBy(90);
+ if(facedir == 1)
+ {
+ box.MinEdge.rotateYZBy(-90);
+ box.MaxEdge.rotateYZBy(-90);
+ }
+ else if(facedir == 2)
+ {
+ box.MinEdge.rotateYZBy(180);
+ box.MaxEdge.rotateYZBy(180);
+ }
+ else if(facedir == 3)
+ {
+ box.MinEdge.rotateYZBy(90);
+ box.MaxEdge.rotateYZBy(90);
+ }
+ break;
+ case 5:
+ box.MinEdge.rotateXYBy(-180);
+ box.MaxEdge.rotateXYBy(-180);
+ if(facedir == 1)
+ {
+ box.MinEdge.rotateXZBy(90);
+ box.MaxEdge.rotateXZBy(90);
+ }
+ else if(facedir == 2)
+ {
+ box.MinEdge.rotateXZBy(180);
+ box.MaxEdge.rotateXZBy(180);
+ }
+ else if(facedir == 3)
+ {
+ box.MinEdge.rotateXZBy(-90);
+ box.MaxEdge.rotateXZBy(-90);
+ }
+ break;
+ default:
+ break;
}
+ box.repair();
boxes.push_back(box);
}
}
diff --git a/src/mapsector.cpp b/src/mapsector.cpp
index 108effa79..ebb050ec3 100644
--- a/src/mapsector.cpp
+++ b/src/mapsector.cpp
@@ -45,10 +45,10 @@ void MapSector::deleteBlocks()
m_block_cache = NULL;
// Delete all
- core::map<s16, MapBlock*>::Iterator i = m_blocks.getIterator();
- for(; i.atEnd() == false; i++)
+ for(std::map<s16, MapBlock*>::iterator i = m_blocks.begin();
+ i != m_blocks.end(); ++i)
{
- delete i.getNode()->getValue();
+ delete i->second;
}
// Clear container
@@ -64,14 +64,14 @@ MapBlock * MapSector::getBlockBuffered(s16 y)
}
// If block doesn't exist, return NULL
- core::map<s16, MapBlock*>::Node *n = m_blocks.find(y);
- if(n == NULL)
+ std::map<s16, MapBlock*>::iterator n = m_blocks.find(y);
+ if(n == m_blocks.end())
{
block = NULL;
}
// If block exists, return it
else{
- block = n->getValue();
+ block = n->second;
}
// Cache the last result
@@ -101,7 +101,7 @@ MapBlock * MapSector::createBlankBlock(s16 y)
{
MapBlock *block = createBlankBlockNoInsert(y);
- m_blocks.insert(y, block);
+ m_blocks[y] = block;
return block;
}
@@ -119,7 +119,7 @@ void MapSector::insertBlock(MapBlock *block)
assert(p2d == m_pos);
// Insert into container
- m_blocks.insert(block_y, block);
+ m_blocks[block_y] = block;
}
void MapSector::deleteBlock(MapBlock *block)
@@ -130,23 +130,18 @@ void MapSector::deleteBlock(MapBlock *block)
m_block_cache = NULL;
// Remove from container
- m_blocks.remove(block_y);
+ m_blocks.erase(block_y);
// Delete
delete block;
}
-void MapSector::getBlocks(core::list<MapBlock*> &dest)
+void MapSector::getBlocks(std::list<MapBlock*> &dest)
{
- core::list<MapBlock*> ref_list;
-
- core::map<s16, MapBlock*>::Iterator bi;
-
- bi = m_blocks.getIterator();
- for(; bi.atEnd() == false; bi++)
+ for(std::map<s16, MapBlock*>::iterator bi = m_blocks.begin();
+ bi != m_blocks.end(); ++bi)
{
- MapBlock *b = bi.getNode()->getValue();
- dest.push_back(b);
+ dest.push_back(bi->second);
}
}
@@ -189,7 +184,7 @@ ServerMapSector* ServerMapSector::deSerialize(
std::istream &is,
Map *parent,
v2s16 p2d,
- core::map<v2s16, MapSector*> & sectors,
+ std::map<v2s16, MapSector*> & sectors,
IGameDef *gamedef
)
{
@@ -219,22 +214,22 @@ ServerMapSector* ServerMapSector::deSerialize(
ServerMapSector *sector = NULL;
- core::map<v2s16, MapSector*>::Node *n = sectors.find(p2d);
+ std::map<v2s16, MapSector*>::iterator n = sectors.find(p2d);
- if(n != NULL)
+ if(n != sectors.end())
{
dstream<<"WARNING: deSerializing existent sectors not supported "
"at the moment, because code hasn't been tested."
<<std::endl;
- MapSector *sector = n->getValue();
+ MapSector *sector = n->second;
assert(sector->getId() == MAPSECTOR_SERVER);
return (ServerMapSector*)sector;
}
else
{
sector = new ServerMapSector(parent, p2d, gamedef);
- sectors.insert(p2d, sector);
+ sectors[p2d] = sector;
}
/*
diff --git a/src/mapsector.h b/src/mapsector.h
index 88fc76b57..4f2b3f31f 100644
--- a/src/mapsector.h
+++ b/src/mapsector.h
@@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h"
#include "exceptions.h"
#include <ostream>
+#include <map>
+#include <list>
class MapBlock;
class Map;
@@ -60,7 +62,7 @@ public:
void deleteBlock(MapBlock *block);
- void getBlocks(core::list<MapBlock*> &dest);
+ void getBlocks(std::list<MapBlock*> &dest);
// Always false at the moment, because sector contains no metadata.
bool differs_from_disk;
@@ -68,7 +70,7 @@ public:
protected:
// The pile of MapBlocks
- core::map<s16, MapBlock*> m_blocks;
+ std::map<s16, MapBlock*> m_blocks;
Map *m_parent;
// Position on parent (in MapBlock widths)
@@ -110,7 +112,7 @@ public:
std::istream &is,
Map *parent,
v2s16 p2d,
- core::map<v2s16, MapSector*> & sectors,
+ std::map<v2s16, MapSector*> & sectors,
IGameDef *gamedef
);
diff --git a/src/mods.cpp b/src/mods.cpp
index ac2d9b17d..6a7ab79aa 100644
--- a/src/mods.cpp
+++ b/src/mods.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "subgame.h"
#include "settings.h"
+#include "strfnd.h"
std::map<std::string, ModSpec> getModsInPath(std::string path)
{
@@ -188,11 +189,58 @@ void ModConfiguration::addMods(std::vector<ModSpec> new_mods)
}
}
+// If failed, returned modspec has name==""
+static ModSpec findCommonMod(const std::string &modname)
+{
+ // Try to find in {$user,$share}/games/common/$modname
+ std::vector<std::string> find_paths;
+ find_paths.push_back(porting::path_user + DIR_DELIM + "games" +
+ DIR_DELIM + "common" + DIR_DELIM + "mods" + DIR_DELIM + modname);
+ find_paths.push_back(porting::path_share + DIR_DELIM + "games" +
+ DIR_DELIM + "common" + DIR_DELIM + "mods" + DIR_DELIM + modname);
+ for(u32 i=0; i<find_paths.size(); i++){
+ const std::string &try_path = find_paths[i];
+ if(fs::PathExists(try_path))
+ return ModSpec(modname, try_path);
+ }
+ // Failed to find mod
+ return ModSpec();
+}
+
ModConfiguration::ModConfiguration(std::string worldpath)
{
+ SubgameSpec gamespec = findWorldSubgame(worldpath);
+
+ // Add common mods without dependency handling
+ std::vector<std::string> inexistent_common_mods;
+ Settings gameconf;
+ if(getGameConfig(gamespec.path, gameconf)){
+ if(gameconf.exists("common_mods")){
+ Strfnd f(gameconf.get("common_mods"));
+ while(!f.atend()){
+ std::string modname = trim(f.next(","));
+ if(modname.empty())
+ continue;
+ ModSpec spec = findCommonMod(modname);
+ if(spec.name.empty())
+ inexistent_common_mods.push_back(modname);
+ else
+ m_sorted_mods.push_back(spec);
+ }
+ }
+ }
+ if(!inexistent_common_mods.empty()){
+ std::string s = "Required common mods ";
+ for(u32 i=0; i<inexistent_common_mods.size(); i++){
+ if(i != 0) s += ", ";
+ s += std::string("\"") + inexistent_common_mods[i] + "\"";
+ }
+ s += " could not be found.";
+ throw ModError(s);
+ }
+
// Add all world mods and all game mods
addModsInPath(worldpath + DIR_DELIM + "worldmods");
- SubgameSpec gamespec = findWorldSubgame(worldpath);
addModsInPath(gamespec.gamemods_path);
// check world.mt file for mods explicitely declared to be
@@ -217,6 +265,6 @@ ModConfiguration::ModConfiguration(std::string worldpath)
}
for(std::set<std::string>::const_iterator i = gamespec.addon_mods_paths.begin();
- i != gamespec.addon_mods_paths.end(); ++i)
+ i != gamespec.addon_mods_paths.end(); ++i)
addModsInPathFiltered((*i),exclude_mod_names);
}
diff --git a/src/mods.h b/src/mods.h
index 9761a9103..32bcfb471 100644
--- a/src/mods.h
+++ b/src/mods.h
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include <map>
#include <exception>
+#include <list>
class ModError : public std::exception
{
@@ -68,7 +69,6 @@ struct ModSpec
{}
};
-
std::map<std::string,ModSpec> getModsInPath(std::string path);
// expands modpack contents, but does not replace them.
@@ -140,6 +140,4 @@ private:
};
-
#endif
-
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index 9a1145a8e..d41df5c3b 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -107,26 +107,31 @@ void NodeBox::deSerialize(std::istream &is)
TileDef
*/
-void TileDef::serialize(std::ostream &os) const
+void TileDef::serialize(std::ostream &os, u16 protocol_version) const
{
- writeU8(os, 0); // version
+ if(protocol_version >= 17)
+ writeU8(os, 1);
+ else
+ writeU8(os, 0);
os<<serializeString(name);
writeU8(os, animation.type);
writeU16(os, animation.aspect_w);
writeU16(os, animation.aspect_h);
writeF1000(os, animation.length);
+ if(protocol_version >= 17)
+ writeU8(os, backface_culling);
}
void TileDef::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version != 0)
- throw SerializationError("unsupported TileDef version");
name = deSerializeString(is);
animation.type = (TileAnimationType)readU8(is);
animation.aspect_w = readU16(is);
animation.aspect_h = readU16(is);
animation.length = readF1000(is);
+ if(version >= 1)
+ backface_culling = readU8(is);
}
/*
@@ -235,10 +240,10 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version)
writeF1000(os, visual_scale);
writeU8(os, 6);
for(u32 i=0; i<6; i++)
- tiledef[i].serialize(os);
+ tiledef[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
- tiledef_special[i].serialize(os);
+ tiledef_special[i].serialize(os, protocol_version);
}
writeU8(os, alpha);
writeU8(os, post_effect_color.getAlpha());
@@ -270,9 +275,9 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version)
serializeSimpleSoundSpec(sound_footstep, os);
serializeSimpleSoundSpec(sound_dig, os);
serializeSimpleSoundSpec(sound_dug, os);
+ writeU8(os, rightclickable);
// Stuff below should be moved to correct place in a version that otherwise changes
// the protocol version
- writeU8(os, rightclickable);
}
void ContentFeatures::deSerialize(std::istream &is)
@@ -331,12 +336,12 @@ void ContentFeatures::deSerialize(std::istream &is)
deSerializeSimpleSoundSpec(sound_footstep, is);
deSerializeSimpleSoundSpec(sound_dig, is);
deSerializeSimpleSoundSpec(sound_dug, is);
+ rightclickable = readU8(is);
// If you add anything here, insert it primarily inside the try-catch
// block to not need to increase the version.
try{
// Stuff below should be moved to correct place in a version that
// otherwise changes the protocol version
- rightclickable = readU8(is);
}catch(SerializationError &e) {};
}
@@ -809,10 +814,10 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version)
writeF1000(os, visual_scale);
writeU8(os, 6);
for(u32 i=0; i<6; i++)
- tiledef[i].serialize(os);
+ tiledef[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
- tiledef_special[i].serialize(os);
+ tiledef_special[i].serialize(os, protocol_version);
}
writeU8(os, alpha);
writeU8(os, post_effect_color.getAlpha());
diff --git a/src/nodedef.h b/src/nodedef.h
index b3f972b9b..4f07565d1 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -119,7 +119,7 @@ struct TileDef
animation.length = 1.0;
}
- void serialize(std::ostream &os) const;
+ void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is);
};
diff --git a/src/noise.h b/src/noise.h
index c2a85771c..34b4d0b41 100644
--- a/src/noise.h
+++ b/src/noise.h
@@ -89,7 +89,7 @@ public:
Noise(NoiseParams *np, int seed, int sx, int sy, int sz);
~Noise();
- void init(NoiseParams *np, int seed, int sx, int sy, int sz);
+ virtual void init(NoiseParams *np, int seed, int sx, int sy, int sz);
void setSize(int sx, int sy);
void setSize(int sx, int sy, int sz);
void setSpreadFactor(v3f spread);
@@ -157,7 +157,7 @@ inline float easeCurve(float t) {
(s) + (np)->seed, (np)->octaves, (np)->persist))
#define NoisePerlin3D(np, x, y, z, s) ((np)->offset + (np)->scale * \
- noise2d_perlin((float)(x) / (np)->spread.X, (float)(y) / (np)->spread.Y, \
+ noise3d_perlin((float)(x) / (np)->spread.X, (float)(y) / (np)->spread.Y, \
(float)(z) / (np)->spread.Z, (s) + (np)->seed, (np)->octaves, (np)->persist))
#endif
diff --git a/src/object_properties.h b/src/object_properties.h
index bde38bd66..eeb397efa 100644
--- a/src/object_properties.h
+++ b/src/object_properties.h
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h"
#include <iostream>
#include <map>
+#include <vector>
struct ObjectProperties
{
@@ -35,8 +36,8 @@ struct ObjectProperties
std::string visual;
std::string mesh;
v2f visual_size;
- core::array<std::string> textures;
- core::array<video::SColor> colors;
+ std::vector<std::string> textures;
+ std::vector<video::SColor> colors;
v2s16 spritediv;
v2s16 initial_sprite_basepos;
bool is_visible;
diff --git a/src/particles.cpp b/src/particles.cpp
index fef21d91b..1d814f619 100644
--- a/src/particles.cpp
+++ b/src/particles.cpp
@@ -32,19 +32,34 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientmap.h"
#include "mapnode.h"
+/*
+ Utility
+*/
+
+v3f random_v3f(v3f min, v3f max)
+{
+ return v3f( rand()/(float)RAND_MAX*(max.X-min.X)+min.X,
+ rand()/(float)RAND_MAX*(max.Y-min.Y)+min.Y,
+ rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z);
+}
+
+std::vector<Particle*> all_particles;
+std::map<u32, ParticleSpawner*> all_particlespawners;
+
Particle::Particle(
IGameDef *gamedef,
scene::ISceneManager* smgr,
LocalPlayer *player,
- s32 id,
+ ClientEnvironment &env,
v3f pos,
v3f velocity,
v3f acceleration,
float expirationtime,
float size,
+ bool collisiondetection,
AtlasPointer ap
):
- scene::ISceneNode(smgr->getRootSceneNode(), smgr, id)
+ scene::ISceneNode(smgr->getRootSceneNode(), smgr)
{
// Misc
m_gamedef = gamedef;
@@ -57,7 +72,6 @@ Particle::Particle(
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
m_material.setTexture(0, ap.atlas);
m_ap = ap;
- m_light = 0;
// Particle related
@@ -68,10 +82,20 @@ Particle::Particle(
m_time = 0;
m_player = player;
m_size = size;
+ m_collisiondetection = collisiondetection;
- // Irrlicht stuff (TODO)
- m_collisionbox = core::aabbox3d<f32>(-size/2,-size/2,-size/2,size/2,size/2,size/2);
+ // Irrlicht stuff
+ m_collisionbox = core::aabbox3d<f32>
+ (-size/2,-size/2,-size/2,size/2,size/2,size/2);
this->setAutomaticCulling(scene::EAC_OFF);
+
+ // Init lighting
+ updateLight(env);
+
+ // Init model
+ updateVertices();
+
+ all_particles.push_back(this);
}
Particle::~Particle()
@@ -82,8 +106,10 @@ void Particle::OnRegisterSceneNode()
{
if (IsVisible)
{
- SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
- SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
+ SceneManager->registerNodeForRendering
+ (this, scene::ESNRP_TRANSPARENT);
+ SceneManager->registerNodeForRendering
+ (this, scene::ESNRP_SOLID);
}
ISceneNode::OnRegisterSceneNode();
@@ -96,45 +122,45 @@ void Particle::render()
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setMaterial(m_material);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
- video::SColor c(255, m_light, m_light, m_light);
-
- video::S3DVertex vertices[4] =
- {
- video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0, c, m_ap.x0(), m_ap.y1()),
- video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0, c, m_ap.x1(), m_ap.y1()),
- video::S3DVertex(m_size/2,m_size/2,0, 0,0,0, c, m_ap.x1(), m_ap.y0()),
- video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0, c ,m_ap.x0(), m_ap.y0()),
- };
-
- for(u16 i=0; i<4; i++)
- {
- vertices[i].Pos.rotateYZBy(m_player->getPitch());
- vertices[i].Pos.rotateXZBy(m_player->getYaw());
- m_box.addInternalPoint(vertices[i].Pos);
- vertices[i].Pos += m_pos*BS;
- }
u16 indices[] = {0,1,2, 2,3,0};
- driver->drawVertexPrimitiveList(vertices, 4, indices, 2,
- video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
+ driver->drawVertexPrimitiveList(m_vertices, 4,
+ indices, 2, video::EVT_STANDARD,
+ scene::EPT_TRIANGLES, video::EIT_16BIT);
}
void Particle::step(float dtime, ClientEnvironment &env)
{
- core::aabbox3d<f32> box = m_collisionbox;
- v3f p_pos = m_pos*BS;
- v3f p_velocity = m_velocity*BS;
- v3f p_acceleration = m_acceleration*BS;
- collisionMoveSimple(&env.getClientMap(), m_gamedef,
- BS*0.5, box,
- 0, dtime,
- p_pos, p_velocity, p_acceleration);
- m_pos = p_pos/BS;
- m_velocity = p_velocity/BS;
- m_acceleration = p_acceleration/BS;
m_time += dtime;
+ if (m_collisiondetection)
+ {
+ core::aabbox3d<f32> box = m_collisionbox;
+ v3f p_pos = m_pos*BS;
+ v3f p_velocity = m_velocity*BS;
+ v3f p_acceleration = m_acceleration*BS;
+ collisionMoveSimple(&env, m_gamedef,
+ BS*0.5, box,
+ 0, dtime,
+ p_pos, p_velocity, p_acceleration);
+ m_pos = p_pos/BS;
+ m_velocity = p_velocity/BS;
+ m_acceleration = p_acceleration/BS;
+ }
+ else
+ {
+ m_velocity += m_acceleration * dtime;
+ m_pos += m_velocity * dtime;
+ }
// Update lighting
+ updateLight(env);
+
+ // Update model
+ updateVertices();
+}
+
+void Particle::updateLight(ClientEnvironment &env)
+{
u8 light = 0;
try{
v3s16 p = v3s16(
@@ -151,11 +177,37 @@ void Particle::step(float dtime, ClientEnvironment &env)
m_light = decode_light(light);
}
-std::vector<Particle*> all_particles;
+void Particle::updateVertices()
+{
+ video::SColor c(255, m_light, m_light, m_light);
+ m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
+ c, m_ap.x0(), m_ap.y1());
+ m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0,
+ c, m_ap.x1(), m_ap.y1());
+ m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0,
+ c, m_ap.x1(), m_ap.y0());
+ m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
+ c ,m_ap.x0(), m_ap.y0());
+
+ for(u16 i=0; i<4; i++)
+ {
+ m_vertices[i].Pos.rotateYZBy(m_player->getPitch());
+ m_vertices[i].Pos.rotateXZBy(m_player->getYaw());
+ m_box.addInternalPoint(m_vertices[i].Pos);
+ m_vertices[i].Pos += m_pos*BS;
+ }
+}
+
+
+/*
+ Helpers
+*/
+
void allparticles_step (float dtime, ClientEnvironment &env)
{
- for(std::vector<Particle*>::iterator i = all_particles.begin(); i != all_particles.end();)
+ for(std::vector<Particle*>::iterator i = all_particles.begin();
+ i != all_particles.end();)
{
if ((*i)->get_expired())
{
@@ -171,22 +223,28 @@ void allparticles_step (float dtime, ClientEnvironment &env)
}
}
-void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
+void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
+ LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
+ const TileSpec tiles[])
{
for (u16 j = 0; j < 32; j++) // set the amount of particles here
{
- addNodeParticle(gamedef, smgr, player, pos, tiles);
+ addNodeParticle(gamedef, smgr, player, env, pos, tiles);
}
}
-void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
+void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
+ LocalPlayer *player, ClientEnvironment &env,
+ v3s16 pos, const TileSpec tiles[])
{
- addNodeParticle(gamedef, smgr, player, pos, tiles);
+ addNodeParticle(gamedef, smgr, player, env, pos, tiles);
}
// add a particle of a node
// used by digging and punching particles
-void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
+void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
+ LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
+ const TileSpec tiles[])
{
// Texture
u8 texid = myrand_range(0,5);
@@ -205,7 +263,10 @@ void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer
ap.pos.Y = ap.y0() + (y1 - ap.y0()) * ((rand()%64)/64.-texsize);
// Physics
- v3f velocity((rand()%100/50.-1)/1.5, rand()%100/35., (rand()%100/50.-1)/1.5);
+ v3f velocity( (rand()%100/50.-1)/1.5,
+ rand()%100/35.,
+ (rand()%100/50.-1)/1.5);
+
v3f acceleration(0,-9,0);
v3f particlepos = v3f(
(f32)pos.X+rand()%100/200.-0.25,
@@ -213,17 +274,180 @@ void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer
(f32)pos.Z+rand()%100/200.-0.25
);
- Particle *particle = new Particle(
+ new Particle(
gamedef,
smgr,
player,
- 0,
+ env,
particlepos,
velocity,
acceleration,
rand()%100/100., // expiration time
visual_size,
+ true,
ap);
+}
- all_particles.push_back(particle);
+/*
+ ParticleSpawner
+*/
+
+ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, LocalPlayer *player,
+ u16 amount, float time,
+ v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
+ float minexptime, float maxexptime, float minsize, float maxsize,
+ bool collisiondetection, AtlasPointer ap, u32 id)
+{
+ m_gamedef = gamedef;
+ m_smgr = smgr;
+ m_player = player;
+ m_amount = amount;
+ m_spawntime = time;
+ m_minpos = minpos;
+ m_maxpos = maxpos;
+ m_minvel = minvel;
+ m_maxvel = maxvel;
+ m_minacc = minacc;
+ m_maxacc = maxacc;
+ m_minexptime = minexptime;
+ m_maxexptime = maxexptime;
+ m_minsize = minsize;
+ m_maxsize = maxsize;
+ m_collisiondetection = collisiondetection;
+ m_ap = ap;
+ m_time = 0;
+
+ for (u16 i = 0; i<=m_amount; i++)
+ {
+ float spawntime = (float)rand()/(float)RAND_MAX*m_spawntime;
+ m_spawntimes.push_back(spawntime);
+ }
+
+ all_particlespawners.insert(std::pair<u32, ParticleSpawner*>(id, this));
+}
+
+ParticleSpawner::~ParticleSpawner() {}
+
+void ParticleSpawner::step(float dtime, ClientEnvironment &env)
+{
+ m_time += dtime;
+
+ if (m_spawntime != 0) // Spawner exists for a predefined timespan
+ {
+ for(std::vector<float>::iterator i = m_spawntimes.begin();
+ i != m_spawntimes.end();)
+ {
+ if ((*i) <= m_time && m_amount > 0)
+ {
+ m_amount--;
+
+ v3f pos = random_v3f(m_minpos, m_maxpos);
+ v3f vel = random_v3f(m_minvel, m_maxvel);
+ v3f acc = random_v3f(m_minacc, m_maxacc);
+ float exptime = rand()/(float)RAND_MAX
+ *(m_maxexptime-m_minexptime)
+ +m_minexptime;
+ float size = rand()/(float)RAND_MAX
+ *(m_maxsize-m_minsize)
+ +m_minsize;
+
+ new Particle(
+ m_gamedef,
+ m_smgr,
+ m_player,
+ env,
+ pos,
+ vel,
+ acc,
+ exptime,
+ size,
+ m_collisiondetection,
+ m_ap);
+ m_spawntimes.erase(i);
+ }
+ else
+ {
+ i++;
+ }
+ }
+ }
+ else // Spawner exists for an infinity timespan, spawn on a per-second base
+ {
+ for (int i = 0; i <= m_amount; i++)
+ {
+ if (rand()/(float)RAND_MAX < dtime)
+ {
+ v3f pos = random_v3f(m_minpos, m_maxpos);
+ v3f vel = random_v3f(m_minvel, m_maxvel);
+ v3f acc = random_v3f(m_minacc, m_maxacc);
+ float exptime = rand()/(float)RAND_MAX
+ *(m_maxexptime-m_minexptime)
+ +m_minexptime;
+ float size = rand()/(float)RAND_MAX
+ *(m_maxsize-m_minsize)
+ +m_minsize;
+
+ new Particle(
+ m_gamedef,
+ m_smgr,
+ m_player,
+ env,
+ pos,
+ vel,
+ acc,
+ exptime,
+ size,
+ m_collisiondetection,
+ m_ap);
+ }
+ }
+ }
+}
+
+void allparticlespawners_step (float dtime, ClientEnvironment &env)
+{
+ for(std::map<u32, ParticleSpawner*>::iterator i =
+ all_particlespawners.begin();
+ i != all_particlespawners.end();)
+ {
+ if (i->second->get_expired())
+ {
+ delete i->second;
+ all_particlespawners.erase(i++);
+ }
+ else
+ {
+ i->second->step(dtime, env);
+ i++;
+ }
+ }
+}
+
+void delete_particlespawner (u32 id)
+{
+ if (all_particlespawners.find(id) != all_particlespawners.end())
+ {
+ delete all_particlespawners.find(id)->second;
+ all_particlespawners.erase(id);
+ }
+}
+
+void clear_particles ()
+{
+ for(std::map<u32, ParticleSpawner*>::iterator i =
+ all_particlespawners.begin();
+ i != all_particlespawners.end();)
+ {
+ delete i->second;
+ all_particlespawners.erase(i++);
+ }
+
+ for(std::vector<Particle*>::iterator i =
+ all_particles.begin();
+ i != all_particles.end();)
+ {
+ (*i)->remove();
+ delete *i;
+ all_particles.erase(i);
+ }
}
diff --git a/src/particles.h b/src/particles.h
index b317549e7..308da551f 100644
--- a/src/particles.h
+++ b/src/particles.h
@@ -35,12 +35,13 @@ class Particle : public scene::ISceneNode
IGameDef* gamedef,
scene::ISceneManager* mgr,
LocalPlayer *player,
- s32 id,
+ ClientEnvironment &env,
v3f pos,
v3f velocity,
v3f acceleration,
float expirationtime,
float size,
+ bool collisiondetection,
AtlasPointer texture
);
~Particle();
@@ -69,6 +70,10 @@ class Particle : public scene::ISceneNode
{ return m_expiration < m_time; }
private:
+ void updateLight(ClientEnvironment &env);
+ void updateVertices();
+
+ video::S3DVertex m_vertices[4];
float m_time;
float m_expiration;
@@ -87,12 +92,71 @@ private:
float m_size;
AtlasPointer m_ap;
u8 m_light;
+ bool m_collisiondetection;
+};
+
+class ParticleSpawner
+{
+ public:
+ ParticleSpawner(IGameDef* gamedef,
+ scene::ISceneManager *smgr,
+ LocalPlayer *player,
+ u16 amount,
+ float time,
+ v3f minp, v3f maxp,
+ v3f minvel, v3f maxvel,
+ v3f minacc, v3f maxacc,
+ float minexptime, float maxexptime,
+ float minsize, float maxsize,
+ bool collisiondetection,
+ AtlasPointer ap,
+ u32 id);
+
+ ~ParticleSpawner();
+
+ void step(float dtime, ClientEnvironment &env);
+
+ bool get_expired ()
+ { return (m_amount <= 0) && m_spawntime != 0; }
+
+ private:
+ float m_time;
+ IGameDef *m_gamedef;
+ scene::ISceneManager *m_smgr;
+ LocalPlayer *m_player;
+ u16 m_amount;
+ float m_spawntime;
+ v3f m_minpos;
+ v3f m_maxpos;
+ v3f m_minvel;
+ v3f m_maxvel;
+ v3f m_minacc;
+ v3f m_maxacc;
+ float m_minexptime;
+ float m_maxexptime;
+ float m_minsize;
+ float m_maxsize;
+ AtlasPointer m_ap;
+ std::vector<float> m_spawntimes;
+ bool m_collisiondetection;
};
void allparticles_step (float dtime, ClientEnvironment &env);
+void allparticlespawners_step (float dtime, ClientEnvironment &env);
+
+void delete_particlespawner (u32 id);
+void clear_particles ();
+
+void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
+ LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
+ const TileSpec tiles[]);
+
+void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
+ LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
+ const TileSpec tiles[]);
-void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
-void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
-void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
+void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
+ LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
+ const TileSpec tiles[]);
#endif
diff --git a/src/porting.h b/src/porting.h
index d7d107340..bcce96ef7 100644
--- a/src/porting.h
+++ b/src/porting.h
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h" // u32
#include "debug.h"
#include "constants.h"
+#include "gettime.h"
#ifdef _MSC_VER
#define SWPRINTF_CHARSTRING L"%S"
@@ -153,18 +154,65 @@ bool threadSetPriority(threadid_t tid, int prio);
*/
#ifdef _WIN32 // Windows
#include <windows.h>
+
+ inline u32 getTimeS()
+ {
+ return GetTickCount() / 1000;
+ }
+
inline u32 getTimeMs()
{
return GetTickCount();
}
+
+ inline u32 getTimeUs()
+ {
+ LARGE_INTEGER freq, t;
+ QueryPerformanceFrequency(&freq);
+ QueryPerformanceCounter(&t);
+ return (double)(t.QuadPart) / ((double)(freq.QuadPart) / 1000000.0);
+ }
+
+ inline u32 getTimeNs()
+ {
+ LARGE_INTEGER freq, t;
+ QueryPerformanceFrequency(&freq);
+ QueryPerformanceCounter(&t);
+ return (double)(t.QuadPart) / ((double)(freq.QuadPart) / 1000000000.0);
+ }
+
#else // Posix
#include <sys/time.h>
+ #include <time.h>
+
+ inline u32 getTimeS()
+ {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec;
+ }
+
inline u32 getTimeMs()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
+
+ inline u32 getTimeUs()
+ {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000 + tv.tv_usec;
+ }
+
+ inline u32 getTimeNs()
+ {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return ts.tv_sec * 1000000000 + ts.tv_nsec;
+ }
+
/*#include <sys/timeb.h>
inline u32 getTimeMs()
{
@@ -174,6 +222,22 @@ bool threadSetPriority(threadid_t tid, int prio);
}*/
#endif
+inline u32 getTime(TimePrecision prec)
+{
+ switch (prec) {
+ case PRECISION_SECONDS:
+ return getTimeS();
+ case PRECISION_MILLI:
+ return getTimeMs();
+ case PRECISION_MICRO:
+ return getTimeUs();
+ case PRECISION_NANO:
+ return getTimeNs();
+ }
+ return 0;
+}
+
+
} // namespace porting
#endif // PORTING_HEADER
diff --git a/src/profiler.h b/src/profiler.h
index b9fa22485..271ad70c1 100644
--- a/src/profiler.h
+++ b/src/profiler.h
@@ -45,21 +45,21 @@ public:
JMutexAutoLock lock(m_mutex);
{
/* No average shall have been used; mark add used as -2 */
- core::map<std::string, int>::Node *n = m_avgcounts.find(name);
- if(n == NULL)
+ std::map<std::string, int>::iterator n = m_avgcounts.find(name);
+ if(n == m_avgcounts.end())
m_avgcounts[name] = -2;
else{
- if(n->getValue() == -1)
- n->setValue(-2);
- assert(n->getValue() == -2);
+ if(n->second == -1)
+ n->second = -2;
+ assert(n->second == -2);
}
}
{
- core::map<std::string, float>::Node *n = m_data.find(name);
- if(n == NULL)
+ std::map<std::string, float>::iterator n = m_data.find(name);
+ if(n == m_data.end())
m_data[name] = value;
else
- n->setValue(n->getValue() + value);
+ n->second += value;
}
}
@@ -67,35 +67,32 @@ public:
{
JMutexAutoLock lock(m_mutex);
{
- core::map<std::string, int>::Node *n = m_avgcounts.find(name);
- if(n == NULL)
+ std::map<std::string, int>::iterator n = m_avgcounts.find(name);
+ if(n == m_avgcounts.end())
m_avgcounts[name] = 1;
else{
/* No add shall have been used */
- assert(n->getValue() != -2);
- if(n->getValue() <= 0)
- n->setValue(1);
- else
- n->setValue(n->getValue() + 1);
+ assert(n->second != -2);
+ n->second = (std::max)(n->second, 0) + 1;
}
}
{
- core::map<std::string, float>::Node *n = m_data.find(name);
- if(n == NULL)
+ std::map<std::string, float>::iterator n = m_data.find(name);
+ if(n == m_data.end())
m_data[name] = value;
else
- n->setValue(n->getValue() + value);
+ n->second += value;
}
}
void clear()
{
JMutexAutoLock lock(m_mutex);
- for(core::map<std::string, float>::Iterator
- i = m_data.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<std::string, float>::iterator
+ i = m_data.begin();
+ i != m_data.end(); ++i)
{
- i.getNode()->setValue(0);
+ i->second = 0;
}
m_avgcounts.clear();
}
@@ -112,9 +109,9 @@ public:
u32 minindex, maxindex;
paging(m_data.size(), page, pagecount, minindex, maxindex);
- for(core::map<std::string, float>::Iterator
- i = m_data.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<std::string, float>::iterator
+ i = m_data.begin();
+ i != m_data.end(); ++i)
{
if(maxindex == 0)
break;
@@ -126,12 +123,12 @@ public:
continue;
}
- std::string name = i.getNode()->getKey();
+ std::string name = i->first;
int avgcount = 1;
- core::map<std::string, int>::Node *n = m_avgcounts.find(name);
- if(n){
- if(n->getValue() >= 1)
- avgcount = n->getValue();
+ std::map<std::string, int>::iterator n = m_avgcounts.find(name);
+ if(n != m_avgcounts.end()){
+ if(n->second >= 1)
+ avgcount = n->second;
}
o<<" "<<name<<": ";
s32 clampsize = 40;
@@ -143,7 +140,7 @@ public:
else
o<<" ";
}
- o<<(i.getNode()->getValue() / avgcount);
+ o<<(i->second / avgcount);
o<<std::endl;
}
}
@@ -169,8 +166,8 @@ public:
private:
JMutex m_mutex;
- core::map<std::string, float> m_data;
- core::map<std::string, int> m_avgcounts;
+ std::map<std::string, float> m_data;
+ std::map<std::string, int> m_avgcounts;
std::map<std::string, float> m_graphvalues;
};
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index 7aa148fd6..80abffa2b 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -27,89 +27,29 @@ extern "C" {
#include <lauxlib.h>
}
-#include "log.h"
-#include "server.h"
-#include "porting.h"
-#include "filesys.h"
-#include "serverobject.h"
-#include "script.h"
-#include "object_properties.h"
-#include "content_sao.h" // For LuaEntitySAO and PlayerSAO
-#include "itemdef.h"
-#include "nodedef.h"
-#include "biome.h"
-#include "craftdef.h"
-#include "main.h" // For g_settings
#include "settings.h" // For accessing g_settings
-#include "nodemetadata.h"
-#include "mapblock.h" // For getNodeBlockPos
-#include "content_nodemeta.h"
-#include "tool.h"
-#include "daynightratio.h"
-#include "noise.h" // PseudoRandom for LuaPseudoRandom
-#include "util/pointedthing.h"
+#include "main.h" // For g_settings
+#include "biome.h"
+#include "emerge.h"
+#include "script.h"
#include "rollback.h"
-#include "treegen.h"
-
-static void stackDump(lua_State *L, std::ostream &o)
-{
- int i;
- int top = lua_gettop(L);
- for (i = 1; i <= top; i++) { /* repeat for each level */
- int t = lua_type(L, i);
- switch (t) {
-
- case LUA_TSTRING: /* strings */
- o<<"\""<<lua_tostring(L, i)<<"\"";
- break;
-
- case LUA_TBOOLEAN: /* booleans */
- o<<(lua_toboolean(L, i) ? "true" : "false");
- break;
-
- case LUA_TNUMBER: /* numbers */ {
- char buf[10];
- snprintf(buf, 10, "%g", lua_tonumber(L, i));
- o<<buf;
- break; }
-
- default: /* other values */
- o<<lua_typename(L, t);
- break;
-
- }
- o<<" ";
- }
- o<<std::endl;
-}
-static void realitycheck(lua_State *L)
-{
- int top = lua_gettop(L);
- if(top >= 30){
- dstream<<"Stack is over 30:"<<std::endl;
- stackDump(L, dstream);
- script_error(L, "Stack is over 30 (reality check)");
- }
-}
-
-class StackUnroller
-{
-private:
- lua_State *m_lua;
- int m_original_top;
-public:
- StackUnroller(lua_State *L):
- m_lua(L),
- m_original_top(-1)
- {
- m_original_top = lua_gettop(m_lua); // store stack height
- }
- ~StackUnroller()
- {
- lua_settop(m_lua, m_original_top); // restore stack height
- }
-};
+#include "scriptapi_types.h"
+#include "scriptapi_env.h"
+#include "scriptapi_nodetimer.h"
+#include "scriptapi_inventory.h"
+#include "scriptapi_nodemeta.h"
+#include "scriptapi_object.h"
+#include "scriptapi_noise.h"
+#include "scriptapi_common.h"
+#include "scriptapi_item.h"
+#include "scriptapi_content.h"
+#include "scriptapi_craft.h"
+#include "scriptapi_particles.h"
+
+/*****************************************************************************/
+/* Mod related */
+/*****************************************************************************/
class ModNameStorer
{
@@ -131,596 +71,150 @@ public:
}
};
-/*
- Getters for stuff in main tables
-*/
-
-static Server* get_server(lua_State *L)
-{
- // Get server from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
- Server *server = (Server*)lua_touserdata(L, -1);
- lua_pop(L, 1);
- return server;
-}
-
-static ServerEnvironment* get_env(lua_State *L)
-{
- // Get environment from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
- ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1);
- lua_pop(L, 1);
- return env;
-}
-
-static void objectref_get(lua_State *L, u16 id)
-{
- // Get minetest.object_refs[i]
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "object_refs");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushnumber(L, id);
- lua_gettable(L, -2);
- lua_remove(L, -2); // object_refs
- lua_remove(L, -2); // minetest
-}
-
-static void luaentity_get(lua_State *L, u16 id)
-{
- // Get minetest.luaentities[i]
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "luaentities");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushnumber(L, id);
- lua_gettable(L, -2);
- lua_remove(L, -2); // luaentities
- lua_remove(L, -2); // minetest
-}
-
-/*
- Table field getters
-*/
-
-static bool getstringfield(lua_State *L, int table,
- const char *fieldname, std::string &result)
-{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isstring(L, -1)){
- size_t len = 0;
- const char *ptr = lua_tolstring(L, -1, &len);
- result.assign(ptr, len);
- got = true;
- }
- lua_pop(L, 1);
- return got;
-}
-
-static bool getintfield(lua_State *L, int table,
- const char *fieldname, int &result)
-{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isnumber(L, -1)){
- result = lua_tonumber(L, -1);
- got = true;
- }
- lua_pop(L, 1);
- return got;
-}
-
-static bool getfloatfield(lua_State *L, int table,
- const char *fieldname, float &result)
+bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
+ const std::string &modname)
{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isnumber(L, -1)){
- result = lua_tonumber(L, -1);
- got = true;
- }
- lua_pop(L, 1);
- return got;
-}
+ ModNameStorer modnamestorer(L, modname);
-static bool getboolfield(lua_State *L, int table,
- const char *fieldname, bool &result)
-{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isboolean(L, -1)){
- result = lua_toboolean(L, -1);
- got = true;
+ if(!string_allowed(modname, "abcdefghijklmnopqrstuvwxyz"
+ "0123456789_")){
+ errorstream<<"Error loading mod \""<<modname
+ <<"\": modname does not follow naming conventions: "
+ <<"Only chararacters [a-z0-9_] are allowed."<<std::endl;
+ return false;
}
- lua_pop(L, 1);
- return got;
-}
-
-static std::string checkstringfield(lua_State *L, int table,
- const char *fieldname)
-{
- lua_getfield(L, table, fieldname);
- std::string s = luaL_checkstring(L, -1);
- lua_pop(L, 1);
- return s;
-}
-static std::string getstringfield_default(lua_State *L, int table,
- const char *fieldname, const std::string &default_)
-{
- std::string result = default_;
- getstringfield(L, table, fieldname, result);
- return result;
-}
-
-static int getintfield_default(lua_State *L, int table,
- const char *fieldname, int default_)
-{
- int result = default_;
- getintfield(L, table, fieldname, result);
- return result;
-}
-
-static float getfloatfield_default(lua_State *L, int table,
- const char *fieldname, float default_)
-{
- float result = default_;
- getfloatfield(L, table, fieldname, result);
- return result;
-}
-
-static bool getboolfield_default(lua_State *L, int table,
- const char *fieldname, bool default_)
-{
- bool result = default_;
- getboolfield(L, table, fieldname, result);
- return result;
-}
-
-struct EnumString
-{
- int num;
- const char *str;
-};
+ bool success = false;
-static bool string_to_enum(const EnumString *spec, int &result,
- const std::string &str)
-{
- const EnumString *esp = spec;
- while(esp->str){
- if(str == std::string(esp->str)){
- result = esp->num;
- return true;
- }
- esp++;
+ try{
+ success = script_load(L, scriptpath.c_str());
}
- return false;
-}
-
-/*static bool enum_to_string(const EnumString *spec, std::string &result,
- int num)
-{
- const EnumString *esp = spec;
- while(esp){
- if(num == esp->num){
- result = esp->str;
- return true;
- }
- esp++;
+ catch(LuaError &e){
+ errorstream<<"Error loading mod \""<<modname
+ <<"\": "<<e.what()<<std::endl;
}
- return false;
-}*/
-
-static int getenumfield(lua_State *L, int table,
- const char *fieldname, const EnumString *spec, int default_)
-{
- int result = default_;
- string_to_enum(spec, result,
- getstringfield_default(L, table, fieldname, ""));
- return result;
-}
-
-static void setintfield(lua_State *L, int table,
- const char *fieldname, int value)
-{
- lua_pushinteger(L, value);
- if(table < 0)
- table -= 1;
- lua_setfield(L, table, fieldname);
-}
-static void setfloatfield(lua_State *L, int table,
- const char *fieldname, float value)
-{
- lua_pushnumber(L, value);
- if(table < 0)
- table -= 1;
- lua_setfield(L, table, fieldname);
-}
-
-static void setboolfield(lua_State *L, int table,
- const char *fieldname, bool value)
-{
- lua_pushboolean(L, value);
- if(table < 0)
- table -= 1;
- lua_setfield(L, table, fieldname);
-}
-
-static void warn_if_field_exists(lua_State *L, int table,
- const char *fieldname, const std::string &message)
-{
- lua_getfield(L, table, fieldname);
- if(!lua_isnil(L, -1)){
- infostream<<script_get_backtrace(L)<<std::endl;
- infostream<<"WARNING: field \""<<fieldname<<"\": "
- <<message<<std::endl;
- }
- lua_pop(L, 1);
+ return success;
}
-/*
- EnumString definitions
-*/
-
-struct EnumString es_ItemType[] =
-{
- {ITEM_NONE, "none"},
- {ITEM_NODE, "node"},
- {ITEM_CRAFT, "craft"},
- {ITEM_TOOL, "tool"},
- {0, NULL},
-};
-
-struct EnumString es_DrawType[] =
-{
- {NDT_NORMAL, "normal"},
- {NDT_AIRLIKE, "airlike"},
- {NDT_LIQUID, "liquid"},
- {NDT_FLOWINGLIQUID, "flowingliquid"},
- {NDT_GLASSLIKE, "glasslike"},
- {NDT_ALLFACES, "allfaces"},
- {NDT_ALLFACES_OPTIONAL, "allfaces_optional"},
- {NDT_TORCHLIKE, "torchlike"},
- {NDT_SIGNLIKE, "signlike"},
- {NDT_PLANTLIKE, "plantlike"},
- {NDT_FENCELIKE, "fencelike"},
- {NDT_RAILLIKE, "raillike"},
- {NDT_NODEBOX, "nodebox"},
- {0, NULL},
-};
-
-struct EnumString es_ContentParamType[] =
-{
- {CPT_NONE, "none"},
- {CPT_LIGHT, "light"},
- {0, NULL},
-};
-
-struct EnumString es_ContentParamType2[] =
-{
- {CPT2_NONE, "none"},
- {CPT2_FULL, "full"},
- {CPT2_FLOWINGLIQUID, "flowingliquid"},
- {CPT2_FACEDIR, "facedir"},
- {CPT2_WALLMOUNTED, "wallmounted"},
- {0, NULL},
-};
-
-struct EnumString es_LiquidType[] =
-{
- {LIQUID_NONE, "none"},
- {LIQUID_FLOWING, "flowing"},
- {LIQUID_SOURCE, "source"},
- {0, NULL},
-};
-struct EnumString es_NodeBoxType[] =
-{
- {NODEBOX_REGULAR, "regular"},
- {NODEBOX_FIXED, "fixed"},
- {NODEBOX_WALLMOUNTED, "wallmounted"},
- {0, NULL},
-};
-
-struct EnumString es_CraftMethod[] =
-{
- {CRAFT_METHOD_NORMAL, "normal"},
- {CRAFT_METHOD_COOKING, "cooking"},
- {CRAFT_METHOD_FUEL, "fuel"},
- {0, NULL},
-};
-
-struct EnumString es_TileAnimationType[] =
-{
- {TAT_NONE, "none"},
- {TAT_VERTICAL_FRAMES, "vertical_frames"},
- {0, NULL},
-};
-
-struct EnumString es_BiomeTerrainType[] =
-{
- {BIOME_TERRAIN_NORMAL, "normal"},
- {BIOME_TERRAIN_LIQUID, "liquid"},
- {BIOME_TERRAIN_NETHER, "nether"},
- {BIOME_TERRAIN_AETHER, "aether"},
- {BIOME_TERRAIN_FLAT, "flat"},
- {0, NULL},
-};
+/*****************************************************************************/
+/* Auth */
+/*****************************************************************************/
/*
- C struct <-> Lua table converter functions
+ Privileges
*/
-
-static void push_v3f(lua_State *L, v3f p)
-{
- lua_newtable(L);
- lua_pushnumber(L, p.X);
- lua_setfield(L, -2, "x");
- lua_pushnumber(L, p.Y);
- lua_setfield(L, -2, "y");
- lua_pushnumber(L, p.Z);
- lua_setfield(L, -2, "z");
-}
-
-static v2s16 read_v2s16(lua_State *L, int index)
-{
- v2s16 p;
- luaL_checktype(L, index, LUA_TTABLE);
- lua_getfield(L, index, "x");
- p.X = lua_tonumber(L, -1);
- lua_pop(L, 1);
- lua_getfield(L, index, "y");
- p.Y = lua_tonumber(L, -1);
- lua_pop(L, 1);
- return p;
-}
-
-static v2f read_v2f(lua_State *L, int index)
-{
- v2f p;
- luaL_checktype(L, index, LUA_TTABLE);
- lua_getfield(L, index, "x");
- p.X = lua_tonumber(L, -1);
- lua_pop(L, 1);
- lua_getfield(L, index, "y");
- p.Y = lua_tonumber(L, -1);
- lua_pop(L, 1);
- return p;
-}
-
-static v3f read_v3f(lua_State *L, int index)
-{
- v3f pos;
- luaL_checktype(L, index, LUA_TTABLE);
- lua_getfield(L, index, "x");
- pos.X = lua_tonumber(L, -1);
- lua_pop(L, 1);
- lua_getfield(L, index, "y");
- pos.Y = lua_tonumber(L, -1);
- lua_pop(L, 1);
- lua_getfield(L, index, "z");
- pos.Z = lua_tonumber(L, -1);
- lua_pop(L, 1);
- return pos;
-}
-
-static v3f check_v3f(lua_State *L, int index)
-{
- v3f pos;
- luaL_checktype(L, index, LUA_TTABLE);
- lua_getfield(L, index, "x");
- pos.X = luaL_checknumber(L, -1);
- lua_pop(L, 1);
- lua_getfield(L, index, "y");
- pos.Y = luaL_checknumber(L, -1);
- lua_pop(L, 1);
- lua_getfield(L, index, "z");
- pos.Z = luaL_checknumber(L, -1);
- lua_pop(L, 1);
- return pos;
-}
-
-static void pushFloatPos(lua_State *L, v3f p)
+static void read_privileges(lua_State *L, int index,
+ std::set<std::string> &result)
{
- p /= BS;
- push_v3f(L, p);
+ result.clear();
+ lua_pushnil(L);
+ if(index < 0)
+ index -= 1;
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ std::string key = luaL_checkstring(L, -2);
+ bool value = lua_toboolean(L, -1);
+ if(value)
+ result.insert(key);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
}
-static v3f checkFloatPos(lua_State *L, int index)
+static void get_auth_handler(lua_State *L)
{
- return check_v3f(L, index) * BS;
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_auth_handler");
+ if(lua_isnil(L, -1)){
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "builtin_auth_handler");
+ }
+ if(lua_type(L, -1) != LUA_TTABLE)
+ throw LuaError(L, "Authentication handler table not valid");
}
-static void push_v3s16(lua_State *L, v3s16 p)
+bool scriptapi_get_auth(lua_State *L, const std::string &playername,
+ std::string *dst_password, std::set<std::string> *dst_privs)
{
- lua_newtable(L);
- lua_pushnumber(L, p.X);
- lua_setfield(L, -2, "x");
- lua_pushnumber(L, p.Y);
- lua_setfield(L, -2, "y");
- lua_pushnumber(L, p.Z);
- lua_setfield(L, -2, "z");
-}
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
-static v3s16 read_v3s16(lua_State *L, int index)
-{
- // Correct rounding at <0
- v3f pf = read_v3f(L, index);
- return floatToInt(pf, 1.0);
-}
+ get_auth_handler(L);
+ lua_getfield(L, -1, "get_auth");
+ if(lua_type(L, -1) != LUA_TFUNCTION)
+ throw LuaError(L, "Authentication handler missing get_auth");
+ lua_pushstring(L, playername.c_str());
+ if(lua_pcall(L, 1, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
-static v3s16 check_v3s16(lua_State *L, int index)
-{
- // Correct rounding at <0
- v3f pf = check_v3f(L, index);
- return floatToInt(pf, 1.0);
-}
+ // nil = login not allowed
+ if(lua_isnil(L, -1))
+ return false;
+ luaL_checktype(L, -1, LUA_TTABLE);
-static void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
-{
- lua_newtable(L);
- lua_pushstring(L, ndef->get(n).name.c_str());
- lua_setfield(L, -2, "name");
- lua_pushnumber(L, n.getParam1());
- lua_setfield(L, -2, "param1");
- lua_pushnumber(L, n.getParam2());
- lua_setfield(L, -2, "param2");
-}
+ std::string password;
+ bool found = getstringfield(L, -1, "password", password);
+ if(!found)
+ throw LuaError(L, "Authentication handler didn't return password");
+ if(dst_password)
+ *dst_password = password;
-static MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
-{
- lua_getfield(L, index, "name");
- const char *name = luaL_checkstring(L, -1);
- lua_pop(L, 1);
- u8 param1;
- lua_getfield(L, index, "param1");
- if(lua_isnil(L, -1))
- param1 = 0;
- else
- param1 = lua_tonumber(L, -1);
- lua_pop(L, 1);
- u8 param2;
- lua_getfield(L, index, "param2");
- if(lua_isnil(L, -1))
- param2 = 0;
- else
- param2 = lua_tonumber(L, -1);
+ lua_getfield(L, -1, "privileges");
+ if(!lua_istable(L, -1))
+ throw LuaError(L,
+ "Authentication handler didn't return privilege table");
+ if(dst_privs)
+ read_privileges(L, -1, *dst_privs);
lua_pop(L, 1);
- return MapNode(ndef, name, param1, param2);
-}
-static video::SColor readARGB8(lua_State *L, int index)
-{
- video::SColor color;
- luaL_checktype(L, index, LUA_TTABLE);
- lua_getfield(L, index, "a");
- if(lua_isnumber(L, -1))
- color.setAlpha(lua_tonumber(L, -1));
- lua_pop(L, 1);
- lua_getfield(L, index, "r");
- color.setRed(lua_tonumber(L, -1));
- lua_pop(L, 1);
- lua_getfield(L, index, "g");
- color.setGreen(lua_tonumber(L, -1));
- lua_pop(L, 1);
- lua_getfield(L, index, "b");
- color.setBlue(lua_tonumber(L, -1));
- lua_pop(L, 1);
- return color;
+ return true;
}
-static aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
+void scriptapi_create_auth(lua_State *L, const std::string &playername,
+ const std::string &password)
{
- aabb3f box;
- if(lua_istable(L, index)){
- lua_rawgeti(L, index, 1);
- box.MinEdge.X = lua_tonumber(L, -1) * scale;
- lua_pop(L, 1);
- lua_rawgeti(L, index, 2);
- box.MinEdge.Y = lua_tonumber(L, -1) * scale;
- lua_pop(L, 1);
- lua_rawgeti(L, index, 3);
- box.MinEdge.Z = lua_tonumber(L, -1) * scale;
- lua_pop(L, 1);
- lua_rawgeti(L, index, 4);
- box.MaxEdge.X = lua_tonumber(L, -1) * scale;
- lua_pop(L, 1);
- lua_rawgeti(L, index, 5);
- box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
- lua_pop(L, 1);
- lua_rawgeti(L, index, 6);
- box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
- lua_pop(L, 1);
- }
- return box;
-}
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
-static std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
-{
- std::vector<aabb3f> boxes;
- if(lua_istable(L, index)){
- int n = lua_objlen(L, index);
- // Check if it's a single box or a list of boxes
- bool possibly_single_box = (n == 6);
- for(int i = 1; i <= n && possibly_single_box; i++){
- lua_rawgeti(L, index, i);
- if(!lua_isnumber(L, -1))
- possibly_single_box = false;
- lua_pop(L, 1);
- }
- if(possibly_single_box){
- // Read a single box
- boxes.push_back(read_aabb3f(L, index, scale));
- } else {
- // Read a list of boxes
- for(int i = 1; i <= n; i++){
- lua_rawgeti(L, index, i);
- boxes.push_back(read_aabb3f(L, -1, scale));
- lua_pop(L, 1);
- }
- }
- }
- return boxes;
+ get_auth_handler(L);
+ lua_getfield(L, -1, "create_auth");
+ if(lua_type(L, -1) != LUA_TFUNCTION)
+ throw LuaError(L, "Authentication handler missing create_auth");
+ lua_pushstring(L, playername.c_str());
+ lua_pushstring(L, password.c_str());
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
}
-static NodeBox read_nodebox(lua_State *L, int index)
+bool scriptapi_set_password(lua_State *L, const std::string &playername,
+ const std::string &password)
{
- NodeBox nodebox;
- if(lua_istable(L, -1)){
- nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
- es_NodeBoxType, NODEBOX_REGULAR);
-
- lua_getfield(L, index, "fixed");
- if(lua_istable(L, -1))
- nodebox.fixed = read_aabb3f_vector(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "wall_top");
- if(lua_istable(L, -1))
- nodebox.wall_top = read_aabb3f(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "wall_bottom");
- if(lua_istable(L, -1))
- nodebox.wall_bottom = read_aabb3f(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "wall_side");
- if(lua_istable(L, -1))
- nodebox.wall_side = read_aabb3f(L, -1, BS);
- lua_pop(L, 1);
- }
- return nodebox;
-}
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
-/*
- NoiseParams
-*/
-static NoiseParams *read_noiseparams(lua_State *L, int index)
-{
- if (index < 0)
- index = lua_gettop(L) + 1 + index;
-
- if (!lua_istable(L, index))
- return NULL;
-
- NoiseParams *np = new NoiseParams;
-
- np->offset = getfloatfield_default(L, index, "offset", 0.0);
- np->scale = getfloatfield_default(L, index, "scale", 0.0);
- lua_getfield(L, index, "spread");
- np->spread = read_v3f(L, -1);
- np->seed = getintfield_default(L, index, "seed", 0);
- np->octaves = getintfield_default(L, index, "octaves", 0);
- np->persist = getfloatfield_default(L, index, "persist", 0.0);
-
- return np;
+ get_auth_handler(L);
+ lua_getfield(L, -1, "set_password");
+ if(lua_type(L, -1) != LUA_TFUNCTION)
+ throw LuaError(L, "Authentication handler missing set_password");
+ lua_pushstring(L, playername.c_str());
+ lua_pushstring(L, password.c_str());
+ if(lua_pcall(L, 2, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return lua_toboolean(L, -1);
}
+/*****************************************************************************/
+/* Misc */
+/*****************************************************************************/
/*
Groups
*/
-static void read_groups(lua_State *L, int index,
+void read_groups(lua_State *L, int index,
std::map<std::string, int> &result)
{
if (!lua_istable(L,index))
@@ -739,131 +233,27 @@ static void read_groups(lua_State *L, int index,
}
}
-/*
- Privileges
-*/
-static void read_privileges(lua_State *L, int index,
- std::set<std::string> &result)
-{
- result.clear();
- lua_pushnil(L);
- if(index < 0)
- index -= 1;
- while(lua_next(L, index) != 0){
- // key at index -2 and value at index -1
- std::string key = luaL_checkstring(L, -2);
- bool value = lua_toboolean(L, -1);
- if(value)
- result.insert(key);
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
-}
-
-/*
- ToolCapabilities
-*/
-
-static ToolCapabilities read_tool_capabilities(
- lua_State *L, int table)
-{
- ToolCapabilities toolcap;
- getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
- getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
- lua_getfield(L, table, "groupcaps");
- if(lua_istable(L, -1)){
- int table_groupcaps = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table_groupcaps) != 0){
- // key at index -2 and value at index -1
- std::string groupname = luaL_checkstring(L, -2);
- if(lua_istable(L, -1)){
- int table_groupcap = lua_gettop(L);
- // This will be created
- ToolGroupCap groupcap;
- // Read simple parameters
- getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
- getintfield(L, table_groupcap, "uses", groupcap.uses);
- // DEPRECATED: maxwear
- float maxwear = 0;
- if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
- if(maxwear != 0)
- groupcap.uses = 1.0/maxwear;
- else
- groupcap.uses = 0;
- infostream<<script_get_backtrace(L)<<std::endl;
- infostream<<"WARNING: field \"maxwear\" is deprecated; "
- <<"should replace with uses=1/maxwear"<<std::endl;
- }
- // Read "times" table
- lua_getfield(L, table_groupcap, "times");
- if(lua_istable(L, -1)){
- int table_times = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table_times) != 0){
- // key at index -2 and value at index -1
- int rating = luaL_checkinteger(L, -2);
- float time = luaL_checknumber(L, -1);
- groupcap.times[rating] = time;
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- }
- lua_pop(L, 1);
- // Insert groupcap into toolcap
- toolcap.groupcaps[groupname] = groupcap;
- }
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- }
- lua_pop(L, 1);
- return toolcap;
-}
-
-static void set_tool_capabilities(lua_State *L, int table,
- const ToolCapabilities &toolcap)
+struct EnumString es_BiomeTerrainType[] =
{
- setfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
- setintfield(L, table, "max_drop_level", toolcap.max_drop_level);
- // Create groupcaps table
- lua_newtable(L);
- // For each groupcap
- for(std::map<std::string, ToolGroupCap>::const_iterator
- i = toolcap.groupcaps.begin(); i != toolcap.groupcaps.end(); i++){
- // Create groupcap table
- lua_newtable(L);
- const std::string &name = i->first;
- const ToolGroupCap &groupcap = i->second;
- // Create subtable "times"
- lua_newtable(L);
- for(std::map<int, float>::const_iterator
- i = groupcap.times.begin(); i != groupcap.times.end(); i++){
- int rating = i->first;
- float time = i->second;
- lua_pushinteger(L, rating);
- lua_pushnumber(L, time);
- lua_settable(L, -3);
- }
- // Set subtable "times"
- lua_setfield(L, -2, "times");
- // Set simple parameters
- setintfield(L, -1, "maxlevel", groupcap.maxlevel);
- setintfield(L, -1, "uses", groupcap.uses);
- // Insert groupcap table into groupcaps table
- lua_setfield(L, -2, name.c_str());
- }
- // Set groupcaps table
- lua_setfield(L, -2, "groupcaps");
-}
+ {BIOME_TERRAIN_NORMAL, "normal"},
+ {BIOME_TERRAIN_LIQUID, "liquid"},
+ {BIOME_TERRAIN_NETHER, "nether"},
+ {BIOME_TERRAIN_AETHER, "aether"},
+ {BIOME_TERRAIN_FLAT, "flat"},
+ {0, NULL},
+};
-static void push_tool_capabilities(lua_State *L,
- const ToolCapabilities &prop)
+struct EnumString es_OreType[] =
{
- lua_newtable(L);
- set_tool_capabilities(L, -1, prop);
-}
+ {ORE_SCATTER, "scatter"},
+ {ORE_SHEET, "sheet"},
+ {ORE_CLAYLIKE, "claylike"},
+ {0, NULL},
+};
+/*****************************************************************************/
+/* Parameters */
+/*****************************************************************************/
/*
DigParams
*/
@@ -902,3692 +292,279 @@ static void push_hit_params(lua_State *L,
}
/*
- PointedThing
-*/
-
-static void push_pointed_thing(lua_State *L, const PointedThing& pointed)
-{
- lua_newtable(L);
- if(pointed.type == POINTEDTHING_NODE)
- {
- lua_pushstring(L, "node");
- lua_setfield(L, -2, "type");
- push_v3s16(L, pointed.node_undersurface);
- lua_setfield(L, -2, "under");
- push_v3s16(L, pointed.node_abovesurface);
- lua_setfield(L, -2, "above");
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- lua_pushstring(L, "object");
- lua_setfield(L, -2, "type");
- objectref_get(L, pointed.object_id);
- lua_setfield(L, -2, "ref");
- }
- else
- {
- lua_pushstring(L, "nothing");
- lua_setfield(L, -2, "type");
- }
-}
-
-/*
- SimpleSoundSpec
-*/
-
-static void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
- if(lua_isnil(L, index)){
- } else if(lua_istable(L, index)){
- getstringfield(L, index, "name", spec.name);
- getfloatfield(L, index, "gain", spec.gain);
- } else if(lua_isstring(L, index)){
- spec.name = lua_tostring(L, index);
- }
-}
-
-/*
- ObjectProperties
-*/
-
-static void read_object_properties(lua_State *L, int index,
- ObjectProperties *prop)
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
- if(!lua_istable(L, index))
- return;
-
- prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
-
- getboolfield(L, -1, "physical", prop->physical);
-
- getfloatfield(L, -1, "weight", prop->weight);
-
- lua_getfield(L, -1, "collisionbox");
- if(lua_istable(L, -1))
- prop->collisionbox = read_aabb3f(L, -1, 1.0);
- lua_pop(L, 1);
-
- getstringfield(L, -1, "visual", prop->visual);
-
- getstringfield(L, -1, "mesh", prop->mesh);
-
- lua_getfield(L, -1, "visual_size");
- if(lua_istable(L, -1))
- prop->visual_size = read_v2f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "textures");
- if(lua_istable(L, -1)){
- prop->textures.clear();
- int table = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- if(lua_isstring(L, -1))
- prop->textures.push_back(lua_tostring(L, -1));
- else
- prop->textures.push_back("");
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- }
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "colors");
- if(lua_istable(L, -1)){
- prop->colors.clear();
- int table = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- if(lua_isstring(L, -1))
- prop->colors.push_back(readARGB8(L, -1));
- else
- prop->colors.push_back(video::SColor(255, 255, 255, 255));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- }
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "spritediv");
- if(lua_istable(L, -1))
- prop->spritediv = read_v2s16(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "initial_sprite_basepos");
- if(lua_istable(L, -1))
- prop->initial_sprite_basepos = read_v2s16(L, -1);
- lua_pop(L, 1);
-
- getboolfield(L, -1, "is_visible", prop->is_visible);
- getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
- getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
-}
-
-/*
- ItemDefinition
-*/
-
-static ItemDefinition read_item_definition(lua_State *L, int index,
- ItemDefinition default_def = ItemDefinition())
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
-
- // Read the item definition
- ItemDefinition def = default_def;
-
- def.type = (ItemType)getenumfield(L, index, "type",
- es_ItemType, ITEM_NONE);
- getstringfield(L, index, "name", def.name);
- getstringfield(L, index, "description", def.description);
- getstringfield(L, index, "inventory_image", def.inventory_image);
- getstringfield(L, index, "wield_image", def.wield_image);
-
- lua_getfield(L, index, "wield_scale");
- if(lua_istable(L, -1)){
- def.wield_scale = check_v3f(L, -1);
- }
- lua_pop(L, 1);
-
- def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
- if(def.stack_max == 0)
- def.stack_max = 1;
-
- lua_getfield(L, index, "on_use");
- def.usable = lua_isfunction(L, -1);
- lua_pop(L, 1);
-
- getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
-
- warn_if_field_exists(L, index, "tool_digging_properties",
- "deprecated: use tool_capabilities");
-
- lua_getfield(L, index, "tool_capabilities");
- if(lua_istable(L, -1)){
- def.tool_capabilities = new ToolCapabilities(
- read_tool_capabilities(L, -1));
- }
-
- // If name is "" (hand), ensure there are ToolCapabilities
- // because it will be looked up there whenever any other item has
- // no ToolCapabilities
- if(def.name == "" && def.tool_capabilities == NULL){
- def.tool_capabilities = new ToolCapabilities();
- }
-
- lua_getfield(L, index, "groups");
- read_groups(L, -1, def.groups);
- lua_pop(L, 1);
-
- // Client shall immediately place this node when player places the item.
- // Server will update the precise end result a moment later.
- // "" = no prediction
- getstringfield(L, index, "node_placement_prediction",
- def.node_placement_prediction);
-
- return def;
-}
-
-/*
- TileDef
+ ServerSoundParams
*/
-static TileDef read_tiledef(lua_State *L, int index)
+static void read_server_sound_params(lua_State *L, int index,
+ ServerSoundParams &params)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
-
- TileDef tiledef;
-
- // key at index -2 and value at index
- if(lua_isstring(L, index)){
- // "default_lava.png"
- tiledef.name = lua_tostring(L, index);
- }
- else if(lua_istable(L, index))
- {
- // {name="default_lava.png", animation={}}
- tiledef.name = "";
- getstringfield(L, index, "name", tiledef.name);
- getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
- tiledef.backface_culling = getboolfield_default(
- L, index, "backface_culling", true);
- // animation = {}
- lua_getfield(L, index, "animation");
- if(lua_istable(L, -1)){
- // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
- tiledef.animation.type = (TileAnimationType)
- getenumfield(L, -1, "type", es_TileAnimationType,
- TAT_NONE);
- tiledef.animation.aspect_w =
- getintfield_default(L, -1, "aspect_w", 16);
- tiledef.animation.aspect_h =
- getintfield_default(L, -1, "aspect_h", 16);
- tiledef.animation.length =
- getfloatfield_default(L, -1, "length", 1.0);
+ // Clear
+ params = ServerSoundParams();
+ if(lua_istable(L, index)){
+ getfloatfield(L, index, "gain", params.gain);
+ getstringfield(L, index, "to_player", params.to_player);
+ lua_getfield(L, index, "pos");
+ if(!lua_isnil(L, -1)){
+ v3f p = read_v3f(L, -1)*BS;
+ params.pos = p;
+ params.type = ServerSoundParams::SSP_POSITIONAL;
}
lua_pop(L, 1);
- }
-
- return tiledef;
-}
-
-/*
- ContentFeatures
-*/
-
-static ContentFeatures read_content_features(lua_State *L, int index)
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
-
- ContentFeatures f;
-
- /* Cache existence of some callbacks */
- lua_getfield(L, index, "on_construct");
- if(!lua_isnil(L, -1)) f.has_on_construct = true;
- lua_pop(L, 1);
- lua_getfield(L, index, "on_destruct");
- if(!lua_isnil(L, -1)) f.has_on_destruct = true;
- lua_pop(L, 1);
- lua_getfield(L, index, "after_destruct");
- if(!lua_isnil(L, -1)) f.has_after_destruct = true;
- lua_pop(L, 1);
-
- lua_getfield(L, index, "on_rightclick");
- f.rightclickable = lua_isfunction(L, -1);
- lua_pop(L, 1);
-
- /* Name */
- getstringfield(L, index, "name", f.name);
-
- /* Groups */
- lua_getfield(L, index, "groups");
- read_groups(L, -1, f.groups);
- lua_pop(L, 1);
-
- /* Visual definition */
-
- f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", es_DrawType,
- NDT_NORMAL);
- getfloatfield(L, index, "visual_scale", f.visual_scale);
-
- // tiles = {}
- lua_getfield(L, index, "tiles");
- // If nil, try the deprecated name "tile_images" instead
- if(lua_isnil(L, -1)){
- lua_pop(L, 1);
- warn_if_field_exists(L, index, "tile_images",
- "Deprecated; new name is \"tiles\".");
- lua_getfield(L, index, "tile_images");
- }
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- int i = 0;
- while(lua_next(L, table) != 0){
- // Read tiledef from value
- f.tiledef[i] = read_tiledef(L, -1);
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- i++;
- if(i==6){
- lua_pop(L, 1);
- break;
- }
- }
- // Copy last value to all remaining textures
- if(i >= 1){
- TileDef lasttile = f.tiledef[i-1];
- while(i < 6){
- f.tiledef[i] = lasttile;
- i++;
- }
- }
- }
- lua_pop(L, 1);
-
- // special_tiles = {}
- lua_getfield(L, index, "special_tiles");
- // If nil, try the deprecated name "special_materials" instead
- if(lua_isnil(L, -1)){
- lua_pop(L, 1);
- warn_if_field_exists(L, index, "special_materials",
- "Deprecated; new name is \"special_tiles\".");
- lua_getfield(L, index, "special_materials");
- }
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- int i = 0;
- while(lua_next(L, table) != 0){
- // Read tiledef from value
- f.tiledef_special[i] = read_tiledef(L, -1);
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- i++;
- if(i==6){
- lua_pop(L, 1);
- break;
+ lua_getfield(L, index, "object");
+ if(!lua_isnil(L, -1)){
+ ObjectRef *ref = ObjectRef::checkobject(L, -1);
+ ServerActiveObject *sao = ObjectRef::getobject(ref);
+ if(sao){
+ params.object = sao->getId();
+ params.type = ServerSoundParams::SSP_OBJECT;
}
}
- }
- lua_pop(L, 1);
-
- f.alpha = getintfield_default(L, index, "alpha", 255);
-
- /* Other stuff */
-
- lua_getfield(L, index, "post_effect_color");
- if(!lua_isnil(L, -1))
- f.post_effect_color = readARGB8(L, -1);
- lua_pop(L, 1);
-
- f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
- es_ContentParamType, CPT_NONE);
- f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
- es_ContentParamType2, CPT2_NONE);
-
- // Warn about some deprecated fields
- warn_if_field_exists(L, index, "wall_mounted",
- "deprecated: use paramtype2 = 'wallmounted'");
- warn_if_field_exists(L, index, "light_propagates",
- "deprecated: determined from paramtype");
- warn_if_field_exists(L, index, "dug_item",
- "deprecated: use 'drop' field");
- warn_if_field_exists(L, index, "extra_dug_item",
- "deprecated: use 'drop' field");
- warn_if_field_exists(L, index, "extra_dug_item_rarity",
- "deprecated: use 'drop' field");
- warn_if_field_exists(L, index, "metadata_name",
- "deprecated: use on_add and metadata callbacks");
-
- // True for all ground-like things like stone and mud, false for eg. trees
- getboolfield(L, index, "is_ground_content", f.is_ground_content);
- f.light_propagates = (f.param_type == CPT_LIGHT);
- getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
- // This is used for collision detection.
- // Also for general solidness queries.
- getboolfield(L, index, "walkable", f.walkable);
- // Player can point to these
- getboolfield(L, index, "pointable", f.pointable);
- // Player can dig these
- getboolfield(L, index, "diggable", f.diggable);
- // Player can climb these
- getboolfield(L, index, "climbable", f.climbable);
- // Player can build on these
- getboolfield(L, index, "buildable_to", f.buildable_to);
- // Whether the node is non-liquid, source liquid or flowing liquid
- f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
- es_LiquidType, LIQUID_NONE);
- // If the content is liquid, this is the flowing version of the liquid.
- getstringfield(L, index, "liquid_alternative_flowing",
- f.liquid_alternative_flowing);
- // If the content is liquid, this is the source version of the liquid.
- getstringfield(L, index, "liquid_alternative_source",
- f.liquid_alternative_source);
- // Viscosity for fluid flow, ranging from 1 to 7, with
- // 1 giving almost instantaneous propagation and 7 being
- // the slowest possible
- f.liquid_viscosity = getintfield_default(L, index,
- "liquid_viscosity", f.liquid_viscosity);
- getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
- // Amount of light the node emits
- f.light_source = getintfield_default(L, index,
- "light_source", f.light_source);
- f.damage_per_second = getintfield_default(L, index,
- "damage_per_second", f.damage_per_second);
-
- lua_getfield(L, index, "node_box");
- if(lua_istable(L, -1))
- f.node_box = read_nodebox(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "selection_box");
- if(lua_istable(L, -1))
- f.selection_box = read_nodebox(L, -1);
- lua_pop(L, 1);
-
- // Set to true if paramtype used to be 'facedir_simple'
- getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
- // Set to true if wall_mounted used to be set to true
- getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
-
- // Sound table
- lua_getfield(L, index, "sounds");
- if(lua_istable(L, -1)){
- lua_getfield(L, -1, "footstep");
- read_soundspec(L, -1, f.sound_footstep);
- lua_pop(L, 1);
- lua_getfield(L, -1, "dig");
- read_soundspec(L, -1, f.sound_dig);
lua_pop(L, 1);
- lua_getfield(L, -1, "dug");
- read_soundspec(L, -1, f.sound_dug);
- lua_pop(L, 1);
- }
- lua_pop(L, 1);
-
- return f;
-}
-
-/*
- Inventory stuff
-*/
-
-static ItemStack read_item(lua_State *L, int index);
-static std::vector<ItemStack> read_items(lua_State *L, int index);
-// creates a table of ItemStacks
-static void push_items(lua_State *L, const std::vector<ItemStack> &items);
-
-static void inventory_set_list_from_lua(Inventory *inv, const char *name,
- lua_State *L, int tableindex, int forcesize=-1)
-{
- if(tableindex < 0)
- tableindex = lua_gettop(L) + 1 + tableindex;
- // If nil, delete list
- if(lua_isnil(L, tableindex)){
- inv->deleteList(name);
- return;
- }
- // Otherwise set list
- std::vector<ItemStack> items = read_items(L, tableindex);
- int listsize = (forcesize != -1) ? forcesize : items.size();
- InventoryList *invlist = inv->addList(name, listsize);
- int index = 0;
- for(std::vector<ItemStack>::const_iterator
- i = items.begin(); i != items.end(); i++){
- if(forcesize != -1 && index == forcesize)
- break;
- invlist->changeItem(index, *i);
- index++;
- }
- while(forcesize != -1 && index < forcesize){
- invlist->deleteItem(index);
- index++;
- }
-}
-
-static void inventory_get_list_to_lua(Inventory *inv, const char *name,
- lua_State *L)
-{
- InventoryList *invlist = inv->getList(name);
- if(invlist == NULL){
- lua_pushnil(L);
- return;
+ params.max_hear_distance = BS*getfloatfield_default(L, index,
+ "max_hear_distance", params.max_hear_distance/BS);
+ getboolfield(L, index, "loop", params.loop);
}
- std::vector<ItemStack> items;
- for(u32 i=0; i<invlist->getSize(); i++)
- items.push_back(invlist->getItem(i));
- push_items(L, items);
}
-/*
- Helpful macros for userdata classes
-*/
-
-#define method(class, name) {#name, class::l_##name}
-
-/*
- LuaItemStack
-*/
-
-class LuaItemStack
-{
-private:
- ItemStack m_stack;
-
- static const char className[];
- static const luaL_reg methods[];
-
- // Exported functions
-
- // garbage collector
- static int gc_object(lua_State *L)
- {
- LuaItemStack *o = *(LuaItemStack **)(lua_touserdata(L, 1));
- delete o;
- return 0;
- }
-
- // is_empty(self) -> true/false
- static int l_is_empty(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- lua_pushboolean(L, item.empty());
- return 1;
- }
-
- // get_name(self) -> string
- static int l_get_name(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- lua_pushstring(L, item.name.c_str());
- return 1;
- }
-
- // get_count(self) -> number
- static int l_get_count(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- lua_pushinteger(L, item.count);
- return 1;
- }
-
- // get_wear(self) -> number
- static int l_get_wear(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- lua_pushinteger(L, item.wear);
- return 1;
- }
-
- // get_metadata(self) -> string
- static int l_get_metadata(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
- return 1;
- }
-
- // clear(self) -> true
- static int l_clear(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- o->m_stack.clear();
- lua_pushboolean(L, true);
- return 1;
- }
-
- // replace(self, itemstack or itemstring or table or nil) -> true
- static int l_replace(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- o->m_stack = read_item(L, 2);
- lua_pushboolean(L, true);
- return 1;
- }
-
- // to_string(self) -> string
- static int l_to_string(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- std::string itemstring = o->m_stack.getItemString();
- lua_pushstring(L, itemstring.c_str());
- return 1;
- }
-
- // to_table(self) -> table or nil
- static int l_to_table(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- const ItemStack &item = o->m_stack;
- if(item.empty())
- {
- lua_pushnil(L);
- }
- else
- {
- lua_newtable(L);
- lua_pushstring(L, item.name.c_str());
- lua_setfield(L, -2, "name");
- lua_pushinteger(L, item.count);
- lua_setfield(L, -2, "count");
- lua_pushinteger(L, item.wear);
- lua_setfield(L, -2, "wear");
- lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
- lua_setfield(L, -2, "metadata");
- }
- return 1;
- }
-
- // get_stack_max(self) -> number
- static int l_get_stack_max(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- lua_pushinteger(L, item.getStackMax(get_server(L)->idef()));
- return 1;
- }
-
- // get_free_space(self) -> number
- static int l_get_free_space(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- lua_pushinteger(L, item.freeSpace(get_server(L)->idef()));
- return 1;
- }
-
- // is_known(self) -> true/false
- // Checks if the item is defined.
- static int l_is_known(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- bool is_known = item.isKnown(get_server(L)->idef());
- lua_pushboolean(L, is_known);
- return 1;
- }
-
- // get_definition(self) -> table
- // Returns the item definition table from minetest.registered_items,
- // or a fallback one (name="unknown")
- static int l_get_definition(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
-
- // Get minetest.registered_items[name]
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_items");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_getfield(L, -1, item.name.c_str());
- if(lua_isnil(L, -1))
- {
- lua_pop(L, 1);
- lua_getfield(L, -1, "unknown");
- }
- return 1;
- }
-
- // get_tool_capabilities(self) -> table
- // Returns the effective tool digging properties.
- // Returns those of the hand ("") if this item has none associated.
- static int l_get_tool_capabilities(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- const ToolCapabilities &prop =
- item.getToolCapabilities(get_server(L)->idef());
- push_tool_capabilities(L, prop);
- return 1;
- }
-
- // add_wear(self, amount) -> true/false
- // The range for "amount" is [0,65535]. Wear is only added if the item
- // is a tool. Adding wear might destroy the item.
- // Returns true if the item is (or was) a tool.
- static int l_add_wear(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- int amount = lua_tointeger(L, 2);
- bool result = item.addWear(amount, get_server(L)->idef());
- lua_pushboolean(L, result);
- return 1;
- }
-
- // add_item(self, itemstack or itemstring or table or nil) -> itemstack
- // Returns leftover item stack
- static int l_add_item(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- ItemStack newitem = read_item(L, 2);
- ItemStack leftover = item.addItem(newitem, get_server(L)->idef());
- create(L, leftover);
- return 1;
- }
-
- // item_fits(self, itemstack or itemstring or table or nil) -> true/false, itemstack
- // First return value is true iff the new item fits fully into the stack
- // Second return value is the would-be-left-over item stack
- static int l_item_fits(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- ItemStack newitem = read_item(L, 2);
- ItemStack restitem;
- bool fits = item.itemFits(newitem, &restitem, get_server(L)->idef());
- lua_pushboolean(L, fits); // first return value
- create(L, restitem); // second return value
- return 2;
- }
-
- // take_item(self, takecount=1) -> itemstack
- static int l_take_item(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- u32 takecount = 1;
- if(!lua_isnone(L, 2))
- takecount = luaL_checkinteger(L, 2);
- ItemStack taken = item.takeItem(takecount);
- create(L, taken);
- return 1;
- }
-
- // peek_item(self, peekcount=1) -> itemstack
- static int l_peek_item(lua_State *L)
- {
- LuaItemStack *o = checkobject(L, 1);
- ItemStack &item = o->m_stack;
- u32 peekcount = 1;
- if(!lua_isnone(L, 2))
- peekcount = lua_tointeger(L, 2);
- ItemStack peekaboo = item.peekItem(peekcount);
- create(L, peekaboo);
- return 1;
- }
-
-public:
- LuaItemStack(const ItemStack &item):
- m_stack(item)
- {
- }
-
- ~LuaItemStack()
- {
- }
-
- const ItemStack& getItem() const
- {
- return m_stack;
- }
- ItemStack& getItem()
- {
- return m_stack;
- }
-
- // LuaItemStack(itemstack or itemstring or table or nil)
- // Creates an LuaItemStack and leaves it on top of stack
- static int create_object(lua_State *L)
- {
- ItemStack item = read_item(L, 1);
- LuaItemStack *o = new LuaItemStack(item);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- return 1;
- }
- // Not callable from Lua
- static int create(lua_State *L, const ItemStack &item)
- {
- LuaItemStack *o = new LuaItemStack(item);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- return 1;
- }
-
- static LuaItemStack* checkobject(lua_State *L, int narg)
- {
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(LuaItemStack**)ud; // unbox pointer
- }
-
- static void Register(lua_State *L)
- {
- lua_newtable(L);
- int methodtable = lua_gettop(L);
- luaL_newmetatable(L, className);
- int metatable = lua_gettop(L);
-
- lua_pushliteral(L, "__metatable");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
-
- lua_pushliteral(L, "__index");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable);
-
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_object);
- lua_settable(L, metatable);
+/*****************************************************************************/
+/* callbacks */
+/*****************************************************************************/
- lua_pop(L, 1); // drop metatable
-
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
-
- // Can be created from Lua (LuaItemStack(itemstack or itemstring or table or nil))
- lua_register(L, className, create_object);
- }
-};
-const char LuaItemStack::className[] = "ItemStack";
-const luaL_reg LuaItemStack::methods[] = {
- method(LuaItemStack, is_empty),
- method(LuaItemStack, get_name),
- method(LuaItemStack, get_count),
- method(LuaItemStack, get_wear),
- method(LuaItemStack, get_metadata),
- method(LuaItemStack, clear),
- method(LuaItemStack, replace),
- method(LuaItemStack, to_string),
- method(LuaItemStack, to_table),
- method(LuaItemStack, get_stack_max),
- method(LuaItemStack, get_free_space),
- method(LuaItemStack, is_known),
- method(LuaItemStack, get_definition),
- method(LuaItemStack, get_tool_capabilities),
- method(LuaItemStack, add_wear),
- method(LuaItemStack, add_item),
- method(LuaItemStack, item_fits),
- method(LuaItemStack, take_item),
- method(LuaItemStack, peek_item),
- {0,0}
-};
-
-static ItemStack read_item(lua_State *L, int index)
+// Push the list of callbacks (a lua table).
+// Then push nargs arguments.
+// Then call this function, which
+// - runs the callbacks
+// - removes the table and arguments from the lua stack
+// - pushes the return value, computed depending on mode
+void scriptapi_run_callbacks(lua_State *L, int nargs,
+ RunCallbacksMode mode)
{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
+ // Insert the return value into the lua stack, below the table
+ assert(lua_gettop(L) >= nargs + 1);
+ lua_pushnil(L);
+ lua_insert(L, -(nargs + 1) - 1);
+ // Stack now looks like this:
+ // ... <return value = nil> <table> <arg#1> <arg#2> ... <arg#n>
- if(lua_isnil(L, index))
- {
- return ItemStack();
- }
- else if(lua_isuserdata(L, index))
- {
- // Convert from LuaItemStack
- LuaItemStack *o = LuaItemStack::checkobject(L, index);
- return o->getItem();
- }
- else if(lua_isstring(L, index))
- {
- // Convert from itemstring
- std::string itemstring = lua_tostring(L, index);
- IItemDefManager *idef = get_server(L)->idef();
- try
- {
- ItemStack item;
- item.deSerialize(itemstring, idef);
- return item;
- }
- catch(SerializationError &e)
- {
- infostream<<"WARNING: unable to create item from itemstring"
- <<": "<<itemstring<<std::endl;
- return ItemStack();
- }
- }
- else if(lua_istable(L, index))
- {
- // Convert from table
- IItemDefManager *idef = get_server(L)->idef();
- std::string name = getstringfield_default(L, index, "name", "");
- int count = getintfield_default(L, index, "count", 1);
- int wear = getintfield_default(L, index, "wear", 0);
- std::string metadata = getstringfield_default(L, index, "metadata", "");
- return ItemStack(name, count, wear, metadata, idef);
- }
- else
- {
- throw LuaError(L, "Expecting itemstack, itemstring, table or nil");
- }
-}
+ int rv = lua_gettop(L) - nargs - 1;
+ int table = rv + 1;
+ int arg = table + 1;
-static std::vector<ItemStack> read_items(lua_State *L, int index)
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
+ luaL_checktype(L, table, LUA_TTABLE);
- std::vector<ItemStack> items;
- luaL_checktype(L, index, LUA_TTABLE);
+ // Foreach
lua_pushnil(L);
- while(lua_next(L, index) != 0){
+ bool first_loop = true;
+ while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
- items.push_back(read_item(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- return items;
-}
-
-// creates a table of ItemStacks
-static void push_items(lua_State *L, const std::vector<ItemStack> &items)
-{
- // Get the table insert function
- lua_getglobal(L, "table");
- lua_getfield(L, -1, "insert");
- int table_insert = lua_gettop(L);
- // Create and fill table
- lua_newtable(L);
- int table = lua_gettop(L);
- for(u32 i=0; i<items.size(); i++){
- ItemStack item = items[i];
- lua_pushvalue(L, table_insert);
- lua_pushvalue(L, table);
- LuaItemStack::create(L, item);
- if(lua_pcall(L, 2, 0, 0))
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ // Call function
+ for(int i = 0; i < nargs; i++)
+ lua_pushvalue(L, arg+i);
+ if(lua_pcall(L, nargs, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
- }
- lua_remove(L, -2); // Remove table
- lua_remove(L, -2); // Remove insert
-}
-/*
- InvRef
-*/
-
-class InvRef
-{
-private:
- InventoryLocation m_loc;
-
- static const char className[];
- static const luaL_reg methods[];
-
- static InvRef *checkobject(lua_State *L, int narg)
- {
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(InvRef**)ud; // unbox pointer
- }
-
- static Inventory* getinv(lua_State *L, InvRef *ref)
- {
- return get_server(L)->getInventory(ref->m_loc);
- }
-
- static InventoryList* getlist(lua_State *L, InvRef *ref,
- const char *listname)
- {
- Inventory *inv = getinv(L, ref);
- if(!inv)
- return NULL;
- return inv->getList(listname);
- }
-
- static void reportInventoryChange(lua_State *L, InvRef *ref)
- {
- // Inform other things that the inventory has changed
- get_server(L)->setInventoryModified(ref->m_loc);
- }
-
- // Exported functions
-
- // garbage collector
- static int gc_object(lua_State *L) {
- InvRef *o = *(InvRef **)(lua_touserdata(L, 1));
- delete o;
- return 0;
- }
-
- // is_empty(self, listname) -> true/false
- static int l_is_empty(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- InventoryList *list = getlist(L, ref, listname);
- if(list && list->getUsedSlots() > 0){
- lua_pushboolean(L, false);
- } else {
- lua_pushboolean(L, true);
- }
- return 1;
- }
-
- // get_size(self, listname)
- static int l_get_size(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- InventoryList *list = getlist(L, ref, listname);
- if(list){
- lua_pushinteger(L, list->getSize());
- } else {
- lua_pushinteger(L, 0);
- }
- return 1;
- }
-
- // get_width(self, listname)
- static int l_get_width(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- InventoryList *list = getlist(L, ref, listname);
- if(list){
- lua_pushinteger(L, list->getWidth());
+ // Move return value to designated space in stack
+ // Or pop it
+ if(first_loop){
+ // Result of first callback is always moved
+ lua_replace(L, rv);
+ first_loop = false;
} else {
- lua_pushinteger(L, 0);
+ // Otherwise, what happens depends on the mode
+ if(mode == RUN_CALLBACKS_MODE_FIRST)
+ lua_pop(L, 1);
+ else if(mode == RUN_CALLBACKS_MODE_LAST)
+ lua_replace(L, rv);
+ else if(mode == RUN_CALLBACKS_MODE_AND ||
+ mode == RUN_CALLBACKS_MODE_AND_SC){
+ if((bool)lua_toboolean(L, rv) == true &&
+ (bool)lua_toboolean(L, -1) == false)
+ lua_replace(L, rv);
+ else
+ lua_pop(L, 1);
+ }
+ else if(mode == RUN_CALLBACKS_MODE_OR ||
+ mode == RUN_CALLBACKS_MODE_OR_SC){
+ if((bool)lua_toboolean(L, rv) == false &&
+ (bool)lua_toboolean(L, -1) == true)
+ lua_replace(L, rv);
+ else
+ lua_pop(L, 1);
+ }
+ else
+ assert(0);
}
- return 1;
- }
- // set_size(self, listname, size)
- static int l_set_size(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- int newsize = luaL_checknumber(L, 3);
- Inventory *inv = getinv(L, ref);
- if(newsize == 0){
- inv->deleteList(listname);
- reportInventoryChange(L, ref);
- return 0;
- }
- InventoryList *list = inv->getList(listname);
- if(list){
- list->setSize(newsize);
- } else {
- list = inv->addList(listname, newsize);
- }
- reportInventoryChange(L, ref);
- return 0;
- }
+ // Handle short circuit modes
+ if(mode == RUN_CALLBACKS_MODE_AND_SC &&
+ (bool)lua_toboolean(L, rv) == false)
+ break;
+ else if(mode == RUN_CALLBACKS_MODE_OR_SC &&
+ (bool)lua_toboolean(L, rv) == true)
+ break;
- // set_width(self, listname, size)
- static int l_set_width(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- int newwidth = luaL_checknumber(L, 3);
- Inventory *inv = getinv(L, ref);
- InventoryList *list = inv->getList(listname);
- if(list){
- list->setWidth(newwidth);
- } else {
- return 0;
- }
- reportInventoryChange(L, ref);
- return 0;
+ // value removed, keep key for next iteration
}
- // get_stack(self, listname, i) -> itemstack
- static int l_get_stack(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- int i = luaL_checknumber(L, 3) - 1;
- InventoryList *list = getlist(L, ref, listname);
- ItemStack item;
- if(list != NULL && i >= 0 && i < (int) list->getSize())
- item = list->getItem(i);
- LuaItemStack::create(L, item);
- return 1;
- }
+ // Remove stuff from stack, leaving only the return value
+ lua_settop(L, rv);
- // set_stack(self, listname, i, stack) -> true/false
- static int l_set_stack(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- int i = luaL_checknumber(L, 3) - 1;
- ItemStack newitem = read_item(L, 4);
- InventoryList *list = getlist(L, ref, listname);
- if(list != NULL && i >= 0 && i < (int) list->getSize()){
- list->changeItem(i, newitem);
- reportInventoryChange(L, ref);
+ // Fix return value in case no callbacks were called
+ if(first_loop){
+ if(mode == RUN_CALLBACKS_MODE_AND ||
+ mode == RUN_CALLBACKS_MODE_AND_SC){
+ lua_pop(L, 1);
lua_pushboolean(L, true);
- } else {
- lua_pushboolean(L, false);
- }
- return 1;
- }
-
- // get_list(self, listname) -> list or nil
- static int l_get_list(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- Inventory *inv = getinv(L, ref);
- inventory_get_list_to_lua(inv, listname, L);
- return 1;
- }
-
- // set_list(self, listname, list)
- static int l_set_list(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- Inventory *inv = getinv(L, ref);
- InventoryList *list = inv->getList(listname);
- if(list)
- inventory_set_list_from_lua(inv, listname, L, 3,
- list->getSize());
- else
- inventory_set_list_from_lua(inv, listname, L, 3);
- reportInventoryChange(L, ref);
- return 0;
- }
-
- // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
- // Returns the leftover stack
- static int l_add_item(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- ItemStack item = read_item(L, 3);
- InventoryList *list = getlist(L, ref, listname);
- if(list){
- ItemStack leftover = list->addItem(item);
- if(leftover.count != item.count)
- reportInventoryChange(L, ref);
- LuaItemStack::create(L, leftover);
- } else {
- LuaItemStack::create(L, item);
- }
- return 1;
- }
-
- // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
- // Returns true if the item completely fits into the list
- static int l_room_for_item(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- ItemStack item = read_item(L, 3);
- InventoryList *list = getlist(L, ref, listname);
- if(list){
- lua_pushboolean(L, list->roomForItem(item));
- } else {
- lua_pushboolean(L, false);
}
- return 1;
- }
-
- // contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
- // Returns true if the list contains the given count of the given item name
- static int l_contains_item(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- ItemStack item = read_item(L, 3);
- InventoryList *list = getlist(L, ref, listname);
- if(list){
- lua_pushboolean(L, list->containsItem(item));
- } else {
+ else if(mode == RUN_CALLBACKS_MODE_OR ||
+ mode == RUN_CALLBACKS_MODE_OR_SC){
+ lua_pop(L, 1);
lua_pushboolean(L, false);
}
- return 1;
- }
-
- // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
- // Returns the items that were actually removed
- static int l_remove_item(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const char *listname = luaL_checkstring(L, 2);
- ItemStack item = read_item(L, 3);
- InventoryList *list = getlist(L, ref, listname);
- if(list){
- ItemStack removed = list->removeItem(item);
- if(!removed.empty())
- reportInventoryChange(L, ref);
- LuaItemStack::create(L, removed);
- } else {
- LuaItemStack::create(L, ItemStack());
- }
- return 1;
- }
-
- // get_location() -> location (like minetest.get_inventory(location))
- static int l_get_location(lua_State *L)
- {
- InvRef *ref = checkobject(L, 1);
- const InventoryLocation &loc = ref->m_loc;
- switch(loc.type){
- case InventoryLocation::PLAYER:
- lua_newtable(L);
- lua_pushstring(L, "player");
- lua_setfield(L, -2, "type");
- lua_pushstring(L, loc.name.c_str());
- lua_setfield(L, -2, "name");
- return 1;
- case InventoryLocation::NODEMETA:
- lua_newtable(L);
- lua_pushstring(L, "nodemeta");
- lua_setfield(L, -2, "type");
- push_v3s16(L, loc.p);
- lua_setfield(L, -2, "name");
- return 1;
- case InventoryLocation::DETACHED:
- lua_newtable(L);
- lua_pushstring(L, "detached");
- lua_setfield(L, -2, "type");
- lua_pushstring(L, loc.name.c_str());
- lua_setfield(L, -2, "name");
- return 1;
- case InventoryLocation::UNDEFINED:
- case InventoryLocation::CURRENT_PLAYER:
- break;
- }
- lua_newtable(L);
- lua_pushstring(L, "undefined");
- lua_setfield(L, -2, "type");
- return 1;
}
+}
-public:
- InvRef(const InventoryLocation &loc):
- m_loc(loc)
- {
- }
-
- ~InvRef()
- {
- }
-
- // Creates an InvRef and leaves it on top of stack
- // Not callable from Lua; all references are created on the C side.
- static void create(lua_State *L, const InventoryLocation &loc)
- {
- InvRef *o = new InvRef(loc);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- }
- static void createPlayer(lua_State *L, Player *player)
- {
- InventoryLocation loc;
- loc.setPlayer(player->getName());
- create(L, loc);
- }
- static void createNodeMeta(lua_State *L, v3s16 p)
- {
- InventoryLocation loc;
- loc.setNodeMeta(p);
- create(L, loc);
- }
-
- static void Register(lua_State *L)
- {
- lua_newtable(L);
- int methodtable = lua_gettop(L);
- luaL_newmetatable(L, className);
- int metatable = lua_gettop(L);
-
- lua_pushliteral(L, "__metatable");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
-
- lua_pushliteral(L, "__index");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable);
-
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_object);
- lua_settable(L, metatable);
-
- lua_pop(L, 1); // drop metatable
-
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
-
- // Cannot be created from Lua
- //lua_register(L, className, create_object);
- }
-};
-const char InvRef::className[] = "InvRef";
-const luaL_reg InvRef::methods[] = {
- method(InvRef, is_empty),
- method(InvRef, get_size),
- method(InvRef, set_size),
- method(InvRef, get_width),
- method(InvRef, set_width),
- method(InvRef, get_stack),
- method(InvRef, set_stack),
- method(InvRef, get_list),
- method(InvRef, set_list),
- method(InvRef, add_item),
- method(InvRef, room_for_item),
- method(InvRef, contains_item),
- method(InvRef, remove_item),
- method(InvRef, get_location),
- {0,0}
-};
-
-/*
- NodeMetaRef
-*/
-
-class NodeMetaRef
+bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
+ const std::string &message)
{
-private:
- v3s16 m_p;
- ServerEnvironment *m_env;
-
- static const char className[];
- static const luaL_reg methods[];
-
- static NodeMetaRef *checkobject(lua_State *L, int narg)
- {
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(NodeMetaRef**)ud; // unbox pointer
- }
-
- static NodeMetadata* getmeta(NodeMetaRef *ref, bool auto_create)
- {
- NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
- if(meta == NULL && auto_create)
- {
- meta = new NodeMetadata(ref->m_env->getGameDef());
- ref->m_env->getMap().setNodeMetadata(ref->m_p, meta);
- }
- return meta;
- }
-
- static void reportMetadataChange(NodeMetaRef *ref)
- {
- // NOTE: This same code is in rollback_interface.cpp
- // Inform other things that the metadata has changed
- v3s16 blockpos = getNodeBlockPos(ref->m_p);
- MapEditEvent event;
- event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
- event.p = blockpos;
- ref->m_env->getMap().dispatchEvent(&event);
- // Set the block to be saved
- MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos);
- if(block)
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- "NodeMetaRef::reportMetadataChange");
- }
-
- // Exported functions
-
- // garbage collector
- static int gc_object(lua_State *L) {
- NodeMetaRef *o = *(NodeMetaRef **)(lua_touserdata(L, 1));
- delete o;
- return 0;
- }
-
- // get_string(self, name)
- static int l_get_string(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = luaL_checkstring(L, 2);
-
- NodeMetadata *meta = getmeta(ref, false);
- if(meta == NULL){
- lua_pushlstring(L, "", 0);
- return 1;
- }
- std::string str = meta->getString(name);
- lua_pushlstring(L, str.c_str(), str.size());
- return 1;
- }
-
- // set_string(self, name, var)
- static int l_set_string(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = luaL_checkstring(L, 2);
- size_t len = 0;
- const char *s = lua_tolstring(L, 3, &len);
- std::string str(s, len);
-
- NodeMetadata *meta = getmeta(ref, !str.empty());
- if(meta == NULL || str == meta->getString(name))
- return 0;
- meta->setString(name, str);
- reportMetadataChange(ref);
- return 0;
- }
-
- // get_int(self, name)
- static int l_get_int(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = lua_tostring(L, 2);
-
- NodeMetadata *meta = getmeta(ref, false);
- if(meta == NULL){
- lua_pushnumber(L, 0);
- return 1;
- }
- std::string str = meta->getString(name);
- lua_pushnumber(L, stoi(str));
- return 1;
- }
-
- // set_int(self, name, var)
- static int l_set_int(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = lua_tostring(L, 2);
- int a = lua_tointeger(L, 3);
- std::string str = itos(a);
-
- NodeMetadata *meta = getmeta(ref, true);
- if(meta == NULL || str == meta->getString(name))
- return 0;
- meta->setString(name, str);
- reportMetadataChange(ref);
- return 0;
- }
-
- // get_float(self, name)
- static int l_get_float(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = lua_tostring(L, 2);
-
- NodeMetadata *meta = getmeta(ref, false);
- if(meta == NULL){
- lua_pushnumber(L, 0);
- return 1;
- }
- std::string str = meta->getString(name);
- lua_pushnumber(L, stof(str));
- return 1;
- }
-
- // set_float(self, name, var)
- static int l_set_float(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = lua_tostring(L, 2);
- float a = lua_tonumber(L, 3);
- std::string str = ftos(a);
-
- NodeMetadata *meta = getmeta(ref, true);
- if(meta == NULL || str == meta->getString(name))
- return 0;
- meta->setString(name, str);
- reportMetadataChange(ref);
- return 0;
- }
-
- // get_inventory(self)
- static int l_get_inventory(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- getmeta(ref, true); // try to ensure the metadata exists
- InvRef::createNodeMeta(L, ref->m_p);
- return 1;
- }
-
- // to_table(self)
- static int l_to_table(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
-
- NodeMetadata *meta = getmeta(ref, true);
- if(meta == NULL){
- lua_pushnil(L);
- return 1;
- }
- lua_newtable(L);
- // fields
- lua_newtable(L);
- {
- std::map<std::string, std::string> fields = meta->getStrings();
- for(std::map<std::string, std::string>::const_iterator
- i = fields.begin(); i != fields.end(); i++){
- const std::string &name = i->first;
- const std::string &value = i->second;
- lua_pushlstring(L, name.c_str(), name.size());
- lua_pushlstring(L, value.c_str(), value.size());
- lua_settable(L, -3);
- }
- }
- lua_setfield(L, -2, "fields");
- // inventory
- lua_newtable(L);
- Inventory *inv = meta->getInventory();
- if(inv){
- std::vector<const InventoryList*> lists = inv->getLists();
- for(std::vector<const InventoryList*>::const_iterator
- i = lists.begin(); i != lists.end(); i++){
- inventory_get_list_to_lua(inv, (*i)->getName().c_str(), L);
- lua_setfield(L, -2, (*i)->getName().c_str());
- }
- }
- lua_setfield(L, -2, "inventory");
- return 1;
- }
-
- // from_table(self, table)
- static int l_from_table(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- int base = 2;
-
- if(lua_isnil(L, base)){
- // No metadata
- ref->m_env->getMap().removeNodeMetadata(ref->m_p);
- lua_pushboolean(L, true);
- return 1;
- }
-
- // Has metadata; clear old one first
- ref->m_env->getMap().removeNodeMetadata(ref->m_p);
- // Create new metadata
- NodeMetadata *meta = getmeta(ref, true);
- // Set fields
- lua_getfield(L, base, "fields");
- int fieldstable = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, fieldstable) != 0){
- // key at index -2 and value at index -1
- std::string name = lua_tostring(L, -2);
- size_t cl;
- const char *cs = lua_tolstring(L, -1, &cl);
- std::string value(cs, cl);
- meta->setString(name, value);
- lua_pop(L, 1); // removes value, keeps key for next iteration
- }
- // Set inventory
- Inventory *inv = meta->getInventory();
- lua_getfield(L, base, "inventory");
- int inventorytable = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, inventorytable) != 0){
- // key at index -2 and value at index -1
- std::string name = lua_tostring(L, -2);
- inventory_set_list_from_lua(inv, name.c_str(), L, -1);
- lua_pop(L, 1); // removes value, keeps key for next iteration
- }
- reportMetadataChange(ref);
- lua_pushboolean(L, true);
- return 1;
- }
-
-public:
- NodeMetaRef(v3s16 p, ServerEnvironment *env):
- m_p(p),
- m_env(env)
- {
- }
-
- ~NodeMetaRef()
- {
- }
-
- // Creates an NodeMetaRef and leaves it on top of stack
- // Not callable from Lua; all references are created on the C side.
- static void create(lua_State *L, v3s16 p, ServerEnvironment *env)
- {
- NodeMetaRef *o = new NodeMetaRef(p, env);
- //infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- }
-
- static void Register(lua_State *L)
- {
- lua_newtable(L);
- int methodtable = lua_gettop(L);
- luaL_newmetatable(L, className);
- int metatable = lua_gettop(L);
-
- lua_pushliteral(L, "__metatable");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
-
- lua_pushliteral(L, "__index");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable);
-
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_object);
- lua_settable(L, metatable);
-
- lua_pop(L, 1); // drop metatable
-
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
-
- // Cannot be created from Lua
- //lua_register(L, className, create_object);
- }
-};
-const char NodeMetaRef::className[] = "NodeMetaRef";
-const luaL_reg NodeMetaRef::methods[] = {
- method(NodeMetaRef, get_string),
- method(NodeMetaRef, set_string),
- method(NodeMetaRef, get_int),
- method(NodeMetaRef, set_int),
- method(NodeMetaRef, get_float),
- method(NodeMetaRef, set_float),
- method(NodeMetaRef, get_inventory),
- method(NodeMetaRef, to_table),
- method(NodeMetaRef, from_table),
- {0,0}
-};
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
-/*
- ObjectRef
-*/
+ // Get minetest.registered_on_chat_messages
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_chat_messages");
+ // Call callbacks
+ lua_pushstring(L, name.c_str());
+ lua_pushstring(L, message.c_str());
+ scriptapi_run_callbacks(L, 2, RUN_CALLBACKS_MODE_OR_SC);
+ bool ate = lua_toboolean(L, -1);
+ return ate;
+}
-class ObjectRef
+void scriptapi_on_shutdown(lua_State *L)
{
-private:
- ServerActiveObject *m_object;
-
- static const char className[];
- static const luaL_reg methods[];
-public:
- static ObjectRef *checkobject(lua_State *L, int narg)
- {
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(ObjectRef**)ud; // unbox pointer
- }
-
- static ServerActiveObject* getobject(ObjectRef *ref)
- {
- ServerActiveObject *co = ref->m_object;
- return co;
- }
-private:
- static LuaEntitySAO* getluaobject(ObjectRef *ref)
- {
- ServerActiveObject *obj = getobject(ref);
- if(obj == NULL)
- return NULL;
- if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
- return NULL;
- return (LuaEntitySAO*)obj;
- }
-
- static PlayerSAO* getplayersao(ObjectRef *ref)
- {
- ServerActiveObject *obj = getobject(ref);
- if(obj == NULL)
- return NULL;
- if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
- return NULL;
- return (PlayerSAO*)obj;
- }
-
- static Player* getplayer(ObjectRef *ref)
- {
- PlayerSAO *playersao = getplayersao(ref);
- if(playersao == NULL)
- return NULL;
- return playersao->getPlayer();
- }
-
- // Exported functions
-
- // garbage collector
- static int gc_object(lua_State *L) {
- ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
- //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
- delete o;
- return 0;
- }
-
- // remove(self)
- static int l_remove(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- verbosestream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
- co->m_removed = true;
- return 0;
- }
-
- // getpos(self)
- // returns: {x=num, y=num, z=num}
- static int l_getpos(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- v3f pos = co->getBasePosition() / BS;
- lua_newtable(L);
- lua_pushnumber(L, pos.X);
- lua_setfield(L, -2, "x");
- lua_pushnumber(L, pos.Y);
- lua_setfield(L, -2, "y");
- lua_pushnumber(L, pos.Z);
- lua_setfield(L, -2, "z");
- return 1;
- }
-
- // setpos(self, pos)
- static int l_setpos(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- //LuaEntitySAO *co = getluaobject(ref);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // pos
- v3f pos = checkFloatPos(L, 2);
- // Do it
- co->setPos(pos);
- return 0;
- }
-
- // moveto(self, pos, continuous=false)
- static int l_moveto(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- //LuaEntitySAO *co = getluaobject(ref);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // pos
- v3f pos = checkFloatPos(L, 2);
- // continuous
- bool continuous = lua_toboolean(L, 3);
- // Do it
- co->moveTo(pos, continuous);
- return 0;
- }
-
- // punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
- static int l_punch(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ObjectRef *puncher_ref = checkobject(L, 2);
- ServerActiveObject *co = getobject(ref);
- ServerActiveObject *puncher = getobject(puncher_ref);
- if(co == NULL) return 0;
- if(puncher == NULL) return 0;
- v3f dir;
- if(lua_type(L, 5) != LUA_TTABLE)
- dir = co->getBasePosition() - puncher->getBasePosition();
- else
- dir = read_v3f(L, 5);
- float time_from_last_punch = 1000000;
- if(lua_isnumber(L, 3))
- time_from_last_punch = lua_tonumber(L, 3);
- ToolCapabilities toolcap = read_tool_capabilities(L, 4);
- dir.normalize();
- // Do it
- co->punch(dir, &toolcap, puncher, time_from_last_punch);
- return 0;
- }
-
- // right_click(self, clicker); clicker = an another ObjectRef
- static int l_right_click(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ObjectRef *ref2 = checkobject(L, 2);
- ServerActiveObject *co = getobject(ref);
- ServerActiveObject *co2 = getobject(ref2);
- if(co == NULL) return 0;
- if(co2 == NULL) return 0;
- // Do it
- co->rightClick(co2);
- return 0;
- }
-
- // set_hp(self, hp)
- // hp = number of hitpoints (2 * number of hearts)
- // returns: nil
- static int l_set_hp(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- luaL_checknumber(L, 2);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- int hp = lua_tonumber(L, 2);
- /*infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
- <<" hp="<<hp<<std::endl;*/
- // Do it
- co->setHP(hp);
- // Return
- return 0;
- }
-
- // get_hp(self)
- // returns: number of hitpoints (2 * number of hearts)
- // 0 if not applicable to this type of object
- static int l_get_hp(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL){
- // Default hp is 1
- lua_pushnumber(L, 1);
- return 1;
- }
- int hp = co->getHP();
- /*infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
- <<" hp="<<hp<<std::endl;*/
- // Return
- lua_pushnumber(L, hp);
- return 1;
- }
-
- // get_inventory(self)
- static int l_get_inventory(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // Do it
- InventoryLocation loc = co->getInventoryLocation();
- if(get_server(L)->getInventory(loc) != NULL)
- InvRef::create(L, loc);
- else
- lua_pushnil(L); // An object may have no inventory (nil)
- return 1;
- }
-
- // get_wield_list(self)
- static int l_get_wield_list(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // Do it
- lua_pushstring(L, co->getWieldList().c_str());
- return 1;
- }
-
- // get_wield_index(self)
- static int l_get_wield_index(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // Do it
- lua_pushinteger(L, co->getWieldIndex() + 1);
- return 1;
- }
-
- // get_wielded_item(self)
- static int l_get_wielded_item(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL){
- // Empty ItemStack
- LuaItemStack::create(L, ItemStack());
- return 1;
- }
- // Do it
- LuaItemStack::create(L, co->getWieldedItem());
- return 1;
- }
-
- // set_wielded_item(self, itemstack or itemstring or table or nil)
- static int l_set_wielded_item(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // Do it
- ItemStack item = read_item(L, 2);
- bool success = co->setWieldedItem(item);
- lua_pushboolean(L, success);
- return 1;
- }
-
- // set_armor_groups(self, groups)
- static int l_set_armor_groups(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // Do it
- ItemGroupList groups;
- read_groups(L, 2, groups);
- co->setArmorGroups(groups);
- return 0;
- }
-
- // set_animation(self, frame_range, frame_speed, frame_blend)
- static int l_set_animation(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // Do it
- v2f frames = v2f(1, 1);
- if(!lua_isnil(L, 2))
- frames = read_v2f(L, 2);
- float frame_speed = 15;
- if(!lua_isnil(L, 3))
- frame_speed = lua_tonumber(L, 3);
- float frame_blend = 0;
- if(!lua_isnil(L, 4))
- frame_blend = lua_tonumber(L, 4);
- co->setAnimation(frames, frame_speed, frame_blend);
- return 0;
- }
-
- // set_bone_position(self, std::string bone, v3f position, v3f rotation)
- static int l_set_bone_position(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // Do it
- std::string bone = "";
- if(!lua_isnil(L, 2))
- bone = lua_tostring(L, 2);
- v3f position = v3f(0, 0, 0);
- if(!lua_isnil(L, 3))
- position = read_v3f(L, 3);
- v3f rotation = v3f(0, 0, 0);
- if(!lua_isnil(L, 4))
- rotation = read_v3f(L, 4);
- co->setBonePosition(bone, position, rotation);
- return 0;
- }
-
- // set_attach(self, parent, bone, position, rotation)
- static int l_set_attach(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ObjectRef *parent_ref = checkobject(L, 2);
- ServerActiveObject *co = getobject(ref);
- ServerActiveObject *parent = getobject(parent_ref);
- if(co == NULL) return 0;
- if(parent == NULL) return 0;
- // Do it
- std::string bone = "";
- if(!lua_isnil(L, 3))
- bone = lua_tostring(L, 3);
- v3f position = v3f(0, 0, 0);
- if(!lua_isnil(L, 4))
- position = read_v3f(L, 4);
- v3f rotation = v3f(0, 0, 0);
- if(!lua_isnil(L, 5))
- rotation = read_v3f(L, 5);
- co->setAttachment(parent->getId(), bone, position, rotation);
- return 0;
- }
-
- // set_detach(self)
- static int l_set_detach(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- // Do it
- co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
- return 0;
- }
-
- // set_properties(self, properties)
- static int l_set_properties(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
- ObjectProperties *prop = co->accessObjectProperties();
- if(!prop)
- return 0;
- read_object_properties(L, 2, prop);
- co->notifyObjectPropertiesModified();
- return 0;
- }
-
- /* LuaEntitySAO-only */
-
- // setvelocity(self, {x=num, y=num, z=num})
- static int l_setvelocity(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- v3f pos = checkFloatPos(L, 2);
- // Do it
- co->setVelocity(pos);
- return 0;
- }
-
- // getvelocity(self)
- static int l_getvelocity(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- // Do it
- v3f v = co->getVelocity();
- pushFloatPos(L, v);
- return 1;
- }
-
- // setacceleration(self, {x=num, y=num, z=num})
- static int l_setacceleration(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- // pos
- v3f pos = checkFloatPos(L, 2);
- // Do it
- co->setAcceleration(pos);
- return 0;
- }
-
- // getacceleration(self)
- static int l_getacceleration(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- // Do it
- v3f v = co->getAcceleration();
- pushFloatPos(L, v);
- return 1;
- }
-
- // setyaw(self, radians)
- static int l_setyaw(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
- // Do it
- co->setYaw(yaw);
- return 0;
- }
-
- // getyaw(self)
- static int l_getyaw(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- // Do it
- float yaw = co->getYaw() * core::DEGTORAD;
- lua_pushnumber(L, yaw);
- return 1;
- }
-
- // settexturemod(self, mod)
- static int l_settexturemod(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- // Do it
- std::string mod = luaL_checkstring(L, 2);
- co->setTextureMod(mod);
- return 0;
- }
-
- // setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
- // select_horiz_by_yawpitch=false)
- static int l_setsprite(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- // Do it
- v2s16 p(0,0);
- if(!lua_isnil(L, 2))
- p = read_v2s16(L, 2);
- int num_frames = 1;
- if(!lua_isnil(L, 3))
- num_frames = lua_tonumber(L, 3);
- float framelength = 0.2;
- if(!lua_isnil(L, 4))
- framelength = lua_tonumber(L, 4);
- bool select_horiz_by_yawpitch = false;
- if(!lua_isnil(L, 5))
- select_horiz_by_yawpitch = lua_toboolean(L, 5);
- co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
- return 0;
- }
-
- // DEPRECATED
- // get_entity_name(self)
- static int l_get_entity_name(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- // Do it
- std::string name = co->getName();
- lua_pushstring(L, name.c_str());
- return 1;
- }
-
- // get_luaentity(self)
- static int l_get_luaentity(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
- // Do it
- luaentity_get(L, co->getId());
- return 1;
- }
-
- /* Player-only */
-
- // is_player(self)
- static int l_is_player(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- lua_pushboolean(L, (player != NULL));
- return 1;
- }
-
- // get_player_name(self)
- static int l_get_player_name(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- if(player == NULL){
- lua_pushlstring(L, "", 0);
- return 1;
- }
- // Do it
- lua_pushstring(L, player->getName());
- return 1;
- }
-
- // get_look_dir(self)
- static int l_get_look_dir(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- if(player == NULL) return 0;
- // Do it
- float pitch = player->getRadPitch();
- float yaw = player->getRadYaw();
- v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw));
- push_v3f(L, v);
- return 1;
- }
-
- // get_look_pitch(self)
- static int l_get_look_pitch(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- if(player == NULL) return 0;
- // Do it
- lua_pushnumber(L, player->getRadPitch());
- return 1;
- }
-
- // get_look_yaw(self)
- static int l_get_look_yaw(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- if(player == NULL) return 0;
- // Do it
- lua_pushnumber(L, player->getRadYaw());
- return 1;
- }
-
- // set_inventory_formspec(self, formspec)
- static int l_set_inventory_formspec(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- if(player == NULL) return 0;
- std::string formspec = luaL_checkstring(L, 2);
-
- player->inventory_formspec = formspec;
- get_server(L)->reportInventoryFormspecModified(player->getName());
- lua_pushboolean(L, true);
- return 1;
- }
-
- // get_inventory_formspec(self) -> formspec
- static int l_get_inventory_formspec(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- if(player == NULL) return 0;
-
- std::string formspec = player->inventory_formspec;
- lua_pushlstring(L, formspec.c_str(), formspec.size());
- return 1;
- }
-
- // get_player_control(self)
- static int l_get_player_control(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- if(player == NULL){
- lua_pushlstring(L, "", 0);
- return 1;
- }
- // Do it
- PlayerControl control = player->getPlayerControl();
- lua_newtable(L);
- lua_pushboolean(L, control.up);
- lua_setfield(L, -2, "up");
- lua_pushboolean(L, control.down);
- lua_setfield(L, -2, "down");
- lua_pushboolean(L, control.left);
- lua_setfield(L, -2, "left");
- lua_pushboolean(L, control.right);
- lua_setfield(L, -2, "right");
- lua_pushboolean(L, control.jump);
- lua_setfield(L, -2, "jump");
- lua_pushboolean(L, control.aux1);
- lua_setfield(L, -2, "aux1");
- lua_pushboolean(L, control.sneak);
- lua_setfield(L, -2, "sneak");
- lua_pushboolean(L, control.LMB);
- lua_setfield(L, -2, "LMB");
- lua_pushboolean(L, control.RMB);
- lua_setfield(L, -2, "RMB");
- return 1;
- }
-
- // get_player_control_bits(self)
- static int l_get_player_control_bits(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- if(player == NULL){
- lua_pushlstring(L, "", 0);
- return 1;
- }
- // Do it
- lua_pushnumber(L, player->keyPressed);
- return 1;
- }
-
-public:
- ObjectRef(ServerActiveObject *object):
- m_object(object)
- {
- //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
- }
-
- ~ObjectRef()
- {
- /*if(m_object)
- infostream<<"ObjectRef destructing for id="
- <<m_object->getId()<<std::endl;
- else
- infostream<<"ObjectRef destructing for id=unknown"<<std::endl;*/
- }
-
- // Creates an ObjectRef and leaves it on top of stack
- // Not callable from Lua; all references are created on the C side.
- static void create(lua_State *L, ServerActiveObject *object)
- {
- ObjectRef *o = new ObjectRef(object);
- //infostream<<"ObjectRef::create: o="<<o<<std::endl;
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- }
-
- static void set_null(lua_State *L)
- {
- ObjectRef *o = checkobject(L, -1);
- o->m_object = NULL;
- }
-
- static void Register(lua_State *L)
- {
- lua_newtable(L);
- int methodtable = lua_gettop(L);
- luaL_newmetatable(L, className);
- int metatable = lua_gettop(L);
-
- lua_pushliteral(L, "__metatable");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
-
- lua_pushliteral(L, "__index");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable);
-
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_object);
- lua_settable(L, metatable);
-
- lua_pop(L, 1); // drop metatable
-
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
-
- // Cannot be created from Lua
- //lua_register(L, className, create_object);
- }
-};
-const char ObjectRef::className[] = "ObjectRef";
-const luaL_reg ObjectRef::methods[] = {
- // ServerActiveObject
- method(ObjectRef, remove),
- method(ObjectRef, getpos),
- method(ObjectRef, setpos),
- method(ObjectRef, moveto),
- method(ObjectRef, punch),
- method(ObjectRef, right_click),
- method(ObjectRef, set_hp),
- method(ObjectRef, get_hp),
- method(ObjectRef, get_inventory),
- method(ObjectRef, get_wield_list),
- method(ObjectRef, get_wield_index),
- method(ObjectRef, get_wielded_item),
- method(ObjectRef, set_wielded_item),
- method(ObjectRef, set_armor_groups),
- method(ObjectRef, set_animation),
- method(ObjectRef, set_bone_position),
- method(ObjectRef, set_attach),
- method(ObjectRef, set_detach),
- method(ObjectRef, set_properties),
- // LuaEntitySAO-only
- method(ObjectRef, setvelocity),
- method(ObjectRef, getvelocity),
- method(ObjectRef, setacceleration),
- method(ObjectRef, getacceleration),
- method(ObjectRef, setyaw),
- method(ObjectRef, getyaw),
- method(ObjectRef, settexturemod),
- method(ObjectRef, setsprite),
- method(ObjectRef, get_entity_name),
- method(ObjectRef, get_luaentity),
- // Player-only
- method(ObjectRef, is_player),
- method(ObjectRef, get_player_name),
- method(ObjectRef, get_look_dir),
- method(ObjectRef, get_look_pitch),
- method(ObjectRef, get_look_yaw),
- method(ObjectRef, set_inventory_formspec),
- method(ObjectRef, get_inventory_formspec),
- method(ObjectRef, get_player_control),
- method(ObjectRef, get_player_control_bits),
- {0,0}
-};
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
-// Creates a new anonymous reference if cobj=NULL or id=0
-static void objectref_get_or_create(lua_State *L,
- ServerActiveObject *cobj)
-{
- if(cobj == NULL || cobj->getId() == 0){
- ObjectRef::create(L, cobj);
- } else {
- objectref_get(L, cobj->getId());
- }
+ // Get registered shutdown hooks
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_shutdown");
+ // Call callbacks
+ scriptapi_run_callbacks(L, 0, RUN_CALLBACKS_MODE_FIRST);
}
-class LuaPerlinNoise
+void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player)
{
-private:
- int seed;
- int octaves;
- float persistence;
- float scale;
- static const char className[];
- static const luaL_reg methods[];
-
- // Exported functions
-
- // garbage collector
- static int gc_object(lua_State *L)
- {
- LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
- delete o;
- return 0;
- }
-
- static int l_get2d(lua_State *L)
- {
- LuaPerlinNoise *o = checkobject(L, 1);
- v2f pos2d = read_v2f(L,2);
- lua_Number val = noise2d_perlin(pos2d.X/o->scale, pos2d.Y/o->scale, o->seed, o->octaves, o->persistence);
- lua_pushnumber(L, val);
- return 1;
- }
- static int l_get3d(lua_State *L)
- {
- LuaPerlinNoise *o = checkobject(L, 1);
- v3f pos3d = read_v3f(L,2);
- lua_Number val = noise3d_perlin(pos3d.X/o->scale, pos3d.Y/o->scale, pos3d.Z/o->scale, o->seed, o->octaves, o->persistence);
- lua_pushnumber(L, val);
- return 1;
- }
-
-public:
- LuaPerlinNoise(int a_seed, int a_octaves, float a_persistence,
- float a_scale):
- seed(a_seed),
- octaves(a_octaves),
- persistence(a_persistence),
- scale(a_scale)
- {
- }
-
- ~LuaPerlinNoise()
- {
- }
-
- // LuaPerlinNoise(seed, octaves, persistence, scale)
- // Creates an LuaPerlinNoise and leaves it on top of stack
- static int create_object(lua_State *L)
- {
- int seed = luaL_checkint(L, 1);
- int octaves = luaL_checkint(L, 2);
- float persistence = luaL_checknumber(L, 3);
- float scale = luaL_checknumber(L, 4);
- LuaPerlinNoise *o = new LuaPerlinNoise(seed, octaves, persistence, scale);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- return 1;
- }
-
- static LuaPerlinNoise* checkobject(lua_State *L, int narg)
- {
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(LuaPerlinNoise**)ud; // unbox pointer
- }
-
- static void Register(lua_State *L)
- {
- lua_newtable(L);
- int methodtable = lua_gettop(L);
- luaL_newmetatable(L, className);
- int metatable = lua_gettop(L);
-
- lua_pushliteral(L, "__metatable");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
-
- lua_pushliteral(L, "__index");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable);
-
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_object);
- lua_settable(L, metatable);
-
- lua_pop(L, 1); // drop metatable
-
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
- // Can be created from Lua (PerlinNoise(seed, octaves, persistence)
- lua_register(L, className, create_object);
- }
-};
-const char LuaPerlinNoise::className[] = "PerlinNoise";
-const luaL_reg LuaPerlinNoise::methods[] = {
- method(LuaPerlinNoise, get2d),
- method(LuaPerlinNoise, get3d),
- {0,0}
-};
+ // Get minetest.registered_on_newplayers
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_newplayers");
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+}
-/*
- PerlinNoiseMap
- */
-class LuaPerlinNoiseMap
+void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player)
{
-private:
- Noise *noise;
- static const char className[];
- static const luaL_reg methods[];
-
- static int gc_object(lua_State *L)
- {
- LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
- delete o;
- return 0;
- }
-
- static int l_get2dMap(lua_State *L)
- {
- int i = 0;
-
- LuaPerlinNoiseMap *o = checkobject(L, 1);
- v2f p = read_v2f(L, 2);
-
- Noise *n = o->noise;
- n->perlinMap2D(p.X, p.Y);
-
- lua_newtable(L);
- for (int y = 0; y != n->sy; y++) {
- lua_newtable(L);
- for (int x = 0; x != n->sx; x++) {
- float noiseval = n->np->offset + n->np->scale * n->result[i++];
- lua_pushnumber(L, noiseval);
- lua_rawseti(L, -2, x + 1);
- }
- lua_rawseti(L, -2, y + 1);
- }
- return 1;
- }
-
- static int l_get3dMap(lua_State *L)
- {
- int i = 0;
-
- LuaPerlinNoiseMap *o = checkobject(L, 1);
- v3f p = read_v3f(L, 2);
-
- Noise *n = o->noise;
- n->perlinMap3D(p.X, p.Y, p.Z);
-
- lua_newtable(L);
- for (int z = 0; z != n->sz; z++) {
- lua_newtable(L);
- for (int y = 0; y != n->sy; y++) {
- lua_newtable(L);
- for (int x = 0; x != n->sx; x++) {
- lua_pushnumber(L, n->np->offset + n->np->scale * n->result[i++]);
- lua_rawseti(L, -2, x + 1);
- }
- lua_rawseti(L, -2, y + 1);
- }
- lua_rawseti(L, -2, z + 1);
- }
- return 1;
- }
-
-public:
- LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size) {
- noise = new Noise(np, seed, size.X, size.Y, size.Z);
- }
-
- ~LuaPerlinNoiseMap()
- {
- delete noise->np;
- delete noise;
- }
-
- // LuaPerlinNoiseMap(np, size)
- // Creates an LuaPerlinNoiseMap and leaves it on top of stack
- static int create_object(lua_State *L)
- {
- NoiseParams *np = read_noiseparams(L, 1);
- if (!np)
- return 0;
- v3s16 size = read_v3s16(L, 2);
-
- LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(np, 0, size);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- return 1;
- }
-
- static LuaPerlinNoiseMap *checkobject(lua_State *L, int narg)
- {
- luaL_checktype(L, narg, LUA_TUSERDATA);
-
- void *ud = luaL_checkudata(L, narg, className);
- if (!ud)
- luaL_typerror(L, narg, className);
-
- return *(LuaPerlinNoiseMap **)ud; // unbox pointer
- }
-
- static void Register(lua_State *L)
- {
- lua_newtable(L);
- int methodtable = lua_gettop(L);
- luaL_newmetatable(L, className);
- int metatable = lua_gettop(L);
-
- lua_pushliteral(L, "__metatable");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
-
- lua_pushliteral(L, "__index");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable);
-
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_object);
- lua_settable(L, metatable);
-
- lua_pop(L, 1); // drop metatable
-
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
-
- // Can be created from Lua (PerlinNoiseMap(np, size)
- lua_register(L, className, create_object);
- }
-};
-const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
-const luaL_reg LuaPerlinNoiseMap::methods[] = {
- method(LuaPerlinNoiseMap, get2dMap),
- method(LuaPerlinNoiseMap, get3dMap),
- {0,0}
-};
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
-/*
- NodeTimerRef
-*/
+ // Get minetest.registered_on_dieplayers
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_dieplayers");
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+}
-class NodeTimerRef
+bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
{
-private:
- v3s16 m_p;
- ServerEnvironment *m_env;
-
- static const char className[];
- static const luaL_reg methods[];
-
- static int gc_object(lua_State *L) {
- NodeTimerRef *o = *(NodeTimerRef **)(lua_touserdata(L, 1));
- delete o;
- return 0;
- }
-
- static NodeTimerRef *checkobject(lua_State *L, int narg)
- {
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(NodeTimerRef**)ud; // unbox pointer
- }
-
- static int l_set(lua_State *L)
- {
- NodeTimerRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- f32 t = luaL_checknumber(L,2);
- f32 e = luaL_checknumber(L,3);
- env->getMap().setNodeTimer(o->m_p,NodeTimer(t,e));
- return 0;
- }
-
- static int l_start(lua_State *L)
- {
- NodeTimerRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- f32 t = luaL_checknumber(L,2);
- env->getMap().setNodeTimer(o->m_p,NodeTimer(t,0));
- return 0;
- }
-
- static int l_stop(lua_State *L)
- {
- NodeTimerRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- env->getMap().removeNodeTimer(o->m_p);
- return 0;
- }
-
- static int l_is_started(lua_State *L)
- {
- NodeTimerRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
-
- NodeTimer t = env->getMap().getNodeTimer(o->m_p);
- lua_pushboolean(L,(t.timeout != 0));
- return 1;
- }
-
- static int l_get_timeout(lua_State *L)
- {
- NodeTimerRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
-
- NodeTimer t = env->getMap().getNodeTimer(o->m_p);
- lua_pushnumber(L,t.timeout);
- return 1;
- }
-
- static int l_get_elapsed(lua_State *L)
- {
- NodeTimerRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
-
- NodeTimer t = env->getMap().getNodeTimer(o->m_p);
- lua_pushnumber(L,t.elapsed);
- return 1;
- }
-
-public:
- NodeTimerRef(v3s16 p, ServerEnvironment *env):
- m_p(p),
- m_env(env)
- {
- }
-
- ~NodeTimerRef()
- {
- }
-
- // Creates an NodeTimerRef and leaves it on top of stack
- // Not callable from Lua; all references are created on the C side.
- static void create(lua_State *L, v3s16 p, ServerEnvironment *env)
- {
- NodeTimerRef *o = new NodeTimerRef(p, env);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- }
-
- static void set_null(lua_State *L)
- {
- NodeTimerRef *o = checkobject(L, -1);
- o->m_env = NULL;
- }
-
- static void Register(lua_State *L)
- {
- lua_newtable(L);
- int methodtable = lua_gettop(L);
- luaL_newmetatable(L, className);
- int metatable = lua_gettop(L);
-
- lua_pushliteral(L, "__metatable");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
-
- lua_pushliteral(L, "__index");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable);
-
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_object);
- lua_settable(L, metatable);
-
- lua_pop(L, 1); // drop metatable
-
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
-
- // Cannot be created from Lua
- //lua_register(L, className, create_object);
- }
-};
-const char NodeTimerRef::className[] = "NodeTimerRef";
-const luaL_reg NodeTimerRef::methods[] = {
- method(NodeTimerRef, start),
- method(NodeTimerRef, set),
- method(NodeTimerRef, stop),
- method(NodeTimerRef, is_started),
- method(NodeTimerRef, get_timeout),
- method(NodeTimerRef, get_elapsed),
- {0,0}
-};
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
-/*
- EnvRef
-*/
+ // Get minetest.registered_on_respawnplayers
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_respawnplayers");
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_OR);
+ bool positioning_handled_by_some = lua_toboolean(L, -1);
+ return positioning_handled_by_some;
+}
-class EnvRef
+void scriptapi_on_joinplayer(lua_State *L, ServerActiveObject *player)
{
-private:
- ServerEnvironment *m_env;
-
- static const char className[];
- static const luaL_reg methods[];
-
- static int gc_object(lua_State *L) {
- EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
- delete o;
- return 0;
- }
-
- static EnvRef *checkobject(lua_State *L, int narg)
- {
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(EnvRef**)ud; // unbox pointer
- }
-
- // Exported functions
-
- // EnvRef:set_node(pos, node)
- // pos = {x=num, y=num, z=num}
- static int l_set_node(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- INodeDefManager *ndef = env->getGameDef()->ndef();
- // parameters
- v3s16 pos = read_v3s16(L, 2);
- MapNode n = readnode(L, 3, ndef);
- // Do it
- bool succeeded = env->setNode(pos, n);
- lua_pushboolean(L, succeeded);
- return 1;
- }
-
- static int l_add_node(lua_State *L)
- {
- return l_set_node(L);
- }
-
- // EnvRef:remove_node(pos)
- // pos = {x=num, y=num, z=num}
- static int l_remove_node(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- INodeDefManager *ndef = env->getGameDef()->ndef();
- // parameters
- v3s16 pos = read_v3s16(L, 2);
- // Do it
- bool succeeded = env->removeNode(pos);
- lua_pushboolean(L, succeeded);
- return 1;
- }
-
- // EnvRef:get_node(pos)
- // pos = {x=num, y=num, z=num}
- static int l_get_node(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // pos
- v3s16 pos = read_v3s16(L, 2);
- // Do it
- MapNode n = env->getMap().getNodeNoEx(pos);
- // Return node
- pushnode(L, n, env->getGameDef()->ndef());
- return 1;
- }
-
- // EnvRef:get_node_or_nil(pos)
- // pos = {x=num, y=num, z=num}
- static int l_get_node_or_nil(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // pos
- v3s16 pos = read_v3s16(L, 2);
- // Do it
- try{
- MapNode n = env->getMap().getNode(pos);
- // Return node
- pushnode(L, n, env->getGameDef()->ndef());
- return 1;
- } catch(InvalidPositionException &e)
- {
- lua_pushnil(L);
- return 1;
- }
- }
-
- // EnvRef:get_node_light(pos, timeofday)
- // pos = {x=num, y=num, z=num}
- // timeofday: nil = current time, 0 = night, 0.5 = day
- static int l_get_node_light(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // Do it
- v3s16 pos = read_v3s16(L, 2);
- u32 time_of_day = env->getTimeOfDay();
- if(lua_isnumber(L, 3))
- time_of_day = 24000.0 * lua_tonumber(L, 3);
- time_of_day %= 24000;
- u32 dnr = time_to_daynight_ratio(time_of_day, true);
- MapNode n = env->getMap().getNodeNoEx(pos);
- try{
- MapNode n = env->getMap().getNode(pos);
- INodeDefManager *ndef = env->getGameDef()->ndef();
- lua_pushinteger(L, n.getLightBlend(dnr, ndef));
- return 1;
- } catch(InvalidPositionException &e)
- {
- lua_pushnil(L);
- return 1;
- }
- }
-
- // EnvRef:place_node(pos, node)
- // pos = {x=num, y=num, z=num}
- static int l_place_node(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- v3s16 pos = read_v3s16(L, 2);
- MapNode n = readnode(L, 3, env->getGameDef()->ndef());
-
- // Don't attempt to load non-loaded area as of now
- MapNode n_old = env->getMap().getNodeNoEx(pos);
- if(n_old.getContent() == CONTENT_IGNORE){
- lua_pushboolean(L, false);
- return 1;
- }
- // Create item to place
- INodeDefManager *ndef = get_server(L)->ndef();
- IItemDefManager *idef = get_server(L)->idef();
- ItemStack item(ndef->get(n).name, 1, 0, "", idef);
- // Make pointed position
- PointedThing pointed;
- pointed.type = POINTEDTHING_NODE;
- pointed.node_abovesurface = pos;
- pointed.node_undersurface = pos + v3s16(0,-1,0);
- // Place it with a NULL placer (appears in Lua as a non-functional
- // ObjectRef)
- bool success = scriptapi_item_on_place(L, item, NULL, pointed);
- lua_pushboolean(L, success);
- return 1;
- }
-
- // EnvRef:dig_node(pos)
- // pos = {x=num, y=num, z=num}
- static int l_dig_node(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- v3s16 pos = read_v3s16(L, 2);
-
- // Don't attempt to load non-loaded area as of now
- MapNode n = env->getMap().getNodeNoEx(pos);
- if(n.getContent() == CONTENT_IGNORE){
- lua_pushboolean(L, false);
- return 1;
- }
- // Dig it out with a NULL digger (appears in Lua as a
- // non-functional ObjectRef)
- bool success = scriptapi_node_on_dig(L, pos, n, NULL);
- lua_pushboolean(L, success);
- return 1;
- }
-
- // EnvRef:punch_node(pos)
- // pos = {x=num, y=num, z=num}
- static int l_punch_node(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- v3s16 pos = read_v3s16(L, 2);
-
- // Don't attempt to load non-loaded area as of now
- MapNode n = env->getMap().getNodeNoEx(pos);
- if(n.getContent() == CONTENT_IGNORE){
- lua_pushboolean(L, false);
- return 1;
- }
- // Punch it with a NULL puncher (appears in Lua as a non-functional
- // ObjectRef)
- bool success = scriptapi_node_on_punch(L, pos, n, NULL);
- lua_pushboolean(L, success);
- return 1;
- }
-
- // EnvRef:get_meta(pos)
- static int l_get_meta(lua_State *L)
- {
- //infostream<<"EnvRef::l_get_meta()"<<std::endl;
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // Do it
- v3s16 p = read_v3s16(L, 2);
- NodeMetaRef::create(L, p, env);
- return 1;
- }
-
- // EnvRef:get_node_timer(pos)
- static int l_get_node_timer(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // Do it
- v3s16 p = read_v3s16(L, 2);
- NodeTimerRef::create(L, p, env);
- return 1;
- }
-
- // EnvRef:add_entity(pos, entityname) -> ObjectRef or nil
- // pos = {x=num, y=num, z=num}
- static int l_add_entity(lua_State *L)
- {
- //infostream<<"EnvRef::l_add_entity()"<<std::endl;
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // pos
- v3f pos = checkFloatPos(L, 2);
- // content
- const char *name = luaL_checkstring(L, 3);
- // Do it
- ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, "");
- int objectid = env->addActiveObject(obj);
- // If failed to add, return nothing (reads as nil)
- if(objectid == 0)
- return 0;
- // Return ObjectRef
- objectref_get_or_create(L, obj);
- return 1;
- }
-
- // EnvRef:add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
- // pos = {x=num, y=num, z=num}
- static int l_add_item(lua_State *L)
- {
- //infostream<<"EnvRef::l_add_item()"<<std::endl;
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // pos
- v3f pos = checkFloatPos(L, 2);
- // item
- ItemStack item = read_item(L, 3);
- if(item.empty() || !item.isKnown(get_server(L)->idef()))
- return 0;
- // Use minetest.spawn_item to spawn a __builtin:item
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "spawn_item");
- if(lua_isnil(L, -1))
- return 0;
- lua_pushvalue(L, 2);
- lua_pushstring(L, item.getItemString().c_str());
- if(lua_pcall(L, 2, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- return 1;
- /*lua_pushvalue(L, 1);
- lua_pushstring(L, "__builtin:item");
- lua_pushstring(L, item.getItemString().c_str());
- return l_add_entity(L);*/
- /*// Do it
- ServerActiveObject *obj = createItemSAO(env, pos, item.getItemString());
- int objectid = env->addActiveObject(obj);
- // If failed to add, return nothing (reads as nil)
- if(objectid == 0)
- return 0;
- // Return ObjectRef
- objectref_get_or_create(L, obj);
- return 1;*/
- }
-
- // EnvRef:add_rat(pos)
- // pos = {x=num, y=num, z=num}
- static int l_add_rat(lua_State *L)
- {
- infostream<<"EnvRef::l_add_rat(): C++ mobs have been removed."
- <<" Doing nothing."<<std::endl;
- return 0;
- }
-
- // EnvRef:add_firefly(pos)
- // pos = {x=num, y=num, z=num}
- static int l_add_firefly(lua_State *L)
- {
- infostream<<"EnvRef::l_add_firefly(): C++ mobs have been removed."
- <<" Doing nothing."<<std::endl;
- return 0;
- }
-
- // EnvRef:get_player_by_name(name)
- static int l_get_player_by_name(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // Do it
- const char *name = luaL_checkstring(L, 2);
- Player *player = env->getPlayer(name);
- if(player == NULL){
- lua_pushnil(L);
- return 1;
- }
- PlayerSAO *sao = player->getPlayerSAO();
- if(sao == NULL){
- lua_pushnil(L);
- return 1;
- }
- // Put player on stack
- objectref_get_or_create(L, sao);
- return 1;
- }
-
- // EnvRef:get_objects_inside_radius(pos, radius)
- static int l_get_objects_inside_radius(lua_State *L)
- {
- // Get the table insert function
- lua_getglobal(L, "table");
- lua_getfield(L, -1, "insert");
- int table_insert = lua_gettop(L);
- // Get environemnt
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // Do it
- v3f pos = checkFloatPos(L, 2);
- float radius = luaL_checknumber(L, 3) * BS;
- std::set<u16> ids = env->getObjectsInsideRadius(pos, radius);
- lua_newtable(L);
- int table = lua_gettop(L);
- for(std::set<u16>::const_iterator
- i = ids.begin(); i != ids.end(); i++){
- ServerActiveObject *obj = env->getActiveObject(*i);
- // Insert object reference into table
- lua_pushvalue(L, table_insert);
- lua_pushvalue(L, table);
- objectref_get_or_create(L, obj);
- if(lua_pcall(L, 2, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- }
- return 1;
- }
-
- // EnvRef:set_timeofday(val)
- // val = 0...1
- static int l_set_timeofday(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // Do it
- float timeofday_f = luaL_checknumber(L, 2);
- assert(timeofday_f >= 0.0 && timeofday_f <= 1.0);
- int timeofday_mh = (int)(timeofday_f * 24000.0);
- // This should be set directly in the environment but currently
- // such changes aren't immediately sent to the clients, so call
- // the server instead.
- //env->setTimeOfDay(timeofday_mh);
- get_server(L)->setTimeOfDay(timeofday_mh);
- return 0;
- }
-
- // EnvRef:get_timeofday() -> 0...1
- static int l_get_timeofday(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // Do it
- int timeofday_mh = env->getTimeOfDay();
- float timeofday_f = (float)timeofday_mh / 24000.0;
- lua_pushnumber(L, timeofday_f);
- return 1;
- }
-
-
- // EnvRef:find_node_near(pos, radius, nodenames) -> pos or nil
- // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
- static int l_find_node_near(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- INodeDefManager *ndef = get_server(L)->ndef();
- v3s16 pos = read_v3s16(L, 2);
- int radius = luaL_checkinteger(L, 3);
- std::set<content_t> filter;
- if(lua_istable(L, 4)){
- int table = 4;
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- ndef->getIds(lua_tostring(L, -1), filter);
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- } else if(lua_isstring(L, 4)){
- ndef->getIds(lua_tostring(L, 4), filter);
- }
-
- for(int d=1; d<=radius; d++){
- core::list<v3s16> list;
- getFacePositions(list, d);
- for(core::list<v3s16>::Iterator i = list.begin();
- i != list.end(); i++){
- v3s16 p = pos + (*i);
- content_t c = env->getMap().getNodeNoEx(p).getContent();
- if(filter.count(c) != 0){
- push_v3s16(L, p);
- return 1;
- }
- }
- }
- return 0;
- }
-
- // EnvRef:find_nodes_in_area(minp, maxp, nodenames) -> list of positions
- // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
- static int l_find_nodes_in_area(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- INodeDefManager *ndef = get_server(L)->ndef();
- v3s16 minp = read_v3s16(L, 2);
- v3s16 maxp = read_v3s16(L, 3);
- std::set<content_t> filter;
- if(lua_istable(L, 4)){
- int table = 4;
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- ndef->getIds(lua_tostring(L, -1), filter);
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- } else if(lua_isstring(L, 4)){
- ndef->getIds(lua_tostring(L, 4), filter);
- }
-
- // Get the table insert function
- lua_getglobal(L, "table");
- lua_getfield(L, -1, "insert");
- int table_insert = lua_gettop(L);
-
- lua_newtable(L);
- int table = lua_gettop(L);
- for(s16 x=minp.X; x<=maxp.X; x++)
- for(s16 y=minp.Y; y<=maxp.Y; y++)
- for(s16 z=minp.Z; z<=maxp.Z; z++)
- {
- v3s16 p(x,y,z);
- content_t c = env->getMap().getNodeNoEx(p).getContent();
- if(filter.count(c) != 0){
- lua_pushvalue(L, table_insert);
- lua_pushvalue(L, table);
- push_v3s16(L, p);
- if(lua_pcall(L, 2, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- }
- }
- return 1;
- }
-
- // EnvRef:get_perlin(seeddiff, octaves, persistence, scale)
- // returns world-specific PerlinNoise
- static int l_get_perlin(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
-
- int seeddiff = luaL_checkint(L, 2);
- int octaves = luaL_checkint(L, 3);
- float persistence = luaL_checknumber(L, 4);
- float scale = luaL_checknumber(L, 5);
-
- LuaPerlinNoise *n = new LuaPerlinNoise(seeddiff + int(env->getServerMap().getSeed()), octaves, persistence, scale);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
- luaL_getmetatable(L, "PerlinNoise");
- lua_setmetatable(L, -2);
- return 1;
- }
-
- // EnvRef:get_perlin_map(noiseparams, size)
- // returns world-specific PerlinNoiseMap
- static int l_get_perlin_map(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if (env == NULL)
- return 0;
-
- NoiseParams *np = read_noiseparams(L, 2);
- if (!np)
- return 0;
- v3s16 size = read_v3s16(L, 3);
-
- int seed = (int)(env->getServerMap().getSeed());
- LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(np, seed, size);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
- luaL_getmetatable(L, "PerlinNoiseMap");
- lua_setmetatable(L, -2);
- return 1;
- }
-
- // EnvRef:clear_objects()
- // clear all objects in the environment
- static int l_clear_objects(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- o->m_env->clearAllObjects();
- return 0;
- }
-
- static int l_spawn_tree(lua_State *L)
- {
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- v3s16 p0 = read_v3s16(L, 2);
-
- treegen::TreeDef tree_def;
- std::string trunk,leaves,fruit;
- INodeDefManager *ndef = env->getGameDef()->ndef();
-
- if(lua_istable(L, 3))
- {
- getstringfield(L, 3, "axiom", tree_def.initial_axiom);
- getstringfield(L, 3, "rules_a", tree_def.rules_a);
- getstringfield(L, 3, "rules_b", tree_def.rules_b);
- getstringfield(L, 3, "rules_c", tree_def.rules_c);
- getstringfield(L, 3, "rules_d", tree_def.rules_d);
- getstringfield(L, 3, "trunk", trunk);
- tree_def.trunknode=ndef->getId(trunk);
- getstringfield(L, 3, "leaves", leaves);
- tree_def.leavesnode=ndef->getId(leaves);
- tree_def.leaves2_chance=0;
- getstringfield(L, 3, "leaves2", leaves);
- if (leaves !="")
- {
- tree_def.leaves2node=ndef->getId(leaves);
- getintfield(L, 3, "leaves2_chance", tree_def.leaves2_chance);
- }
- getintfield(L, 3, "angle", tree_def.angle);
- getintfield(L, 3, "iterations", tree_def.iterations);
- getintfield(L, 3, "random_level", tree_def.iterations_random_level);
- getstringfield(L, 3, "trunk_type", tree_def.trunk_type);
- getboolfield(L, 3, "thin_branches", tree_def.thin_branches);
- tree_def.fruit_chance=0;
- getstringfield(L, 3, "fruit", fruit);
- if (fruit != "")
- {
- tree_def.fruitnode=ndef->getId(fruit);
- getintfield(L, 3, "fruit_chance",tree_def.fruit_chance);
- }
- getintfield(L, 3, "seed", tree_def.seed);
- }
- else
- return 0;
- treegen::spawn_ltree (env, p0, ndef, tree_def);
- return 1;
- }
-
-public:
- EnvRef(ServerEnvironment *env):
- m_env(env)
- {
- //infostream<<"EnvRef created"<<std::endl;
- }
-
- ~EnvRef()
- {
- //infostream<<"EnvRef destructing"<<std::endl;
- }
-
- // Creates an EnvRef and leaves it on top of stack
- // Not callable from Lua; all references are created on the C side.
- static void create(lua_State *L, ServerEnvironment *env)
- {
- EnvRef *o = new EnvRef(env);
- //infostream<<"EnvRef::create: o="<<o<<std::endl;
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- }
-
- static void set_null(lua_State *L)
- {
- EnvRef *o = checkobject(L, -1);
- o->m_env = NULL;
- }
-
- static void Register(lua_State *L)
- {
- lua_newtable(L);
- int methodtable = lua_gettop(L);
- luaL_newmetatable(L, className);
- int metatable = lua_gettop(L);
-
- lua_pushliteral(L, "__metatable");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
-
- lua_pushliteral(L, "__index");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable);
-
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_object);
- lua_settable(L, metatable);
-
- lua_pop(L, 1); // drop metatable
-
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
-
- // Cannot be created from Lua
- //lua_register(L, className, create_object);
- }
-};
-const char EnvRef::className[] = "EnvRef";
-const luaL_reg EnvRef::methods[] = {
- method(EnvRef, set_node),
- method(EnvRef, add_node),
- method(EnvRef, remove_node),
- method(EnvRef, get_node),
- method(EnvRef, get_node_or_nil),
- method(EnvRef, get_node_light),
- method(EnvRef, place_node),
- method(EnvRef, dig_node),
- method(EnvRef, punch_node),
- method(EnvRef, add_entity),
- method(EnvRef, add_item),
- method(EnvRef, add_rat),
- method(EnvRef, add_firefly),
- method(EnvRef, get_meta),
- method(EnvRef, get_node_timer),
- method(EnvRef, get_player_by_name),
- method(EnvRef, get_objects_inside_radius),
- method(EnvRef, set_timeofday),
- method(EnvRef, get_timeofday),
- method(EnvRef, find_node_near),
- method(EnvRef, find_nodes_in_area),
- method(EnvRef, get_perlin),
- method(EnvRef, get_perlin_map),
- method(EnvRef, clear_objects),
- method(EnvRef, spawn_tree),
- {0,0}
-};
-
-/*
- LuaPseudoRandom
-*/
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+ // Get minetest.registered_on_joinplayers
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_joinplayers");
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+}
-class LuaPseudoRandom
+void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player)
{
-private:
- PseudoRandom m_pseudo;
-
- static const char className[];
- static const luaL_reg methods[];
-
- // Exported functions
-
- // garbage collector
- static int gc_object(lua_State *L)
- {
- LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
- delete o;
- return 0;
- }
-
- // next(self, min=0, max=32767) -> get next value
- static int l_next(lua_State *L)
- {
- LuaPseudoRandom *o = checkobject(L, 1);
- int min = 0;
- int max = 32767;
- lua_settop(L, 3); // Fill 2 and 3 with nil if they don't exist
- if(!lua_isnil(L, 2))
- min = luaL_checkinteger(L, 2);
- if(!lua_isnil(L, 3))
- max = luaL_checkinteger(L, 3);
- if(max < min){
- errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
- throw LuaError(L, "PseudoRandom.next(): max < min");
- }
- if(max - min != 32767 && max - min > 32767/5)
- throw LuaError(L, "PseudoRandom.next() max-min is not 32767 and is > 32768/5. This is disallowed due to the bad random distribution the implementation would otherwise make.");
- PseudoRandom &pseudo = o->m_pseudo;
- int val = pseudo.next();
- val = (val % (max-min+1)) + min;
- lua_pushinteger(L, val);
- return 1;
- }
-
-public:
- LuaPseudoRandom(int seed):
- m_pseudo(seed)
- {
- }
-
- ~LuaPseudoRandom()
- {
- }
-
- const PseudoRandom& getItem() const
- {
- return m_pseudo;
- }
- PseudoRandom& getItem()
- {
- return m_pseudo;
- }
-
- // LuaPseudoRandom(seed)
- // Creates an LuaPseudoRandom and leaves it on top of stack
- static int create_object(lua_State *L)
- {
- int seed = luaL_checknumber(L, 1);
- LuaPseudoRandom *o = new LuaPseudoRandom(seed);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, className);
- lua_setmetatable(L, -2);
- return 1;
- }
-
- static LuaPseudoRandom* checkobject(lua_State *L, int narg)
- {
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(LuaPseudoRandom**)ud; // unbox pointer
- }
-
- static void Register(lua_State *L)
- {
- lua_newtable(L);
- int methodtable = lua_gettop(L);
- luaL_newmetatable(L, className);
- int metatable = lua_gettop(L);
-
- lua_pushliteral(L, "__metatable");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
-
- lua_pushliteral(L, "__index");
- lua_pushvalue(L, methodtable);
- lua_settable(L, metatable);
-
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_object);
- lua_settable(L, metatable);
-
- lua_pop(L, 1); // drop metatable
-
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
-
- // Can be created from Lua (LuaPseudoRandom(seed))
- lua_register(L, className, create_object);
- }
-};
-const char LuaPseudoRandom::className[] = "PseudoRandom";
-const luaL_reg LuaPseudoRandom::methods[] = {
- method(LuaPseudoRandom, next),
- {0,0}
-};
-
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+ // Get minetest.registered_on_leaveplayers
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_leaveplayers");
+ // Call callbacks
+ objectref_get_or_create(L, player);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+}
/*
- LuaABM
+ player
*/
-
-class LuaABM : public ActiveBlockModifier
+void scriptapi_on_player_receive_fields(lua_State *L,
+ ServerActiveObject *player,
+ const std::string &formname,
+ const std::map<std::string, std::string> &fields)
{
-private:
- lua_State *m_lua;
- int m_id;
-
- std::set<std::string> m_trigger_contents;
- std::set<std::string> m_required_neighbors;
- float m_trigger_interval;
- u32 m_trigger_chance;
-public:
- LuaABM(lua_State *L, int id,
- const std::set<std::string> &trigger_contents,
- const std::set<std::string> &required_neighbors,
- float trigger_interval, u32 trigger_chance):
- m_lua(L),
- m_id(id),
- m_trigger_contents(trigger_contents),
- m_required_neighbors(required_neighbors),
- m_trigger_interval(trigger_interval),
- m_trigger_chance(trigger_chance)
- {
- }
- virtual std::set<std::string> getTriggerContents()
- {
- return m_trigger_contents;
- }
- virtual std::set<std::string> getRequiredNeighbors()
- {
- return m_required_neighbors;
- }
- virtual float getTriggerInterval()
- {
- return m_trigger_interval;
- }
- virtual u32 getTriggerChance()
- {
- return m_trigger_chance;
- }
- virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
- u32 active_object_count, u32 active_object_count_wider)
- {
- lua_State *L = m_lua;
-
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_abms
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_abms");
- luaL_checktype(L, -1, LUA_TTABLE);
- int registered_abms = lua_gettop(L);
-
- // Get minetest.registered_abms[m_id]
- lua_pushnumber(L, m_id);
- lua_gettable(L, registered_abms);
- if(lua_isnil(L, -1))
- assert(0);
-
- // Call action
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_getfield(L, -1, "action");
- luaL_checktype(L, -1, LUA_TFUNCTION);
- push_v3s16(L, p);
- pushnode(L, n, env->getGameDef()->ndef());
- lua_pushnumber(L, active_object_count);
- lua_pushnumber(L, active_object_count_wider);
- if(lua_pcall(L, 4, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- }
-};
-
-/*
- ServerSoundParams
-*/
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
-static void read_server_sound_params(lua_State *L, int index,
- ServerSoundParams &params)
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
- // Clear
- params = ServerSoundParams();
- if(lua_istable(L, index)){
- getfloatfield(L, index, "gain", params.gain);
- getstringfield(L, index, "to_player", params.to_player);
- lua_getfield(L, index, "pos");
- if(!lua_isnil(L, -1)){
- v3f p = read_v3f(L, -1)*BS;
- params.pos = p;
- params.type = ServerSoundParams::SSP_POSITIONAL;
- }
- lua_pop(L, 1);
- lua_getfield(L, index, "object");
- if(!lua_isnil(L, -1)){
- ObjectRef *ref = ObjectRef::checkobject(L, -1);
- ServerActiveObject *sao = ObjectRef::getobject(ref);
- if(sao){
- params.object = sao->getId();
- params.type = ServerSoundParams::SSP_OBJECT;
- }
- }
- lua_pop(L, 1);
- params.max_hear_distance = BS*getfloatfield_default(L, index,
- "max_hear_distance", params.max_hear_distance/BS);
- getboolfield(L, index, "loop", params.loop);
+ // Get minetest.registered_on_chat_messages
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_player_receive_fields");
+ // Call callbacks
+ // param 1
+ objectref_get_or_create(L, player);
+ // param 2
+ lua_pushstring(L, formname.c_str());
+ // param 3
+ lua_newtable(L);
+ for(std::map<std::string, std::string>::const_iterator
+ i = fields.begin(); i != fields.end(); i++){
+ const std::string &name = i->first;
+ const std::string &value = i->second;
+ lua_pushstring(L, name.c_str());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
}
+ scriptapi_run_callbacks(L, 3, RUN_CALLBACKS_MODE_OR_SC);
}
-
-/*
- Global functions
-*/
+/*****************************************************************************/
+/* Api functions */
+/*****************************************************************************/
// debug(text)
// Writes a line to dstream
@@ -4644,8 +621,6 @@ static int l_register_biome_groups(lua_State *L)
{
luaL_checktype(L, 1, LUA_TTABLE);
int index = 1;
- if (!lua_istable(L, index))
- throw LuaError(L, "register_biome_groups: parameter is not a table");
BiomeDefManager *bmgr = get_server(L)->getBiomeDef();
if (!bmgr) {
@@ -4717,318 +692,53 @@ static int l_register_biome(lua_State *L)
return 0;
}
-// register_item_raw({lots of stuff})
-static int l_register_item_raw(lua_State *L)
-{
- luaL_checktype(L, 1, LUA_TTABLE);
- int table = 1;
-
- // Get the writable item and node definition managers from the server
- IWritableItemDefManager *idef =
- get_server(L)->getWritableItemDefManager();
- IWritableNodeDefManager *ndef =
- get_server(L)->getWritableNodeDefManager();
-
- // Check if name is defined
- std::string name;
- lua_getfield(L, table, "name");
- if(lua_isstring(L, -1)){
- name = lua_tostring(L, -1);
- verbosestream<<"register_item_raw: "<<name<<std::endl;
- } else {
- throw LuaError(L, "register_item_raw: name is not defined or not a string");
- }
-
- // Check if on_use is defined
-
- ItemDefinition def;
- // Set a distinctive default value to check if this is set
- def.node_placement_prediction = "__default";
- // Read the item definition
- def = read_item_definition(L, table, def);
-
- // Default to having client-side placement prediction for nodes
- // ("" in item definition sets it off)
- if(def.node_placement_prediction == "__default"){
- if(def.type == ITEM_NODE)
- def.node_placement_prediction = name;
- else
- def.node_placement_prediction = "";
- }
-
- // Register item definition
- idef->registerItem(def);
-
- // Read the node definition (content features) and register it
- if(def.type == ITEM_NODE)
- {
- ContentFeatures f = read_content_features(L, table);
- ndef->set(f.name, f);
- }
-
- return 0; /* number of results */
-}
-
-// register_alias_raw(name, convert_to_name)
-static int l_register_alias_raw(lua_State *L)
-{
- std::string name = luaL_checkstring(L, 1);
- std::string convert_to = luaL_checkstring(L, 2);
-
- // Get the writable item definition manager from the server
- IWritableItemDefManager *idef =
- get_server(L)->getWritableItemDefManager();
-
- idef->registerAlias(name, convert_to);
-
- return 0; /* number of results */
-}
-
-// helper for register_craft
-static bool read_craft_recipe_shaped(lua_State *L, int index,
- int &width, std::vector<std::string> &recipe)
+static int l_register_ore(lua_State *L)
{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
-
- if(!lua_istable(L, index))
- return false;
-
- lua_pushnil(L);
- int rowcount = 0;
- while(lua_next(L, index) != 0){
- int colcount = 0;
- // key at index -2 and value at index -1
- if(!lua_istable(L, -1))
- return false;
- int table2 = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table2) != 0){
- // key at index -2 and value at index -1
- if(!lua_isstring(L, -1))
- return false;
- recipe.push_back(lua_tostring(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- colcount++;
- }
- if(rowcount == 0){
- width = colcount;
- } else {
- if(colcount != width)
- return false;
- }
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- rowcount++;
- }
- return width != 0;
-}
-
-// helper for register_craft
-static bool read_craft_recipe_shapeless(lua_State *L, int index,
- std::vector<std::string> &recipe)
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
-
- if(!lua_istable(L, index))
- return false;
-
- lua_pushnil(L);
- while(lua_next(L, index) != 0){
- // key at index -2 and value at index -1
- if(!lua_isstring(L, -1))
- return false;
- recipe.push_back(lua_tostring(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
+ int index = 1;
+ luaL_checktype(L, index, LUA_TTABLE);
+
+ IWritableNodeDefManager *ndef = get_server(L)->getWritableNodeDefManager();
+ EmergeManager *emerge = get_server(L)->getEmergeManager();
+
+ enum OreType oretype = (OreType)getenumfield(L, index,
+ "ore_type", es_OreType, ORE_SCATTER);
+ Ore *ore = createOre(oretype);
+ if (!ore) {
+ errorstream << "register_ore: ore_type "
+ << oretype << " not implemented";
+ return 0;
}
- return true;
-}
-
-// helper for register_craft
-static bool read_craft_replacements(lua_State *L, int index,
- CraftReplacements &replacements)
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
-
- if(!lua_istable(L, index))
- return false;
-
- lua_pushnil(L);
- while(lua_next(L, index) != 0){
- // key at index -2 and value at index -1
- if(!lua_istable(L, -1))
- return false;
- lua_rawgeti(L, -1, 1);
- if(!lua_isstring(L, -1))
- return false;
- std::string replace_from = lua_tostring(L, -1);
- lua_pop(L, 1);
- lua_rawgeti(L, -1, 2);
- if(!lua_isstring(L, -1))
- return false;
- std::string replace_to = lua_tostring(L, -1);
- lua_pop(L, 1);
- replacements.pairs.push_back(
- std::make_pair(replace_from, replace_to));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
+
+ ore->ore_name = getstringfield_default(L, index, "ore", "");
+ ore->wherein_name = getstringfield_default(L, index, "wherein", "");
+ ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
+ ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
+ ore->clust_size = getintfield_default(L, index, "clust_size", 0);
+ ore->height_min = getintfield_default(L, index, "height_min", 0);
+ ore->height_max = getintfield_default(L, index, "height_max", 0);
+ ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0.);
+
+ lua_getfield(L, index, "noise_params");
+ ore->np = read_noiseparams(L, -1);
+ lua_pop(L, 1);
+
+ ore->noise = NULL;
+
+ if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
+ errorstream << "register_ore: clust_scarcity and clust_num_ores"
+ "must be greater than 0";
+ delete ore;
+ return 0;
}
- return true;
+
+ emerge->ores.push_back(ore);
+
+ verbosestream << "register_ore: ore '" << ore->ore_name
+ << "' registered" << std::endl;
+ return 0;
}
-// register_craft({output=item, recipe={{item00,item10},{item01,item11}})
-static int l_register_craft(lua_State *L)
-{
- //infostream<<"register_craft"<<std::endl;
- luaL_checktype(L, 1, LUA_TTABLE);
- int table = 1;
-
- // Get the writable craft definition manager from the server
- IWritableCraftDefManager *craftdef =
- get_server(L)->getWritableCraftDefManager();
-
- std::string type = getstringfield_default(L, table, "type", "shaped");
-
- /*
- CraftDefinitionShaped
- */
- if(type == "shaped"){
- std::string output = getstringfield_default(L, table, "output", "");
- if(output == "")
- throw LuaError(L, "Crafting definition is missing an output");
-
- int width = 0;
- std::vector<std::string> recipe;
- lua_getfield(L, table, "recipe");
- if(lua_isnil(L, -1))
- throw LuaError(L, "Crafting definition is missing a recipe"
- " (output=\"" + output + "\")");
- if(!read_craft_recipe_shaped(L, -1, width, recipe))
- throw LuaError(L, "Invalid crafting recipe"
- " (output=\"" + output + "\")");
-
- CraftReplacements replacements;
- lua_getfield(L, table, "replacements");
- if(!lua_isnil(L, -1))
- {
- if(!read_craft_replacements(L, -1, replacements))
- throw LuaError(L, "Invalid replacements"
- " (output=\"" + output + "\")");
- }
-
- CraftDefinition *def = new CraftDefinitionShaped(
- output, width, recipe, replacements);
- craftdef->registerCraft(def);
- }
- /*
- CraftDefinitionShapeless
- */
- else if(type == "shapeless"){
- std::string output = getstringfield_default(L, table, "output", "");
- if(output == "")
- throw LuaError(L, "Crafting definition (shapeless)"
- " is missing an output");
-
- std::vector<std::string> recipe;
- lua_getfield(L, table, "recipe");
- if(lua_isnil(L, -1))
- throw LuaError(L, "Crafting definition (shapeless)"
- " is missing a recipe"
- " (output=\"" + output + "\")");
- if(!read_craft_recipe_shapeless(L, -1, recipe))
- throw LuaError(L, "Invalid crafting recipe"
- " (output=\"" + output + "\")");
-
- CraftReplacements replacements;
- lua_getfield(L, table, "replacements");
- if(!lua_isnil(L, -1))
- {
- if(!read_craft_replacements(L, -1, replacements))
- throw LuaError(L, "Invalid replacements"
- " (output=\"" + output + "\")");
- }
-
- CraftDefinition *def = new CraftDefinitionShapeless(
- output, recipe, replacements);
- craftdef->registerCraft(def);
- }
- /*
- CraftDefinitionToolRepair
- */
- else if(type == "toolrepair"){
- float additional_wear = getfloatfield_default(L, table,
- "additional_wear", 0.0);
-
- CraftDefinition *def = new CraftDefinitionToolRepair(
- additional_wear);
- craftdef->registerCraft(def);
- }
- /*
- CraftDefinitionCooking
- */
- else if(type == "cooking"){
- std::string output = getstringfield_default(L, table, "output", "");
- if(output == "")
- throw LuaError(L, "Crafting definition (cooking)"
- " is missing an output");
-
- std::string recipe = getstringfield_default(L, table, "recipe", "");
- if(recipe == "")
- throw LuaError(L, "Crafting definition (cooking)"
- " is missing a recipe"
- " (output=\"" + output + "\")");
-
- float cooktime = getfloatfield_default(L, table, "cooktime", 3.0);
-
- CraftReplacements replacements;
- lua_getfield(L, table, "replacements");
- if(!lua_isnil(L, -1))
- {
- if(!read_craft_replacements(L, -1, replacements))
- throw LuaError(L, "Invalid replacements"
- " (cooking output=\"" + output + "\")");
- }
-
- CraftDefinition *def = new CraftDefinitionCooking(
- output, recipe, cooktime, replacements);
- craftdef->registerCraft(def);
- }
- /*
- CraftDefinitionFuel
- */
- else if(type == "fuel"){
- std::string recipe = getstringfield_default(L, table, "recipe", "");
- if(recipe == "")
- throw LuaError(L, "Crafting definition (fuel)"
- " is missing a recipe");
-
- float burntime = getfloatfield_default(L, table, "burntime", 1.0);
-
- CraftReplacements replacements;
- lua_getfield(L, table, "replacements");
- if(!lua_isnil(L, -1))
- {
- if(!read_craft_replacements(L, -1, replacements))
- throw LuaError(L, "Invalid replacements"
- " (fuel recipe=\"" + recipe + "\")");
- }
- CraftDefinition *def = new CraftDefinitionFuel(
- recipe, burntime, replacements);
- craftdef->registerCraft(def);
- }
- else
- {
- throw LuaError(L, "Unknown crafting definition type: \"" + type + "\"");
- }
-
- lua_pop(L, 1);
- return 0; /* number of results */
-}
// setting_set(name, value)
static int l_setting_set(lua_State *L)
@@ -5164,45 +874,6 @@ static int l_unban_player_of_ip(lua_State *L)
return 1;
}
-// get_inventory(location)
-static int l_get_inventory(lua_State *L)
-{
- InventoryLocation loc;
-
- std::string type = checkstringfield(L, 1, "type");
- if(type == "player"){
- std::string name = checkstringfield(L, 1, "name");
- loc.setPlayer(name);
- } else if(type == "node"){
- lua_getfield(L, 1, "pos");
- v3s16 pos = check_v3s16(L, -1);
- loc.setNodeMeta(pos);
- } else if(type == "detached"){
- std::string name = checkstringfield(L, 1, "name");
- loc.setDetached(name);
- }
-
- if(get_server(L)->getInventory(loc) != NULL)
- InvRef::create(L, loc);
- else
- lua_pushnil(L);
- return 1;
-}
-
-// create_detached_inventory_raw(name)
-static int l_create_detached_inventory_raw(lua_State *L)
-{
- const char *name = luaL_checkstring(L, 1);
- if(get_server(L)->createDetachedInventory(name) != NULL){
- InventoryLocation loc;
- loc.setDetached(name);
- InvRef::create(L, loc);
- }else{
- lua_pushnil(L);
- }
- return 1;
-}
-
// show_formspec(playername,formname,formspec)
static int l_show_formspec(lua_State *L)
{
@@ -5278,24 +949,24 @@ static int l_get_modpath(lua_State *L)
static int l_get_modnames(lua_State *L)
{
// Get a list of mods
- core::list<std::string> mods_unsorted, mods_sorted;
+ std::list<std::string> mods_unsorted, mods_sorted;
get_server(L)->getModNames(mods_unsorted);
// Take unsorted items from mods_unsorted and sort them into
// mods_sorted; not great performance but the number of mods on a
// server will likely be small.
- for(core::list<std::string>::Iterator i = mods_unsorted.begin();
- i != mods_unsorted.end(); i++)
+ for(std::list<std::string>::iterator i = mods_unsorted.begin();
+ i != mods_unsorted.end(); ++i)
{
bool added = false;
- for(core::list<std::string>::Iterator x = mods_sorted.begin();
- x != mods_unsorted.end(); x++)
+ for(std::list<std::string>::iterator x = mods_sorted.begin();
+ x != mods_sorted.end(); ++x)
{
// I doubt anybody using Minetest will be using
// anything not ASCII based :)
if((*i).compare(*x) <= 0)
{
- mods_sorted.insert_before(x, *i);
+ mods_sorted.insert(x, *i);
added = true;
break;
}
@@ -5312,7 +983,7 @@ static int l_get_modnames(lua_State *L)
// Package them up for Lua
lua_newtable(L);
int new_table = lua_gettop(L);
- core::list<std::string>::Iterator i = mods_sorted.begin();
+ std::list<std::string>::iterator i = mods_sorted.begin();
while(i != mods_sorted.end())
{
lua_pushvalue(L, insertion_func);
@@ -5322,7 +993,7 @@ static int l_get_modnames(lua_State *L)
{
script_error(L, "error: %s", lua_tostring(L, -1));
}
- i++;
+ ++i;
}
return 1;
}
@@ -5383,102 +1054,6 @@ static int l_notify_authentication_modified(lua_State *L)
return 0;
}
-// get_craft_result(input)
-static int l_get_craft_result(lua_State *L)
-{
- int input_i = 1;
- std::string method_s = getstringfield_default(L, input_i, "method", "normal");
- enum CraftMethod method = (CraftMethod)getenumfield(L, input_i, "method",
- es_CraftMethod, CRAFT_METHOD_NORMAL);
- int width = 1;
- lua_getfield(L, input_i, "width");
- if(lua_isnumber(L, -1))
- width = luaL_checkinteger(L, -1);
- lua_pop(L, 1);
- lua_getfield(L, input_i, "items");
- std::vector<ItemStack> items = read_items(L, -1);
- lua_pop(L, 1); // items
-
- IGameDef *gdef = get_server(L);
- ICraftDefManager *cdef = gdef->cdef();
- CraftInput input(method, width, items);
- CraftOutput output;
- bool got = cdef->getCraftResult(input, output, true, gdef);
- lua_newtable(L); // output table
- if(got){
- ItemStack item;
- item.deSerialize(output.item, gdef->idef());
- LuaItemStack::create(L, item);
- lua_setfield(L, -2, "item");
- setintfield(L, -1, "time", output.time);
- } else {
- LuaItemStack::create(L, ItemStack());
- lua_setfield(L, -2, "item");
- setintfield(L, -1, "time", 0);
- }
- lua_newtable(L); // decremented input table
- lua_pushstring(L, method_s.c_str());
- lua_setfield(L, -2, "method");
- lua_pushinteger(L, width);
- lua_setfield(L, -2, "width");
- push_items(L, input.items);
- lua_setfield(L, -2, "items");
- return 2;
-}
-
-// get_craft_recipe(result item)
-static int l_get_craft_recipe(lua_State *L)
-{
- int k = 0;
- char tmp[20];
- int input_i = 1;
- std::string o_item = luaL_checkstring(L,input_i);
-
- IGameDef *gdef = get_server(L);
- ICraftDefManager *cdef = gdef->cdef();
- CraftInput input;
- CraftOutput output(o_item,0);
- bool got = cdef->getCraftRecipe(input, output, gdef);
- lua_newtable(L); // output table
- if(got){
- lua_newtable(L);
- for(std::vector<ItemStack>::const_iterator
- i = input.items.begin();
- i != input.items.end(); i++, k++)
- {
- if (i->empty())
- {
- continue;
- }
- sprintf(tmp,"%d",k);
- lua_pushstring(L,tmp);
- lua_pushstring(L,i->name.c_str());
- lua_settable(L, -3);
- }
- lua_setfield(L, -2, "items");
- setintfield(L, -1, "width", input.width);
- switch (input.method) {
- case CRAFT_METHOD_NORMAL:
- lua_pushstring(L,"normal");
- break;
- case CRAFT_METHOD_COOKING:
- lua_pushstring(L,"cooking");
- break;
- case CRAFT_METHOD_FUEL:
- lua_pushstring(L,"fuel");
- break;
- default:
- lua_pushstring(L,"unknown");
- }
- lua_setfield(L, -2, "type");
- } else {
- lua_pushnil(L);
- lua_setfield(L, -2, "items");
- setintfield(L, -1, "width", 0);
- }
- return 1;
-}
-
// rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
static int l_rollback_get_last_node_actor(lua_State *L)
{
@@ -5538,6 +1113,7 @@ static const struct luaL_Reg minetest_f [] = {
{"register_craft", l_register_craft},
{"register_biome", l_register_biome},
{"register_biome_groups", l_register_biome_groups},
+ {"register_ore", l_register_ore},
{"setting_set", l_setting_set},
{"setting_get", l_setting_get},
{"setting_getbool", l_setting_getbool},
@@ -5565,11 +1141,16 @@ static const struct luaL_Reg minetest_f [] = {
{"notify_authentication_modified", l_notify_authentication_modified},
{"get_craft_result", l_get_craft_result},
{"get_craft_recipe", l_get_craft_recipe},
+ {"get_all_craft_recipes", l_get_all_craft_recipes},
{"rollback_get_last_node_actor", l_rollback_get_last_node_actor},
{"rollback_revert_actions_by", l_rollback_revert_actions_by},
+ {"add_particle", l_add_particle},
+ {"add_particlespawner", l_add_particlespawner},
+ {"delete_particlespawner", l_delete_particlespawner},
{NULL, NULL}
};
+
/*
Main export function
*/
@@ -5610,1596 +1191,3 @@ void scriptapi_export(lua_State *L, Server *server)
LuaPerlinNoise::Register(L);
LuaPerlinNoiseMap::Register(L);
}
-
-bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
- const std::string &modname)
-{
- ModNameStorer modnamestorer(L, modname);
-
- if(!string_allowed(modname, "abcdefghijklmnopqrstuvwxyz"
- "0123456789_")){
- errorstream<<"Error loading mod \""<<modname
- <<"\": modname does not follow naming conventions: "
- <<"Only chararacters [a-z0-9_] are allowed."<<std::endl;
- return false;
- }
-
- bool success = false;
-
- try{
- success = script_load(L, scriptpath.c_str());
- }
- catch(LuaError &e){
- errorstream<<"Error loading mod \""<<modname
- <<"\": "<<e.what()<<std::endl;
- }
-
- return success;
-}
-
-void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- verbosestream<<"scriptapi_add_environment"<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Create EnvRef on stack
- EnvRef::create(L, env);
- int envref = lua_gettop(L);
-
- // minetest.env = envref
- lua_getglobal(L, "minetest");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushvalue(L, envref);
- lua_setfield(L, -2, "env");
-
- // Store environment as light userdata in registry
- lua_pushlightuserdata(L, env);
- lua_setfield(L, LUA_REGISTRYINDEX, "minetest_env");
-
- /*
- Add ActiveBlockModifiers to environment
- */
-
- // Get minetest.registered_abms
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_abms");
- luaL_checktype(L, -1, LUA_TTABLE);
- int registered_abms = lua_gettop(L);
-
- if(lua_istable(L, registered_abms)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- int id = lua_tonumber(L, -2);
- int current_abm = lua_gettop(L);
-
- std::set<std::string> trigger_contents;
- lua_getfield(L, current_abm, "nodenames");
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- trigger_contents.insert(lua_tostring(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- } else if(lua_isstring(L, -1)){
- trigger_contents.insert(lua_tostring(L, -1));
- }
- lua_pop(L, 1);
-
- std::set<std::string> required_neighbors;
- lua_getfield(L, current_abm, "neighbors");
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- required_neighbors.insert(lua_tostring(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- } else if(lua_isstring(L, -1)){
- required_neighbors.insert(lua_tostring(L, -1));
- }
- lua_pop(L, 1);
-
- float trigger_interval = 10.0;
- getfloatfield(L, current_abm, "interval", trigger_interval);
-
- int trigger_chance = 50;
- getintfield(L, current_abm, "chance", trigger_chance);
-
- LuaABM *abm = new LuaABM(L, id, trigger_contents,
- required_neighbors, trigger_interval, trigger_chance);
-
- env->addActiveBlockModifier(abm);
-
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- }
- lua_pop(L, 1);
-}
-
-#if 0
-// Dump stack top with the dump2 function
-static void dump2(lua_State *L, const char *name)
-{
- // Dump object (debug)
- lua_getglobal(L, "dump2");
- luaL_checktype(L, -1, LUA_TFUNCTION);
- lua_pushvalue(L, -2); // Get previous stack top as first parameter
- lua_pushstring(L, name);
- if(lua_pcall(L, 2, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-#endif
-
-/*
- object_reference
-*/
-
-void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Create object on stack
- ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
- int object = lua_gettop(L);
-
- // Get minetest.object_refs table
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "object_refs");
- luaL_checktype(L, -1, LUA_TTABLE);
- int objectstable = lua_gettop(L);
-
- // object_refs[id] = object
- lua_pushnumber(L, cobj->getId()); // Push id
- lua_pushvalue(L, object); // Copy object to top of stack
- lua_settable(L, objectstable);
-}
-
-void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.object_refs table
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "object_refs");
- luaL_checktype(L, -1, LUA_TTABLE);
- int objectstable = lua_gettop(L);
-
- // Get object_refs[id]
- lua_pushnumber(L, cobj->getId()); // Push id
- lua_gettable(L, objectstable);
- // Set object reference to NULL
- ObjectRef::set_null(L);
- lua_pop(L, 1); // pop object
-
- // Set object_refs[id] = nil
- lua_pushnumber(L, cobj->getId()); // Push id
- lua_pushnil(L);
- lua_settable(L, objectstable);
-}
-
-/*
- misc
-*/
-
-// What scriptapi_run_callbacks does with the return values of callbacks.
-// Regardless of the mode, if only one callback is defined,
-// its return value is the total return value.
-// Modes only affect the case where 0 or >= 2 callbacks are defined.
-enum RunCallbacksMode
-{
- // Returns the return value of the first callback
- // Returns nil if list of callbacks is empty
- RUN_CALLBACKS_MODE_FIRST,
- // Returns the return value of the last callback
- // Returns nil if list of callbacks is empty
- RUN_CALLBACKS_MODE_LAST,
- // If any callback returns a false value, the first such is returned
- // Otherwise, the first callback's return value (trueish) is returned
- // Returns true if list of callbacks is empty
- RUN_CALLBACKS_MODE_AND,
- // Like above, but stops calling callbacks (short circuit)
- // after seeing the first false value
- RUN_CALLBACKS_MODE_AND_SC,
- // If any callback returns a true value, the first such is returned
- // Otherwise, the first callback's return value (falseish) is returned
- // Returns false if list of callbacks is empty
- RUN_CALLBACKS_MODE_OR,
- // Like above, but stops calling callbacks (short circuit)
- // after seeing the first true value
- RUN_CALLBACKS_MODE_OR_SC,
- // Note: "a true value" and "a false value" refer to values that
- // are converted by lua_toboolean to true or false, respectively.
-};
-
-// Push the list of callbacks (a lua table).
-// Then push nargs arguments.
-// Then call this function, which
-// - runs the callbacks
-// - removes the table and arguments from the lua stack
-// - pushes the return value, computed depending on mode
-static void scriptapi_run_callbacks(lua_State *L, int nargs,
- RunCallbacksMode mode)
-{
- // Insert the return value into the lua stack, below the table
- assert(lua_gettop(L) >= nargs + 1);
- lua_pushnil(L);
- lua_insert(L, -(nargs + 1) - 1);
- // Stack now looks like this:
- // ... <return value = nil> <table> <arg#1> <arg#2> ... <arg#n>
-
- int rv = lua_gettop(L) - nargs - 1;
- int table = rv + 1;
- int arg = table + 1;
-
- luaL_checktype(L, table, LUA_TTABLE);
-
- // Foreach
- lua_pushnil(L);
- bool first_loop = true;
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- for(int i = 0; i < nargs; i++)
- lua_pushvalue(L, arg+i);
- if(lua_pcall(L, nargs, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-
- // Move return value to designated space in stack
- // Or pop it
- if(first_loop){
- // Result of first callback is always moved
- lua_replace(L, rv);
- first_loop = false;
- } else {
- // Otherwise, what happens depends on the mode
- if(mode == RUN_CALLBACKS_MODE_FIRST)
- lua_pop(L, 1);
- else if(mode == RUN_CALLBACKS_MODE_LAST)
- lua_replace(L, rv);
- else if(mode == RUN_CALLBACKS_MODE_AND ||
- mode == RUN_CALLBACKS_MODE_AND_SC){
- if((bool)lua_toboolean(L, rv) == true &&
- (bool)lua_toboolean(L, -1) == false)
- lua_replace(L, rv);
- else
- lua_pop(L, 1);
- }
- else if(mode == RUN_CALLBACKS_MODE_OR ||
- mode == RUN_CALLBACKS_MODE_OR_SC){
- if((bool)lua_toboolean(L, rv) == false &&
- (bool)lua_toboolean(L, -1) == true)
- lua_replace(L, rv);
- else
- lua_pop(L, 1);
- }
- else
- assert(0);
- }
-
- // Handle short circuit modes
- if(mode == RUN_CALLBACKS_MODE_AND_SC &&
- (bool)lua_toboolean(L, rv) == false)
- break;
- else if(mode == RUN_CALLBACKS_MODE_OR_SC &&
- (bool)lua_toboolean(L, rv) == true)
- break;
-
- // value removed, keep key for next iteration
- }
-
- // Remove stuff from stack, leaving only the return value
- lua_settop(L, rv);
-
- // Fix return value in case no callbacks were called
- if(first_loop){
- if(mode == RUN_CALLBACKS_MODE_AND ||
- mode == RUN_CALLBACKS_MODE_AND_SC){
- lua_pop(L, 1);
- lua_pushboolean(L, true);
- }
- else if(mode == RUN_CALLBACKS_MODE_OR ||
- mode == RUN_CALLBACKS_MODE_OR_SC){
- lua_pop(L, 1);
- lua_pushboolean(L, false);
- }
- }
-}
-
-bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
- const std::string &message)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_on_chat_messages
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_chat_messages");
- // Call callbacks
- lua_pushstring(L, name.c_str());
- lua_pushstring(L, message.c_str());
- scriptapi_run_callbacks(L, 2, RUN_CALLBACKS_MODE_OR_SC);
- bool ate = lua_toboolean(L, -1);
- return ate;
-}
-
-void scriptapi_on_shutdown(lua_State *L)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get registered shutdown hooks
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_shutdown");
- // Call callbacks
- scriptapi_run_callbacks(L, 0, RUN_CALLBACKS_MODE_FIRST);
-}
-
-void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_on_newplayers
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_newplayers");
- // Call callbacks
- objectref_get_or_create(L, player);
- scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
-}
-
-void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_on_dieplayers
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_dieplayers");
- // Call callbacks
- objectref_get_or_create(L, player);
- scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
-}
-
-bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_on_respawnplayers
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_respawnplayers");
- // Call callbacks
- objectref_get_or_create(L, player);
- scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_OR);
- bool positioning_handled_by_some = lua_toboolean(L, -1);
- return positioning_handled_by_some;
-}
-
-void scriptapi_on_joinplayer(lua_State *L, ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_on_joinplayers
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_joinplayers");
- // Call callbacks
- objectref_get_or_create(L, player);
- scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
-}
-
-void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_on_leaveplayers
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_leaveplayers");
- // Call callbacks
- objectref_get_or_create(L, player);
- scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
-}
-
-static void get_auth_handler(lua_State *L)
-{
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_auth_handler");
- if(lua_isnil(L, -1)){
- lua_pop(L, 1);
- lua_getfield(L, -1, "builtin_auth_handler");
- }
- if(lua_type(L, -1) != LUA_TTABLE)
- throw LuaError(L, "Authentication handler table not valid");
-}
-
-bool scriptapi_get_auth(lua_State *L, const std::string &playername,
- std::string *dst_password, std::set<std::string> *dst_privs)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- get_auth_handler(L);
- lua_getfield(L, -1, "get_auth");
- if(lua_type(L, -1) != LUA_TFUNCTION)
- throw LuaError(L, "Authentication handler missing get_auth");
- lua_pushstring(L, playername.c_str());
- if(lua_pcall(L, 1, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-
- // nil = login not allowed
- if(lua_isnil(L, -1))
- return false;
- luaL_checktype(L, -1, LUA_TTABLE);
-
- std::string password;
- bool found = getstringfield(L, -1, "password", password);
- if(!found)
- throw LuaError(L, "Authentication handler didn't return password");
- if(dst_password)
- *dst_password = password;
-
- lua_getfield(L, -1, "privileges");
- if(!lua_istable(L, -1))
- throw LuaError(L,
- "Authentication handler didn't return privilege table");
- if(dst_privs)
- read_privileges(L, -1, *dst_privs);
- lua_pop(L, 1);
-
- return true;
-}
-
-void scriptapi_create_auth(lua_State *L, const std::string &playername,
- const std::string &password)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- get_auth_handler(L);
- lua_getfield(L, -1, "create_auth");
- if(lua_type(L, -1) != LUA_TFUNCTION)
- throw LuaError(L, "Authentication handler missing create_auth");
- lua_pushstring(L, playername.c_str());
- lua_pushstring(L, password.c_str());
- if(lua_pcall(L, 2, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-bool scriptapi_set_password(lua_State *L, const std::string &playername,
- const std::string &password)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- get_auth_handler(L);
- lua_getfield(L, -1, "set_password");
- if(lua_type(L, -1) != LUA_TFUNCTION)
- throw LuaError(L, "Authentication handler missing set_password");
- lua_pushstring(L, playername.c_str());
- lua_pushstring(L, password.c_str());
- if(lua_pcall(L, 2, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- return lua_toboolean(L, -1);
-}
-
-/*
- player
-*/
-
-void scriptapi_on_player_receive_fields(lua_State *L,
- ServerActiveObject *player,
- const std::string &formname,
- const std::map<std::string, std::string> &fields)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_on_chat_messages
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_player_receive_fields");
- // Call callbacks
- // param 1
- objectref_get_or_create(L, player);
- // param 2
- lua_pushstring(L, formname.c_str());
- // param 3
- lua_newtable(L);
- for(std::map<std::string, std::string>::const_iterator
- i = fields.begin(); i != fields.end(); i++){
- const std::string &name = i->first;
- const std::string &value = i->second;
- lua_pushstring(L, name.c_str());
- lua_pushlstring(L, value.c_str(), value.size());
- lua_settable(L, -3);
- }
- scriptapi_run_callbacks(L, 3, RUN_CALLBACKS_MODE_OR_SC);
-}
-
-/*
- item callbacks and node callbacks
-*/
-
-// Retrieves minetest.registered_items[name][callbackname]
-// If that is nil or on error, return false and stack is unchanged
-// If that is a function, returns true and pushes the
-// function onto the stack
-// If minetest.registered_items[name] doesn't exist, minetest.nodedef_default
-// is tried instead so unknown items can still be manipulated to some degree
-static bool get_item_callback(lua_State *L,
- const char *name, const char *callbackname)
-{
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_items");
- lua_remove(L, -2);
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_getfield(L, -1, name);
- lua_remove(L, -2);
- // Should be a table
- if(lua_type(L, -1) != LUA_TTABLE)
- {
- // Report error and clean up
- errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
- lua_pop(L, 1);
-
- // Try minetest.nodedef_default instead
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "nodedef_default");
- lua_remove(L, -2);
- luaL_checktype(L, -1, LUA_TTABLE);
- }
- lua_getfield(L, -1, callbackname);
- lua_remove(L, -2);
- // Should be a function or nil
- if(lua_type(L, -1) == LUA_TFUNCTION)
- {
- return true;
- }
- else if(lua_isnil(L, -1))
- {
- lua_pop(L, 1);
- return false;
- }
- else
- {
- errorstream<<"Item \""<<name<<"\" callback \""
- <<callbackname<<" is not a function"<<std::endl;
- lua_pop(L, 1);
- return false;
- }
-}
-
-bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
- ServerActiveObject *dropper, v3f pos)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Push callback function on stack
- if(!get_item_callback(L, item.name.c_str(), "on_drop"))
- return false;
-
- // Call function
- LuaItemStack::create(L, item);
- objectref_get_or_create(L, dropper);
- pushFloatPos(L, pos);
- if(lua_pcall(L, 3, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if(!lua_isnil(L, -1))
- item = read_item(L, -1);
- return true;
-}
-
-bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
- ServerActiveObject *placer, const PointedThing &pointed)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Push callback function on stack
- if(!get_item_callback(L, item.name.c_str(), "on_place"))
- return false;
-
- // Call function
- LuaItemStack::create(L, item);
- objectref_get_or_create(L, placer);
- push_pointed_thing(L, pointed);
- if(lua_pcall(L, 3, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if(!lua_isnil(L, -1))
- item = read_item(L, -1);
- return true;
-}
-
-bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
- ServerActiveObject *user, const PointedThing &pointed)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Push callback function on stack
- if(!get_item_callback(L, item.name.c_str(), "on_use"))
- return false;
-
- // Call function
- LuaItemStack::create(L, item);
- objectref_get_or_create(L, user);
- push_pointed_thing(L, pointed);
- if(lua_pcall(L, 3, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if(!lua_isnil(L, -1))
- item = read_item(L, -1);
- return true;
-}
-
-bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node,
- ServerActiveObject *puncher)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_punch"))
- return false;
-
- // Call function
- push_v3s16(L, p);
- pushnode(L, node, ndef);
- objectref_get_or_create(L, puncher);
- if(lua_pcall(L, 3, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- return true;
-}
-
-bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
- ServerActiveObject *digger)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_dig"))
- return false;
-
- // Call function
- push_v3s16(L, p);
- pushnode(L, node, ndef);
- objectref_get_or_create(L, digger);
- if(lua_pcall(L, 3, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- return true;
-}
-
-void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_construct"))
- return;
-
- // Call function
- push_v3s16(L, p);
- if(lua_pcall(L, 1, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_destruct"))
- return;
-
- // Call function
- push_v3s16(L, p);
- if(lua_pcall(L, 1, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-void scriptapi_node_after_destruct(lua_State *L, v3s16 p, MapNode node)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(), "after_destruct"))
- return;
-
- // Call function
- push_v3s16(L, p);
- pushnode(L, node, ndef);
- if(lua_pcall(L, 2, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-bool scriptapi_node_on_timer(lua_State *L, v3s16 p, MapNode node, f32 dtime)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_timer"))
- return false;
-
- // Call function
- push_v3s16(L, p);
- lua_pushnumber(L,dtime);
- if(lua_pcall(L, 2, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if((bool)lua_isboolean(L,-1) && (bool)lua_toboolean(L,-1) == true)
- return true;
-
- return false;
-}
-
-void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
- const std::string &formname,
- const std::map<std::string, std::string> &fields,
- ServerActiveObject *sender)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // If node doesn't exist, we don't know what callback to call
- MapNode node = get_env(L)->getMap().getNodeNoEx(p);
- if(node.getContent() == CONTENT_IGNORE)
- return;
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_receive_fields"))
- return;
-
- // Call function
- // param 1
- push_v3s16(L, p);
- // param 2
- lua_pushstring(L, formname.c_str());
- // param 3
- lua_newtable(L);
- for(std::map<std::string, std::string>::const_iterator
- i = fields.begin(); i != fields.end(); i++){
- const std::string &name = i->first;
- const std::string &value = i->second;
- lua_pushstring(L, name.c_str());
- lua_pushlstring(L, value.c_str(), value.size());
- lua_settable(L, -3);
- }
- // param 4
- objectref_get_or_create(L, sender);
- if(lua_pcall(L, 4, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-/*
- Node metadata inventory callbacks
-*/
-
-// Return number of accepted items to be moved
-int scriptapi_nodemeta_inventory_allow_move(lua_State *L, v3s16 p,
- const std::string &from_list, int from_index,
- const std::string &to_list, int to_index,
- int count, ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // If node doesn't exist, we don't know what callback to call
- MapNode node = get_env(L)->getMap().getNodeNoEx(p);
- if(node.getContent() == CONTENT_IGNORE)
- return 0;
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(),
- "allow_metadata_inventory_move"))
- return count;
-
- // function(pos, from_list, from_index, to_list, to_index, count, player)
- // pos
- push_v3s16(L, p);
- // from_list
- lua_pushstring(L, from_list.c_str());
- // from_index
- lua_pushinteger(L, from_index + 1);
- // to_list
- lua_pushstring(L, to_list.c_str());
- // to_index
- lua_pushinteger(L, to_index + 1);
- // count
- lua_pushinteger(L, count);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 7, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if(!lua_isnumber(L, -1))
- throw LuaError(L, "allow_metadata_inventory_move should return a number");
- return luaL_checkinteger(L, -1);
-}
-
-// Return number of accepted items to be put
-int scriptapi_nodemeta_inventory_allow_put(lua_State *L, v3s16 p,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // If node doesn't exist, we don't know what callback to call
- MapNode node = get_env(L)->getMap().getNodeNoEx(p);
- if(node.getContent() == CONTENT_IGNORE)
- return 0;
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(),
- "allow_metadata_inventory_put"))
- return stack.count;
-
- // Call function(pos, listname, index, stack, player)
- // pos
- push_v3s16(L, p);
- // listname
- lua_pushstring(L, listname.c_str());
- // index
- lua_pushinteger(L, index + 1);
- // stack
- LuaItemStack::create(L, stack);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 5, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if(!lua_isnumber(L, -1))
- throw LuaError(L, "allow_metadata_inventory_put should return a number");
- return luaL_checkinteger(L, -1);
-}
-
-// Return number of accepted items to be taken
-int scriptapi_nodemeta_inventory_allow_take(lua_State *L, v3s16 p,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // If node doesn't exist, we don't know what callback to call
- MapNode node = get_env(L)->getMap().getNodeNoEx(p);
- if(node.getContent() == CONTENT_IGNORE)
- return 0;
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(),
- "allow_metadata_inventory_take"))
- return stack.count;
-
- // Call function(pos, listname, index, count, player)
- // pos
- push_v3s16(L, p);
- // listname
- lua_pushstring(L, listname.c_str());
- // index
- lua_pushinteger(L, index + 1);
- // stack
- LuaItemStack::create(L, stack);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 5, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if(!lua_isnumber(L, -1))
- throw LuaError(L, "allow_metadata_inventory_take should return a number");
- return luaL_checkinteger(L, -1);
-}
-
-// Report moved items
-void scriptapi_nodemeta_inventory_on_move(lua_State *L, v3s16 p,
- const std::string &from_list, int from_index,
- const std::string &to_list, int to_index,
- int count, ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // If node doesn't exist, we don't know what callback to call
- MapNode node = get_env(L)->getMap().getNodeNoEx(p);
- if(node.getContent() == CONTENT_IGNORE)
- return;
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(),
- "on_metadata_inventory_move"))
- return;
-
- // function(pos, from_list, from_index, to_list, to_index, count, player)
- // pos
- push_v3s16(L, p);
- // from_list
- lua_pushstring(L, from_list.c_str());
- // from_index
- lua_pushinteger(L, from_index + 1);
- // to_list
- lua_pushstring(L, to_list.c_str());
- // to_index
- lua_pushinteger(L, to_index + 1);
- // count
- lua_pushinteger(L, count);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 7, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-// Report put items
-void scriptapi_nodemeta_inventory_on_put(lua_State *L, v3s16 p,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // If node doesn't exist, we don't know what callback to call
- MapNode node = get_env(L)->getMap().getNodeNoEx(p);
- if(node.getContent() == CONTENT_IGNORE)
- return;
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(),
- "on_metadata_inventory_put"))
- return;
-
- // Call function(pos, listname, index, stack, player)
- // pos
- push_v3s16(L, p);
- // listname
- lua_pushstring(L, listname.c_str());
- // index
- lua_pushinteger(L, index + 1);
- // stack
- LuaItemStack::create(L, stack);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 5, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-// Report taken items
-void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- INodeDefManager *ndef = get_server(L)->ndef();
-
- // If node doesn't exist, we don't know what callback to call
- MapNode node = get_env(L)->getMap().getNodeNoEx(p);
- if(node.getContent() == CONTENT_IGNORE)
- return;
-
- // Push callback function on stack
- if(!get_item_callback(L, ndef->get(node).name.c_str(),
- "on_metadata_inventory_take"))
- return;
-
- // Call function(pos, listname, index, stack, player)
- // pos
- push_v3s16(L, p);
- // listname
- lua_pushstring(L, listname.c_str());
- // index
- lua_pushinteger(L, index + 1);
- // stack
- LuaItemStack::create(L, stack);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 5, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-/*
- Detached inventory callbacks
-*/
-
-// Retrieves minetest.detached_inventories[name][callbackname]
-// If that is nil or on error, return false and stack is unchanged
-// If that is a function, returns true and pushes the
-// function onto the stack
-static bool get_detached_inventory_callback(lua_State *L,
- const std::string &name, const char *callbackname)
-{
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "detached_inventories");
- lua_remove(L, -2);
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_getfield(L, -1, name.c_str());
- lua_remove(L, -2);
- // Should be a table
- if(lua_type(L, -1) != LUA_TTABLE)
- {
- errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
- lua_pop(L, 1);
- return false;
- }
- lua_getfield(L, -1, callbackname);
- lua_remove(L, -2);
- // Should be a function or nil
- if(lua_type(L, -1) == LUA_TFUNCTION)
- {
- return true;
- }
- else if(lua_isnil(L, -1))
- {
- lua_pop(L, 1);
- return false;
- }
- else
- {
- errorstream<<"Detached inventory \""<<name<<"\" callback \""
- <<callbackname<<"\" is not a function"<<std::endl;
- lua_pop(L, 1);
- return false;
- }
-}
-
-// Return number of accepted items to be moved
-int scriptapi_detached_inventory_allow_move(lua_State *L,
- const std::string &name,
- const std::string &from_list, int from_index,
- const std::string &to_list, int to_index,
- int count, ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Push callback function on stack
- if(!get_detached_inventory_callback(L, name, "allow_move"))
- return count;
-
- // function(inv, from_list, from_index, to_list, to_index, count, player)
- // inv
- InventoryLocation loc;
- loc.setDetached(name);
- InvRef::create(L, loc);
- // from_list
- lua_pushstring(L, from_list.c_str());
- // from_index
- lua_pushinteger(L, from_index + 1);
- // to_list
- lua_pushstring(L, to_list.c_str());
- // to_index
- lua_pushinteger(L, to_index + 1);
- // count
- lua_pushinteger(L, count);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 7, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if(!lua_isnumber(L, -1))
- throw LuaError(L, "allow_move should return a number");
- return luaL_checkinteger(L, -1);
-}
-
-// Return number of accepted items to be put
-int scriptapi_detached_inventory_allow_put(lua_State *L,
- const std::string &name,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Push callback function on stack
- if(!get_detached_inventory_callback(L, name, "allow_put"))
- return stack.count; // All will be accepted
-
- // Call function(inv, listname, index, stack, player)
- // inv
- InventoryLocation loc;
- loc.setDetached(name);
- InvRef::create(L, loc);
- // listname
- lua_pushstring(L, listname.c_str());
- // index
- lua_pushinteger(L, index + 1);
- // stack
- LuaItemStack::create(L, stack);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 5, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if(!lua_isnumber(L, -1))
- throw LuaError(L, "allow_put should return a number");
- return luaL_checkinteger(L, -1);
-}
-
-// Return number of accepted items to be taken
-int scriptapi_detached_inventory_allow_take(lua_State *L,
- const std::string &name,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Push callback function on stack
- if(!get_detached_inventory_callback(L, name, "allow_take"))
- return stack.count; // All will be accepted
-
- // Call function(inv, listname, index, stack, player)
- // inv
- InventoryLocation loc;
- loc.setDetached(name);
- InvRef::create(L, loc);
- // listname
- lua_pushstring(L, listname.c_str());
- // index
- lua_pushinteger(L, index + 1);
- // stack
- LuaItemStack::create(L, stack);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 5, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- if(!lua_isnumber(L, -1))
- throw LuaError(L, "allow_take should return a number");
- return luaL_checkinteger(L, -1);
-}
-
-// Report moved items
-void scriptapi_detached_inventory_on_move(lua_State *L,
- const std::string &name,
- const std::string &from_list, int from_index,
- const std::string &to_list, int to_index,
- int count, ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Push callback function on stack
- if(!get_detached_inventory_callback(L, name, "on_move"))
- return;
-
- // function(inv, from_list, from_index, to_list, to_index, count, player)
- // inv
- InventoryLocation loc;
- loc.setDetached(name);
- InvRef::create(L, loc);
- // from_list
- lua_pushstring(L, from_list.c_str());
- // from_index
- lua_pushinteger(L, from_index + 1);
- // to_list
- lua_pushstring(L, to_list.c_str());
- // to_index
- lua_pushinteger(L, to_index + 1);
- // count
- lua_pushinteger(L, count);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 7, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-// Report put items
-void scriptapi_detached_inventory_on_put(lua_State *L,
- const std::string &name,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Push callback function on stack
- if(!get_detached_inventory_callback(L, name, "on_put"))
- return;
-
- // Call function(inv, listname, index, stack, player)
- // inv
- InventoryLocation loc;
- loc.setDetached(name);
- InvRef::create(L, loc);
- // listname
- lua_pushstring(L, listname.c_str());
- // index
- lua_pushinteger(L, index + 1);
- // stack
- LuaItemStack::create(L, stack);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 5, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-// Report taken items
-void scriptapi_detached_inventory_on_take(lua_State *L,
- const std::string &name,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- StackUnroller stack_unroller(L);
-
- // Push callback function on stack
- if(!get_detached_inventory_callback(L, name, "on_take"))
- return;
-
- // Call function(inv, listname, index, stack, player)
- // inv
- InventoryLocation loc;
- loc.setDetached(name);
- InvRef::create(L, loc);
- // listname
- lua_pushstring(L, listname.c_str());
- // index
- lua_pushinteger(L, index + 1);
- // stack
- LuaItemStack::create(L, stack);
- // player
- objectref_get_or_create(L, player);
- if(lua_pcall(L, 5, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
-}
-
-/*
- environment
-*/
-
-void scriptapi_environment_step(lua_State *L, float dtime)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_step"<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_globalsteps
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_globalsteps");
- // Call callbacks
- lua_pushnumber(L, dtime);
- scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
-}
-
-void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
- u32 blockseed)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_on_generated"<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_on_generateds
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_generateds");
- // Call callbacks
- push_v3s16(L, minp);
- push_v3s16(L, maxp);
- lua_pushnumber(L, blockseed);
- scriptapi_run_callbacks(L, 3, RUN_CALLBACKS_MODE_FIRST);
-}
-
-/*
- luaentity
-*/
-
-bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- verbosestream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
- <<name<<"\""<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.registered_entities[name]
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_entities");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushstring(L, name);
- lua_gettable(L, -2);
- // Should be a table, which we will use as a prototype
- //luaL_checktype(L, -1, LUA_TTABLE);
- if(lua_type(L, -1) != LUA_TTABLE){
- errorstream<<"LuaEntity name \""<<name<<"\" not defined"<<std::endl;
- return false;
- }
- int prototype_table = lua_gettop(L);
- //dump2(L, "prototype_table");
-
- // Create entity object
- lua_newtable(L);
- int object = lua_gettop(L);
-
- // Set object metatable
- lua_pushvalue(L, prototype_table);
- lua_setmetatable(L, -2);
-
- // Add object reference
- // This should be userdata with metatable ObjectRef
- objectref_get(L, id);
- luaL_checktype(L, -1, LUA_TUSERDATA);
- if(!luaL_checkudata(L, -1, "ObjectRef"))
- luaL_typerror(L, -1, "ObjectRef");
- lua_setfield(L, -2, "object");
-
- // minetest.luaentities[id] = object
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "luaentities");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushnumber(L, id); // Push id
- lua_pushvalue(L, object); // Copy object to top of stack
- lua_settable(L, -3);
-
- return true;
-}
-
-void scriptapi_luaentity_activate(lua_State *L, u16 id,
- const std::string &staticdata, u32 dtime_s)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- verbosestream<<"scriptapi_luaentity_activate: id="<<id<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.luaentities[id]
- luaentity_get(L, id);
- int object = lua_gettop(L);
-
- // Get on_activate function
- lua_pushvalue(L, object);
- lua_getfield(L, -1, "on_activate");
- if(!lua_isnil(L, -1)){
- luaL_checktype(L, -1, LUA_TFUNCTION);
- lua_pushvalue(L, object); // self
- lua_pushlstring(L, staticdata.c_str(), staticdata.size());
- lua_pushinteger(L, dtime_s);
- // Call with 3 arguments, 0 results
- if(lua_pcall(L, 3, 0, 0))
- script_error(L, "error running function on_activate: %s\n",
- lua_tostring(L, -1));
- }
-}
-
-void scriptapi_luaentity_rm(lua_State *L, u16 id)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- verbosestream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
-
- // Get minetest.luaentities table
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "luaentities");
- luaL_checktype(L, -1, LUA_TTABLE);
- int objectstable = lua_gettop(L);
-
- // Set luaentities[id] = nil
- lua_pushnumber(L, id); // Push id
- lua_pushnil(L);
- lua_settable(L, objectstable);
-
- lua_pop(L, 2); // pop luaentities, minetest
-}
-
-std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.luaentities[id]
- luaentity_get(L, id);
- int object = lua_gettop(L);
-
- // Get get_staticdata function
- lua_pushvalue(L, object);
- lua_getfield(L, -1, "get_staticdata");
- if(lua_isnil(L, -1))
- return "";
-
- luaL_checktype(L, -1, LUA_TFUNCTION);
- lua_pushvalue(L, object); // self
- // Call with 1 arguments, 1 results
- if(lua_pcall(L, 1, 1, 0))
- script_error(L, "error running function get_staticdata: %s\n",
- lua_tostring(L, -1));
-
- size_t len=0;
- const char *s = lua_tolstring(L, -1, &len);
- return std::string(s, len);
-}
-
-void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
- ObjectProperties *prop)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.luaentities[id]
- luaentity_get(L, id);
- //int object = lua_gettop(L);
-
- // Set default values that differ from ObjectProperties defaults
- prop->hp_max = 10;
-
- /* Read stuff */
-
- prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
-
- getboolfield(L, -1, "physical", prop->physical);
-
- getfloatfield(L, -1, "weight", prop->weight);
-
- lua_getfield(L, -1, "collisionbox");
- if(lua_istable(L, -1))
- prop->collisionbox = read_aabb3f(L, -1, 1.0);
- lua_pop(L, 1);
-
- getstringfield(L, -1, "visual", prop->visual);
-
- getstringfield(L, -1, "mesh", prop->mesh);
-
- // Deprecated: read object properties directly
- read_object_properties(L, -1, prop);
-
- // Read initial_properties
- lua_getfield(L, -1, "initial_properties");
- read_object_properties(L, -1, prop);
- lua_pop(L, 1);
-}
-
-void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.luaentities[id]
- luaentity_get(L, id);
- int object = lua_gettop(L);
- // State: object is at top of stack
- // Get step function
- lua_getfield(L, -1, "on_step");
- if(lua_isnil(L, -1))
- return;
- luaL_checktype(L, -1, LUA_TFUNCTION);
- lua_pushvalue(L, object); // self
- lua_pushnumber(L, dtime); // dtime
- // Call with 2 arguments, 0 results
- if(lua_pcall(L, 2, 0, 0))
- script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1));
-}
-
-// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
-// tool_capabilities, direction)
-void scriptapi_luaentity_punch(lua_State *L, u16 id,
- ServerActiveObject *puncher, float time_from_last_punch,
- const ToolCapabilities *toolcap, v3f dir)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.luaentities[id]
- luaentity_get(L, id);
- int object = lua_gettop(L);
- // State: object is at top of stack
- // Get function
- lua_getfield(L, -1, "on_punch");
- if(lua_isnil(L, -1))
- return;
- luaL_checktype(L, -1, LUA_TFUNCTION);
- lua_pushvalue(L, object); // self
- objectref_get_or_create(L, puncher); // Clicker reference
- lua_pushnumber(L, time_from_last_punch);
- push_tool_capabilities(L, *toolcap);
- push_v3f(L, dir);
- // Call with 5 arguments, 0 results
- if(lua_pcall(L, 5, 0, 0))
- script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
-}
-
-// Calls entity:on_rightclick(ObjectRef clicker)
-void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
- ServerActiveObject *clicker)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
- StackUnroller stack_unroller(L);
-
- // Get minetest.luaentities[id]
- luaentity_get(L, id);
- int object = lua_gettop(L);
- // State: object is at top of stack
- // Get function
- lua_getfield(L, -1, "on_rightclick");
- if(lua_isnil(L, -1))
- return;
- luaL_checktype(L, -1, LUA_TFUNCTION);
- lua_pushvalue(L, object); // self
- objectref_get_or_create(L, clicker); // Clicker reference
- // Call with 2 arguments, 0 results
- if(lua_pcall(L, 2, 0, 0))
- script_error(L, "error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
-}
-
diff --git a/src/scriptapi.h b/src/scriptapi.h
index e94ca781f..7f19bcef5 100644
--- a/src/scriptapi.h
+++ b/src/scriptapi.h
@@ -20,41 +20,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef SCRIPTAPI_HEADER
#define SCRIPTAPI_HEADER
-#include "irrlichttypes_bloated.h"
#include <string>
-#include "mapnode.h"
#include <set>
#include <map>
+#include "irr_v3d.h"
+#include "irr_v2d.h"
+
+extern "C" {
+#include <lua.h>
+}
+#include "scriptapi_inventory.h"
+#include "scriptapi_nodemeta.h"
+#include "scriptapi_entity.h"
+#include "scriptapi_object.h"
+#include "scriptapi_env.h"
+#include "scriptapi_item.h"
+#include "scriptapi_node.h"
+
+#define luamethod(class, name) {#name, class::l_##name}
class Server;
-class ServerEnvironment;
-class ServerActiveObject;
-typedef struct lua_State lua_State;
-struct ObjectProperties;
-struct ItemStack;
-struct PointedThing;
-//class IGameDef;
-struct ToolCapabilities;
void scriptapi_export(lua_State *L, Server *server);
bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
const std::string &modname);
-void scriptapi_add_environment(lua_State *L, ServerEnvironment *env);
-
-void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj);
-void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj);
// Returns true if script handled message
bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
const std::string &message);
-/* environment */
-// On environment step
-void scriptapi_environment_step(lua_State *L, float dtime);
-// After generating a piece of map
-void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
- u32 blockseed);
-
/* server */
void scriptapi_on_shutdown(lua_State *L);
@@ -77,110 +71,5 @@ void scriptapi_on_player_receive_fields(lua_State *L,
const std::string &formname,
const std::map<std::string, std::string> &fields);
-/* item callbacks */
-bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
- ServerActiveObject *dropper, v3f pos);
-bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
- ServerActiveObject *placer, const PointedThing &pointed);
-bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
- ServerActiveObject *user, const PointedThing &pointed);
-
-/* node callbacks */
-bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node,
- ServerActiveObject *puncher);
-bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
- ServerActiveObject *digger);
-// Node constructor
-void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node);
-// Node destructor
-void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node);
-// Node post-destructor
-void scriptapi_node_after_destruct(lua_State *L, v3s16 p, MapNode node);
-// Node Timer event
-bool scriptapi_node_on_timer(lua_State *L, v3s16 p, MapNode node, f32 dtime);
-// Called when a metadata form returns values
-void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
- const std::string &formname,
- const std::map<std::string, std::string> &fields,
- ServerActiveObject *sender);
-
-/* Node metadata inventory callbacks */
-// Return number of accepted items to be moved
-int scriptapi_nodemeta_inventory_allow_move(lua_State *L, v3s16 p,
- const std::string &from_list, int from_index,
- const std::string &to_list, int to_index,
- int count, ServerActiveObject *player);
-// Return number of accepted items to be put
-int scriptapi_nodemeta_inventory_allow_put(lua_State *L, v3s16 p,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player);
-// Return number of accepted items to be taken
-int scriptapi_nodemeta_inventory_allow_take(lua_State *L, v3s16 p,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player);
-// Report moved items
-void scriptapi_nodemeta_inventory_on_move(lua_State *L, v3s16 p,
- const std::string &from_list, int from_index,
- const std::string &to_list, int to_index,
- int count, ServerActiveObject *player);
-// Report put items
-void scriptapi_nodemeta_inventory_on_put(lua_State *L, v3s16 p,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player);
-// Report taken items
-void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player);
-
-/* Detached inventory callbacks */
-// Return number of accepted items to be moved
-int scriptapi_detached_inventory_allow_move(lua_State *L,
- const std::string &name,
- const std::string &from_list, int from_index,
- const std::string &to_list, int to_index,
- int count, ServerActiveObject *player);
-// Return number of accepted items to be put
-int scriptapi_detached_inventory_allow_put(lua_State *L,
- const std::string &name,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player);
-// Return number of accepted items to be taken
-int scriptapi_detached_inventory_allow_take(lua_State *L,
- const std::string &name,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player);
-// Report moved items
-void scriptapi_detached_inventory_on_move(lua_State *L,
- const std::string &name,
- const std::string &from_list, int from_index,
- const std::string &to_list, int to_index,
- int count, ServerActiveObject *player);
-// Report put items
-void scriptapi_detached_inventory_on_put(lua_State *L,
- const std::string &name,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player);
-// Report taken items
-void scriptapi_detached_inventory_on_take(lua_State *L,
- const std::string &name,
- const std::string &listname, int index, ItemStack &stack,
- ServerActiveObject *player);
-
-/* luaentity */
-// Returns true if succesfully added into Lua; false otherwise.
-bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name);
-void scriptapi_luaentity_activate(lua_State *L, u16 id,
- const std::string &staticdata, u32 dtime_s);
-void scriptapi_luaentity_rm(lua_State *L, u16 id);
-std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id);
-void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
- ObjectProperties *prop);
-void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime);
-void scriptapi_luaentity_punch(lua_State *L, u16 id,
- ServerActiveObject *puncher, float time_from_last_punch,
- const ToolCapabilities *toolcap, v3f dir);
-void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
- ServerActiveObject *clicker);
-
#endif
diff --git a/src/scriptapi_common.cpp b/src/scriptapi_common.cpp
new file mode 100644
index 000000000..2d6f6c72b
--- /dev/null
+++ b/src/scriptapi_common.cpp
@@ -0,0 +1,311 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_common.h"
+
+extern "C" {
+#include "lauxlib.h"
+}
+
+#include "script.h"
+#include "scriptapi_types.h"
+#include "scriptapi_object.h"
+
+
+Server* get_server(lua_State *L)
+{
+ // Get server from registry
+ lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
+ Server *server = (Server*)lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ return server;
+}
+
+ServerEnvironment* get_env(lua_State *L)
+{
+ // Get environment from registry
+ lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
+ ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ return env;
+}
+
+void warn_if_field_exists(lua_State *L, int table,
+ const char *fieldname, const std::string &message)
+{
+ lua_getfield(L, table, fieldname);
+ if(!lua_isnil(L, -1)){
+ infostream<<script_get_backtrace(L)<<std::endl;
+ infostream<<"WARNING: field \""<<fieldname<<"\": "
+ <<message<<std::endl;
+ }
+ lua_pop(L, 1);
+}
+
+/*
+ ToolCapabilities
+*/
+
+ToolCapabilities read_tool_capabilities(
+ lua_State *L, int table)
+{
+ ToolCapabilities toolcap;
+ getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
+ getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
+ lua_getfield(L, table, "groupcaps");
+ if(lua_istable(L, -1)){
+ int table_groupcaps = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table_groupcaps) != 0){
+ // key at index -2 and value at index -1
+ std::string groupname = luaL_checkstring(L, -2);
+ if(lua_istable(L, -1)){
+ int table_groupcap = lua_gettop(L);
+ // This will be created
+ ToolGroupCap groupcap;
+ // Read simple parameters
+ getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
+ getintfield(L, table_groupcap, "uses", groupcap.uses);
+ // DEPRECATED: maxwear
+ float maxwear = 0;
+ if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
+ if(maxwear != 0)
+ groupcap.uses = 1.0/maxwear;
+ else
+ groupcap.uses = 0;
+ infostream<<script_get_backtrace(L)<<std::endl;
+ infostream<<"WARNING: field \"maxwear\" is deprecated; "
+ <<"should replace with uses=1/maxwear"<<std::endl;
+ }
+ // Read "times" table
+ lua_getfield(L, table_groupcap, "times");
+ if(lua_istable(L, -1)){
+ int table_times = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table_times) != 0){
+ // key at index -2 and value at index -1
+ int rating = luaL_checkinteger(L, -2);
+ float time = luaL_checknumber(L, -1);
+ groupcap.times[rating] = time;
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+ // Insert groupcap into toolcap
+ toolcap.groupcaps[groupname] = groupcap;
+ }
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, table, "damage_groups");
+ if(lua_istable(L, -1)){
+ int table_damage_groups = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table_damage_groups) != 0){
+ // key at index -2 and value at index -1
+ std::string groupname = luaL_checkstring(L, -2);
+ u16 value = luaL_checkinteger(L, -1);
+ toolcap.damageGroups[groupname] = value;
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+ return toolcap;
+}
+
+void set_tool_capabilities(lua_State *L, int table,
+ const ToolCapabilities &toolcap)
+{
+ setfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
+ setintfield(L, table, "max_drop_level", toolcap.max_drop_level);
+ // Create groupcaps table
+ lua_newtable(L);
+ // For each groupcap
+ for(std::map<std::string, ToolGroupCap>::const_iterator
+ i = toolcap.groupcaps.begin(); i != toolcap.groupcaps.end(); i++){
+ // Create groupcap table
+ lua_newtable(L);
+ const std::string &name = i->first;
+ const ToolGroupCap &groupcap = i->second;
+ // Create subtable "times"
+ lua_newtable(L);
+ for(std::map<int, float>::const_iterator
+ i = groupcap.times.begin(); i != groupcap.times.end(); i++){
+ int rating = i->first;
+ float time = i->second;
+ lua_pushinteger(L, rating);
+ lua_pushnumber(L, time);
+ lua_settable(L, -3);
+ }
+ // Set subtable "times"
+ lua_setfield(L, -2, "times");
+ // Set simple parameters
+ setintfield(L, -1, "maxlevel", groupcap.maxlevel);
+ setintfield(L, -1, "uses", groupcap.uses);
+ // Insert groupcap table into groupcaps table
+ lua_setfield(L, -2, name.c_str());
+ }
+ // Set groupcaps table
+ lua_setfield(L, -2, "groupcaps");
+ //Create damage_groups table
+ lua_newtable(L);
+ // For each damage group
+ for(std::map<std::string, s16>::const_iterator
+ i = toolcap.damageGroups.begin(); i != toolcap.damageGroups.end(); i++){
+ // Create damage group table
+ lua_pushinteger(L, i->second);
+ lua_setfield(L, -2, i->first.c_str());
+ }
+ lua_setfield(L, -2, "damage_groups");
+}
+
+void push_tool_capabilities(lua_State *L,
+ const ToolCapabilities &prop)
+{
+ lua_newtable(L);
+ set_tool_capabilities(L, -1, prop);
+}
+
+void realitycheck(lua_State *L)
+{
+ int top = lua_gettop(L);
+ if(top >= 30){
+ dstream<<"Stack is over 30:"<<std::endl;
+ stackDump(L, dstream);
+ script_error(L, "Stack is over 30 (reality check)");
+ }
+}
+
+/*
+ PointedThing
+*/
+
+void push_pointed_thing(lua_State *L, const PointedThing& pointed)
+{
+ lua_newtable(L);
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ lua_pushstring(L, "node");
+ lua_setfield(L, -2, "type");
+ push_v3s16(L, pointed.node_undersurface);
+ lua_setfield(L, -2, "under");
+ push_v3s16(L, pointed.node_abovesurface);
+ lua_setfield(L, -2, "above");
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ lua_pushstring(L, "object");
+ lua_setfield(L, -2, "type");
+ objectref_get(L, pointed.object_id);
+ lua_setfield(L, -2, "ref");
+ }
+ else
+ {
+ lua_pushstring(L, "nothing");
+ lua_setfield(L, -2, "type");
+ }
+}
+
+void stackDump(lua_State *L, std::ostream &o)
+{
+ int i;
+ int top = lua_gettop(L);
+ for (i = 1; i <= top; i++) { /* repeat for each level */
+ int t = lua_type(L, i);
+ switch (t) {
+
+ case LUA_TSTRING: /* strings */
+ o<<"\""<<lua_tostring(L, i)<<"\"";
+ break;
+
+ case LUA_TBOOLEAN: /* booleans */
+ o<<(lua_toboolean(L, i) ? "true" : "false");
+ break;
+
+ case LUA_TNUMBER: /* numbers */ {
+ char buf[10];
+ snprintf(buf, 10, "%g", lua_tonumber(L, i));
+ o<<buf;
+ break; }
+
+ default: /* other values */
+ o<<lua_typename(L, t);
+ break;
+
+ }
+ o<<" ";
+ }
+ o<<std::endl;
+}
+
+#if 0
+// Dump stack top with the dump2 function
+static void dump2(lua_State *L, const char *name)
+{
+ // Dump object (debug)
+ lua_getglobal(L, "dump2");
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, -2); // Get previous stack top as first parameter
+ lua_pushstring(L, name);
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+#endif
+
+bool string_to_enum(const EnumString *spec, int &result,
+ const std::string &str)
+{
+ const EnumString *esp = spec;
+ while(esp->str){
+ if(str == std::string(esp->str)){
+ result = esp->num;
+ return true;
+ }
+ esp++;
+ }
+ return false;
+}
+
+/*bool enum_to_string(const EnumString *spec, std::string &result,
+ int num)
+{
+ const EnumString *esp = spec;
+ while(esp){
+ if(num == esp->num){
+ result = esp->str;
+ return true;
+ }
+ esp++;
+ }
+ return false;
+}*/
+
+int getenumfield(lua_State *L, int table,
+ const char *fieldname, const EnumString *spec, int default_)
+{
+ int result = default_;
+ string_to_enum(spec, result,
+ getstringfield_default(L, table, fieldname, ""));
+ return result;
+}
diff --git a/src/scriptapi_common.h b/src/scriptapi_common.h
new file mode 100644
index 000000000..d029b48d3
--- /dev/null
+++ b/src/scriptapi_common.h
@@ -0,0 +1,112 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_COMMON_H_
+#define LUA_COMMON_H_
+
+extern "C" {
+#include <lua.h>
+}
+
+#include "server.h"
+#include "environment.h"
+#include "nodedef.h"
+#include "util/pointedthing.h"
+#include "tool.h"
+
+Server* get_server(lua_State *L);
+ServerEnvironment* get_env(lua_State *L);
+
+void warn_if_field_exists(lua_State *L, int table,
+ const char *fieldname, const std::string &message);
+
+ToolCapabilities read_tool_capabilities (lua_State *L, int table);
+void push_tool_capabilities (lua_State *L,
+ const ToolCapabilities &prop);
+void set_tool_capabilities (lua_State *L, int table,
+ const ToolCapabilities &toolcap);
+
+void realitycheck (lua_State *L);
+
+void push_pointed_thing (lua_State *L,
+ const PointedThing& pointed);
+
+void stackDump (lua_State *L, std::ostream &o);
+
+class StackUnroller
+{
+private:
+ lua_State *m_lua;
+ int m_original_top;
+public:
+ StackUnroller(lua_State *L):
+ m_lua(L),
+ m_original_top(-1)
+ {
+ m_original_top = lua_gettop(m_lua); // store stack height
+ }
+ ~StackUnroller()
+ {
+ lua_settop(m_lua, m_original_top); // restore stack height
+ }
+};
+
+/* definitions */
+// What scriptapi_run_callbacks does with the return values of callbacks.
+// Regardless of the mode, if only one callback is defined,
+// its return value is the total return value.
+// Modes only affect the case where 0 or >= 2 callbacks are defined.
+enum RunCallbacksMode
+{
+ // Returns the return value of the first callback
+ // Returns nil if list of callbacks is empty
+ RUN_CALLBACKS_MODE_FIRST,
+ // Returns the return value of the last callback
+ // Returns nil if list of callbacks is empty
+ RUN_CALLBACKS_MODE_LAST,
+ // If any callback returns a false value, the first such is returned
+ // Otherwise, the first callback's return value (trueish) is returned
+ // Returns true if list of callbacks is empty
+ RUN_CALLBACKS_MODE_AND,
+ // Like above, but stops calling callbacks (short circuit)
+ // after seeing the first false value
+ RUN_CALLBACKS_MODE_AND_SC,
+ // If any callback returns a true value, the first such is returned
+ // Otherwise, the first callback's return value (falseish) is returned
+ // Returns false if list of callbacks is empty
+ RUN_CALLBACKS_MODE_OR,
+ // Like above, but stops calling callbacks (short circuit)
+ // after seeing the first true value
+ RUN_CALLBACKS_MODE_OR_SC,
+ // Note: "a true value" and "a false value" refer to values that
+ // are converted by lua_toboolean to true or false, respectively.
+};
+
+struct EnumString
+{
+ int num;
+ const char *str;
+};
+
+bool string_to_enum(const EnumString *spec, int &result,
+ const std::string &str);
+
+int getenumfield(lua_State *L, int table,
+ const char *fieldname, const EnumString *spec, int default_);
+#endif /* LUA_COMMON_H_ */
diff --git a/src/scriptapi_content.cpp b/src/scriptapi_content.cpp
new file mode 100644
index 000000000..3b7ed5179
--- /dev/null
+++ b/src/scriptapi_content.cpp
@@ -0,0 +1,322 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_content.h"
+#include "scriptapi_types.h"
+#include "scriptapi_common.h"
+#include "scriptapi_node.h"
+
+
+NodeBox read_nodebox(lua_State *L, int index)
+{
+ NodeBox nodebox;
+ if(lua_istable(L, -1)){
+ nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
+ es_NodeBoxType, NODEBOX_REGULAR);
+
+ lua_getfield(L, index, "fixed");
+ if(lua_istable(L, -1))
+ nodebox.fixed = read_aabb3f_vector(L, -1, BS);
+ lua_pop(L, 1);
+
+ lua_getfield(L, index, "wall_top");
+ if(lua_istable(L, -1))
+ nodebox.wall_top = read_aabb3f(L, -1, BS);
+ lua_pop(L, 1);
+
+ lua_getfield(L, index, "wall_bottom");
+ if(lua_istable(L, -1))
+ nodebox.wall_bottom = read_aabb3f(L, -1, BS);
+ lua_pop(L, 1);
+
+ lua_getfield(L, index, "wall_side");
+ if(lua_istable(L, -1))
+ nodebox.wall_side = read_aabb3f(L, -1, BS);
+ lua_pop(L, 1);
+ }
+ return nodebox;
+}
+
+/*
+ SimpleSoundSpec
+*/
+
+void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+ if(lua_isnil(L, index)){
+ } else if(lua_istable(L, index)){
+ getstringfield(L, index, "name", spec.name);
+ getfloatfield(L, index, "gain", spec.gain);
+ } else if(lua_isstring(L, index)){
+ spec.name = lua_tostring(L, index);
+ }
+}
+
+struct EnumString es_TileAnimationType[] =
+{
+ {TAT_NONE, "none"},
+ {TAT_VERTICAL_FRAMES, "vertical_frames"},
+ {0, NULL},
+};
+
+/*
+ TileDef
+*/
+
+TileDef read_tiledef(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ TileDef tiledef;
+
+ // key at index -2 and value at index
+ if(lua_isstring(L, index)){
+ // "default_lava.png"
+ tiledef.name = lua_tostring(L, index);
+ }
+ else if(lua_istable(L, index))
+ {
+ // {name="default_lava.png", animation={}}
+ tiledef.name = "";
+ getstringfield(L, index, "name", tiledef.name);
+ getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
+ tiledef.backface_culling = getboolfield_default(
+ L, index, "backface_culling", true);
+ // animation = {}
+ lua_getfield(L, index, "animation");
+ if(lua_istable(L, -1)){
+ // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
+ tiledef.animation.type = (TileAnimationType)
+ getenumfield(L, -1, "type", es_TileAnimationType,
+ TAT_NONE);
+ tiledef.animation.aspect_w =
+ getintfield_default(L, -1, "aspect_w", 16);
+ tiledef.animation.aspect_h =
+ getintfield_default(L, -1, "aspect_h", 16);
+ tiledef.animation.length =
+ getfloatfield_default(L, -1, "length", 1.0);
+ }
+ lua_pop(L, 1);
+ }
+
+ return tiledef;
+}
+
+/*
+ ContentFeatures
+*/
+
+ContentFeatures read_content_features(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ ContentFeatures f;
+
+ /* Cache existence of some callbacks */
+ lua_getfield(L, index, "on_construct");
+ if(!lua_isnil(L, -1)) f.has_on_construct = true;
+ lua_pop(L, 1);
+ lua_getfield(L, index, "on_destruct");
+ if(!lua_isnil(L, -1)) f.has_on_destruct = true;
+ lua_pop(L, 1);
+ lua_getfield(L, index, "after_destruct");
+ if(!lua_isnil(L, -1)) f.has_after_destruct = true;
+ lua_pop(L, 1);
+
+ lua_getfield(L, index, "on_rightclick");
+ f.rightclickable = lua_isfunction(L, -1);
+ lua_pop(L, 1);
+
+ /* Name */
+ getstringfield(L, index, "name", f.name);
+
+ /* Groups */
+ lua_getfield(L, index, "groups");
+ read_groups(L, -1, f.groups);
+ lua_pop(L, 1);
+
+ /* Visual definition */
+
+ f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", es_DrawType,
+ NDT_NORMAL);
+ getfloatfield(L, index, "visual_scale", f.visual_scale);
+
+ // tiles = {}
+ lua_getfield(L, index, "tiles");
+ // If nil, try the deprecated name "tile_images" instead
+ if(lua_isnil(L, -1)){
+ lua_pop(L, 1);
+ warn_if_field_exists(L, index, "tile_images",
+ "Deprecated; new name is \"tiles\".");
+ lua_getfield(L, index, "tile_images");
+ }
+ if(lua_istable(L, -1)){
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ int i = 0;
+ while(lua_next(L, table) != 0){
+ // Read tiledef from value
+ f.tiledef[i] = read_tiledef(L, -1);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ i++;
+ if(i==6){
+ lua_pop(L, 1);
+ break;
+ }
+ }
+ // Copy last value to all remaining textures
+ if(i >= 1){
+ TileDef lasttile = f.tiledef[i-1];
+ while(i < 6){
+ f.tiledef[i] = lasttile;
+ i++;
+ }
+ }
+ }
+ lua_pop(L, 1);
+
+ // special_tiles = {}
+ lua_getfield(L, index, "special_tiles");
+ // If nil, try the deprecated name "special_materials" instead
+ if(lua_isnil(L, -1)){
+ lua_pop(L, 1);
+ warn_if_field_exists(L, index, "special_materials",
+ "Deprecated; new name is \"special_tiles\".");
+ lua_getfield(L, index, "special_materials");
+ }
+ if(lua_istable(L, -1)){
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ int i = 0;
+ while(lua_next(L, table) != 0){
+ // Read tiledef from value
+ f.tiledef_special[i] = read_tiledef(L, -1);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ i++;
+ if(i==6){
+ lua_pop(L, 1);
+ break;
+ }
+ }
+ }
+ lua_pop(L, 1);
+
+ f.alpha = getintfield_default(L, index, "alpha", 255);
+
+ /* Other stuff */
+
+ lua_getfield(L, index, "post_effect_color");
+ if(!lua_isnil(L, -1))
+ f.post_effect_color = readARGB8(L, -1);
+ lua_pop(L, 1);
+
+ f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
+ es_ContentParamType, CPT_NONE);
+ f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
+ es_ContentParamType2, CPT2_NONE);
+
+ // Warn about some deprecated fields
+ warn_if_field_exists(L, index, "wall_mounted",
+ "deprecated: use paramtype2 = 'wallmounted'");
+ warn_if_field_exists(L, index, "light_propagates",
+ "deprecated: determined from paramtype");
+ warn_if_field_exists(L, index, "dug_item",
+ "deprecated: use 'drop' field");
+ warn_if_field_exists(L, index, "extra_dug_item",
+ "deprecated: use 'drop' field");
+ warn_if_field_exists(L, index, "extra_dug_item_rarity",
+ "deprecated: use 'drop' field");
+ warn_if_field_exists(L, index, "metadata_name",
+ "deprecated: use on_add and metadata callbacks");
+
+ // True for all ground-like things like stone and mud, false for eg. trees
+ getboolfield(L, index, "is_ground_content", f.is_ground_content);
+ f.light_propagates = (f.param_type == CPT_LIGHT);
+ getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
+ // This is used for collision detection.
+ // Also for general solidness queries.
+ getboolfield(L, index, "walkable", f.walkable);
+ // Player can point to these
+ getboolfield(L, index, "pointable", f.pointable);
+ // Player can dig these
+ getboolfield(L, index, "diggable", f.diggable);
+ // Player can climb these
+ getboolfield(L, index, "climbable", f.climbable);
+ // Player can build on these
+ getboolfield(L, index, "buildable_to", f.buildable_to);
+ // Whether the node is non-liquid, source liquid or flowing liquid
+ f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
+ es_LiquidType, LIQUID_NONE);
+ // If the content is liquid, this is the flowing version of the liquid.
+ getstringfield(L, index, "liquid_alternative_flowing",
+ f.liquid_alternative_flowing);
+ // If the content is liquid, this is the source version of the liquid.
+ getstringfield(L, index, "liquid_alternative_source",
+ f.liquid_alternative_source);
+ // Viscosity for fluid flow, ranging from 1 to 7, with
+ // 1 giving almost instantaneous propagation and 7 being
+ // the slowest possible
+ f.liquid_viscosity = getintfield_default(L, index,
+ "liquid_viscosity", f.liquid_viscosity);
+ getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
+ // Amount of light the node emits
+ f.light_source = getintfield_default(L, index,
+ "light_source", f.light_source);
+ f.damage_per_second = getintfield_default(L, index,
+ "damage_per_second", f.damage_per_second);
+
+ lua_getfield(L, index, "node_box");
+ if(lua_istable(L, -1))
+ f.node_box = read_nodebox(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, index, "selection_box");
+ if(lua_istable(L, -1))
+ f.selection_box = read_nodebox(L, -1);
+ lua_pop(L, 1);
+
+ // Set to true if paramtype used to be 'facedir_simple'
+ getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
+ // Set to true if wall_mounted used to be set to true
+ getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
+
+ // Sound table
+ lua_getfield(L, index, "sounds");
+ if(lua_istable(L, -1)){
+ lua_getfield(L, -1, "footstep");
+ read_soundspec(L, -1, f.sound_footstep);
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "dig");
+ read_soundspec(L, -1, f.sound_dig);
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "dug");
+ read_soundspec(L, -1, f.sound_dug);
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
+ return f;
+}
diff --git a/src/scriptapi_content.h b/src/scriptapi_content.h
new file mode 100644
index 000000000..801f3856e
--- /dev/null
+++ b/src/scriptapi_content.h
@@ -0,0 +1,37 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_CONTENT_H_
+#define LUA_CONTENT_H_
+
+extern "C" {
+#include <lua.h>
+}
+
+#include "nodedef.h"
+
+ContentFeatures read_content_features (lua_State *L, int index);
+TileDef read_tiledef (lua_State *L, int index);
+void read_soundspec (lua_State *L, int index,
+ SimpleSoundSpec &spec);
+NodeBox read_nodebox (lua_State *L, int index);
+
+extern struct EnumString es_TileAnimationType[];
+
+#endif /* LUA_CONTENT_H_ */
diff --git a/src/scriptapi_craft.cpp b/src/scriptapi_craft.cpp
new file mode 100644
index 000000000..183eeb840
--- /dev/null
+++ b/src/scriptapi_craft.cpp
@@ -0,0 +1,454 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_craft.h"
+
+extern "C" {
+#include <lauxlib.h>
+}
+
+#include "script.h"
+#include "scriptapi_types.h"
+#include "scriptapi_common.h"
+#include "scriptapi_item.h"
+
+
+struct EnumString es_CraftMethod[] =
+{
+ {CRAFT_METHOD_NORMAL, "normal"},
+ {CRAFT_METHOD_COOKING, "cooking"},
+ {CRAFT_METHOD_FUEL, "fuel"},
+ {0, NULL},
+};
+
+
+// helper for register_craft
+bool read_craft_recipe_shaped(lua_State *L, int index,
+ int &width, std::vector<std::string> &recipe)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ if(!lua_istable(L, index))
+ return false;
+
+ lua_pushnil(L);
+ int rowcount = 0;
+ while(lua_next(L, index) != 0){
+ int colcount = 0;
+ // key at index -2 and value at index -1
+ if(!lua_istable(L, -1))
+ return false;
+ int table2 = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table2) != 0){
+ // key at index -2 and value at index -1
+ if(!lua_isstring(L, -1))
+ return false;
+ recipe.push_back(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ colcount++;
+ }
+ if(rowcount == 0){
+ width = colcount;
+ } else {
+ if(colcount != width)
+ return false;
+ }
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ rowcount++;
+ }
+ return width != 0;
+}
+
+// helper for register_craft
+bool read_craft_recipe_shapeless(lua_State *L, int index,
+ std::vector<std::string> &recipe)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ if(!lua_istable(L, index))
+ return false;
+
+ lua_pushnil(L);
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ if(!lua_isstring(L, -1))
+ return false;
+ recipe.push_back(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ return true;
+}
+
+// helper for register_craft
+bool read_craft_replacements(lua_State *L, int index,
+ CraftReplacements &replacements)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ if(!lua_istable(L, index))
+ return false;
+
+ lua_pushnil(L);
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ if(!lua_istable(L, -1))
+ return false;
+ lua_rawgeti(L, -1, 1);
+ if(!lua_isstring(L, -1))
+ return false;
+ std::string replace_from = lua_tostring(L, -1);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 2);
+ if(!lua_isstring(L, -1))
+ return false;
+ std::string replace_to = lua_tostring(L, -1);
+ lua_pop(L, 1);
+ replacements.pairs.push_back(
+ std::make_pair(replace_from, replace_to));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ return true;
+}
+// register_craft({output=item, recipe={{item00,item10},{item01,item11}})
+int l_register_craft(lua_State *L)
+{
+ //infostream<<"register_craft"<<std::endl;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ int table = 1;
+
+ // Get the writable craft definition manager from the server
+ IWritableCraftDefManager *craftdef =
+ get_server(L)->getWritableCraftDefManager();
+
+ std::string type = getstringfield_default(L, table, "type", "shaped");
+
+ /*
+ CraftDefinitionShaped
+ */
+ if(type == "shaped"){
+ std::string output = getstringfield_default(L, table, "output", "");
+ if(output == "")
+ throw LuaError(L, "Crafting definition is missing an output");
+
+ int width = 0;
+ std::vector<std::string> recipe;
+ lua_getfield(L, table, "recipe");
+ if(lua_isnil(L, -1))
+ throw LuaError(L, "Crafting definition is missing a recipe"
+ " (output=\"" + output + "\")");
+ if(!read_craft_recipe_shaped(L, -1, width, recipe))
+ throw LuaError(L, "Invalid crafting recipe"
+ " (output=\"" + output + "\")");
+
+ CraftReplacements replacements;
+ lua_getfield(L, table, "replacements");
+ if(!lua_isnil(L, -1))
+ {
+ if(!read_craft_replacements(L, -1, replacements))
+ throw LuaError(L, "Invalid replacements"
+ " (output=\"" + output + "\")");
+ }
+
+ CraftDefinition *def = new CraftDefinitionShaped(
+ output, width, recipe, replacements);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionShapeless
+ */
+ else if(type == "shapeless"){
+ std::string output = getstringfield_default(L, table, "output", "");
+ if(output == "")
+ throw LuaError(L, "Crafting definition (shapeless)"
+ " is missing an output");
+
+ std::vector<std::string> recipe;
+ lua_getfield(L, table, "recipe");
+ if(lua_isnil(L, -1))
+ throw LuaError(L, "Crafting definition (shapeless)"
+ " is missing a recipe"
+ " (output=\"" + output + "\")");
+ if(!read_craft_recipe_shapeless(L, -1, recipe))
+ throw LuaError(L, "Invalid crafting recipe"
+ " (output=\"" + output + "\")");
+
+ CraftReplacements replacements;
+ lua_getfield(L, table, "replacements");
+ if(!lua_isnil(L, -1))
+ {
+ if(!read_craft_replacements(L, -1, replacements))
+ throw LuaError(L, "Invalid replacements"
+ " (output=\"" + output + "\")");
+ }
+
+ CraftDefinition *def = new CraftDefinitionShapeless(
+ output, recipe, replacements);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionToolRepair
+ */
+ else if(type == "toolrepair"){
+ float additional_wear = getfloatfield_default(L, table,
+ "additional_wear", 0.0);
+
+ CraftDefinition *def = new CraftDefinitionToolRepair(
+ additional_wear);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionCooking
+ */
+ else if(type == "cooking"){
+ std::string output = getstringfield_default(L, table, "output", "");
+ if(output == "")
+ throw LuaError(L, "Crafting definition (cooking)"
+ " is missing an output");
+
+ std::string recipe = getstringfield_default(L, table, "recipe", "");
+ if(recipe == "")
+ throw LuaError(L, "Crafting definition (cooking)"
+ " is missing a recipe"
+ " (output=\"" + output + "\")");
+
+ float cooktime = getfloatfield_default(L, table, "cooktime", 3.0);
+
+ CraftReplacements replacements;
+ lua_getfield(L, table, "replacements");
+ if(!lua_isnil(L, -1))
+ {
+ if(!read_craft_replacements(L, -1, replacements))
+ throw LuaError(L, "Invalid replacements"
+ " (cooking output=\"" + output + "\")");
+ }
+
+ CraftDefinition *def = new CraftDefinitionCooking(
+ output, recipe, cooktime, replacements);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionFuel
+ */
+ else if(type == "fuel"){
+ std::string recipe = getstringfield_default(L, table, "recipe", "");
+ if(recipe == "")
+ throw LuaError(L, "Crafting definition (fuel)"
+ " is missing a recipe");
+
+ float burntime = getfloatfield_default(L, table, "burntime", 1.0);
+
+ CraftReplacements replacements;
+ lua_getfield(L, table, "replacements");
+ if(!lua_isnil(L, -1))
+ {
+ if(!read_craft_replacements(L, -1, replacements))
+ throw LuaError(L, "Invalid replacements"
+ " (fuel recipe=\"" + recipe + "\")");
+ }
+
+ CraftDefinition *def = new CraftDefinitionFuel(
+ recipe, burntime, replacements);
+ craftdef->registerCraft(def);
+ }
+ else
+ {
+ throw LuaError(L, "Unknown crafting definition type: \"" + type + "\"");
+ }
+
+ lua_pop(L, 1);
+ return 0; /* number of results */
+}
+
+// get_craft_result(input)
+int l_get_craft_result(lua_State *L)
+{
+ int input_i = 1;
+ std::string method_s = getstringfield_default(L, input_i, "method", "normal");
+ enum CraftMethod method = (CraftMethod)getenumfield(L, input_i, "method",
+ es_CraftMethod, CRAFT_METHOD_NORMAL);
+ int width = 1;
+ lua_getfield(L, input_i, "width");
+ if(lua_isnumber(L, -1))
+ width = luaL_checkinteger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, input_i, "items");
+ std::vector<ItemStack> items = read_items(L, -1);
+ lua_pop(L, 1); // items
+
+ IGameDef *gdef = get_server(L);
+ ICraftDefManager *cdef = gdef->cdef();
+ CraftInput input(method, width, items);
+ CraftOutput output;
+ bool got = cdef->getCraftResult(input, output, true, gdef);
+ lua_newtable(L); // output table
+ if(got){
+ ItemStack item;
+ item.deSerialize(output.item, gdef->idef());
+ LuaItemStack::create(L, item);
+ lua_setfield(L, -2, "item");
+ setintfield(L, -1, "time", output.time);
+ } else {
+ LuaItemStack::create(L, ItemStack());
+ lua_setfield(L, -2, "item");
+ setintfield(L, -1, "time", 0);
+ }
+ lua_newtable(L); // decremented input table
+ lua_pushstring(L, method_s.c_str());
+ lua_setfield(L, -2, "method");
+ lua_pushinteger(L, width);
+ lua_setfield(L, -2, "width");
+ push_items(L, input.items);
+ lua_setfield(L, -2, "items");
+ return 2;
+}
+
+// get_craft_recipe(result item)
+int l_get_craft_recipe(lua_State *L)
+{
+ int k = 0;
+ char tmp[20];
+ int input_i = 1;
+ std::string o_item = luaL_checkstring(L,input_i);
+
+ IGameDef *gdef = get_server(L);
+ ICraftDefManager *cdef = gdef->cdef();
+ CraftInput input;
+ CraftOutput output(o_item,0);
+ bool got = cdef->getCraftRecipe(input, output, gdef);
+ lua_newtable(L); // output table
+ if(got){
+ lua_newtable(L);
+ for(std::vector<ItemStack>::const_iterator
+ i = input.items.begin();
+ i != input.items.end(); i++, k++)
+ {
+ if (i->empty())
+ {
+ continue;
+ }
+ sprintf(tmp,"%d",k);
+ lua_pushstring(L,tmp);
+ lua_pushstring(L,i->name.c_str());
+ lua_settable(L, -3);
+ }
+ lua_setfield(L, -2, "items");
+ setintfield(L, -1, "width", input.width);
+ switch (input.method) {
+ case CRAFT_METHOD_NORMAL:
+ lua_pushstring(L,"normal");
+ break;
+ case CRAFT_METHOD_COOKING:
+ lua_pushstring(L,"cooking");
+ break;
+ case CRAFT_METHOD_FUEL:
+ lua_pushstring(L,"fuel");
+ break;
+ default:
+ lua_pushstring(L,"unknown");
+ }
+ lua_setfield(L, -2, "type");
+ } else {
+ lua_pushnil(L);
+ lua_setfield(L, -2, "items");
+ setintfield(L, -1, "width", 0);
+ }
+ return 1;
+}
+
+// get_all_craft_recipes(result item)
+int l_get_all_craft_recipes(lua_State *L)
+{
+ char tmp[20];
+ int input_i = 1;
+ std::string o_item = luaL_checkstring(L,input_i);
+ IGameDef *gdef = get_server(L);
+ ICraftDefManager *cdef = gdef->cdef();
+ CraftInput input;
+ CraftOutput output(o_item,0);
+ std::vector<CraftDefinition*> recipes_list = cdef->getCraftRecipes(output, gdef);
+ if (recipes_list.empty())
+ {
+ lua_pushnil(L);
+ return 1;
+ }
+ // Get the table insert function
+ lua_getglobal(L, "table");
+ lua_getfield(L, -1, "insert");
+ int table_insert = lua_gettop(L);
+ lua_newtable(L);
+ int table = lua_gettop(L);
+ for(std::vector<CraftDefinition*>::const_iterator
+ i = recipes_list.begin();
+ i != recipes_list.end(); i++)
+ {
+ CraftOutput tmpout;
+ tmpout.item = "";
+ tmpout.time = 0;
+ CraftDefinition *def = *i;
+ tmpout = def->getOutput(input, gdef);
+ if(tmpout.item.substr(0,output.item.length()) == output.item)
+ {
+ input = def->getInput(output, gdef);
+ lua_pushvalue(L, table_insert);
+ lua_pushvalue(L, table);
+ lua_newtable(L);
+ int k = 0;
+ lua_newtable(L);
+ for(std::vector<ItemStack>::const_iterator
+ i = input.items.begin();
+ i != input.items.end(); i++, k++)
+ {
+ if (i->empty()) continue;
+ sprintf(tmp,"%d",k);
+ lua_pushstring(L,tmp);
+ lua_pushstring(L,i->name.c_str());
+ lua_settable(L, -3);
+ }
+ lua_setfield(L, -2, "items");
+ setintfield(L, -1, "width", input.width);
+ switch (input.method)
+ {
+ case CRAFT_METHOD_NORMAL:
+ lua_pushstring(L,"normal");
+ break;
+ case CRAFT_METHOD_COOKING:
+ lua_pushstring(L,"cooking");
+ break;
+ case CRAFT_METHOD_FUEL:
+ lua_pushstring(L,"fuel");
+ break;
+ default:
+ lua_pushstring(L,"unknown");
+ }
+ lua_setfield(L, -2, "type");
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ }
+ }
+ return 1;
+}
diff --git a/src/scriptapi_craft.h b/src/scriptapi_craft.h
new file mode 100644
index 000000000..f28989fd9
--- /dev/null
+++ b/src/scriptapi_craft.h
@@ -0,0 +1,51 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_CRAFT_H_
+#define LUA_CRAFT_H_
+
+#include <vector>
+
+extern "C" {
+#include <lua.h>
+}
+
+#include "craftdef.h"
+
+/*****************************************************************************/
+/* Mod API */
+/*****************************************************************************/
+int l_register_craft(lua_State *L);
+int l_get_craft_recipe(lua_State *L);
+int l_get_all_craft_recipes(lua_State *L);
+int l_get_craft_result(lua_State *L);
+
+/*****************************************************************************/
+/* scriptapi internal */
+/*****************************************************************************/
+bool read_craft_replacements(lua_State *L, int index,
+ CraftReplacements &replacements);
+bool read_craft_recipe_shapeless(lua_State *L, int index,
+ std::vector<std::string> &recipe);
+bool read_craft_recipe_shaped(lua_State *L, int index,
+ int &width, std::vector<std::string> &recipe);
+
+extern struct EnumString es_CraftMethod[];
+
+#endif /* LUA_CRAFT_H_ */
diff --git a/src/scriptapi_entity.cpp b/src/scriptapi_entity.cpp
new file mode 100644
index 000000000..c15f801a6
--- /dev/null
+++ b/src/scriptapi_entity.cpp
@@ -0,0 +1,293 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_entity.h"
+
+extern "C" {
+#include <lauxlib.h>
+}
+
+#include "log.h"
+#include "script.h"
+#include "scriptapi_types.h"
+#include "scriptapi_object.h"
+#include "scriptapi_common.h"
+
+
+void luaentity_get(lua_State *L, u16 id)
+{
+ // Get minetest.luaentities[i]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "luaentities");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnumber(L, id);
+ lua_gettable(L, -2);
+ lua_remove(L, -2); // luaentities
+ lua_remove(L, -2); // minetest
+}
+
+/*
+ luaentity
+*/
+
+bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ verbosestream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
+ <<name<<"\""<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.registered_entities[name]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_entities");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushstring(L, name);
+ lua_gettable(L, -2);
+ // Should be a table, which we will use as a prototype
+ //luaL_checktype(L, -1, LUA_TTABLE);
+ if(lua_type(L, -1) != LUA_TTABLE){
+ errorstream<<"LuaEntity name \""<<name<<"\" not defined"<<std::endl;
+ return false;
+ }
+ int prototype_table = lua_gettop(L);
+ //dump2(L, "prototype_table");
+
+ // Create entity object
+ lua_newtable(L);
+ int object = lua_gettop(L);
+
+ // Set object metatable
+ lua_pushvalue(L, prototype_table);
+ lua_setmetatable(L, -2);
+
+ // Add object reference
+ // This should be userdata with metatable ObjectRef
+ objectref_get(L, id);
+ luaL_checktype(L, -1, LUA_TUSERDATA);
+ if(!luaL_checkudata(L, -1, "ObjectRef"))
+ luaL_typerror(L, -1, "ObjectRef");
+ lua_setfield(L, -2, "object");
+
+ // minetest.luaentities[id] = object
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "luaentities");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnumber(L, id); // Push id
+ lua_pushvalue(L, object); // Copy object to top of stack
+ lua_settable(L, -3);
+
+ return true;
+}
+
+void scriptapi_luaentity_activate(lua_State *L, u16 id,
+ const std::string &staticdata, u32 dtime_s)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ verbosestream<<"scriptapi_luaentity_activate: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.luaentities[id]
+ luaentity_get(L, id);
+ int object = lua_gettop(L);
+
+ // Get on_activate function
+ lua_pushvalue(L, object);
+ lua_getfield(L, -1, "on_activate");
+ if(!lua_isnil(L, -1)){
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, object); // self
+ lua_pushlstring(L, staticdata.c_str(), staticdata.size());
+ lua_pushinteger(L, dtime_s);
+ // Call with 3 arguments, 0 results
+ if(lua_pcall(L, 3, 0, 0))
+ script_error(L, "error running function on_activate: %s\n",
+ lua_tostring(L, -1));
+ }
+}
+
+void scriptapi_luaentity_rm(lua_State *L, u16 id)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ verbosestream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
+
+ // Get minetest.luaentities table
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "luaentities");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int objectstable = lua_gettop(L);
+
+ // Set luaentities[id] = nil
+ lua_pushnumber(L, id); // Push id
+ lua_pushnil(L);
+ lua_settable(L, objectstable);
+
+ lua_pop(L, 2); // pop luaentities, minetest
+}
+
+std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.luaentities[id]
+ luaentity_get(L, id);
+ int object = lua_gettop(L);
+
+ // Get get_staticdata function
+ lua_pushvalue(L, object);
+ lua_getfield(L, -1, "get_staticdata");
+ if(lua_isnil(L, -1))
+ return "";
+
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, object); // self
+ // Call with 1 arguments, 1 results
+ if(lua_pcall(L, 1, 1, 0))
+ script_error(L, "error running function get_staticdata: %s\n",
+ lua_tostring(L, -1));
+
+ size_t len=0;
+ const char *s = lua_tolstring(L, -1, &len);
+ return std::string(s, len);
+}
+
+void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
+ ObjectProperties *prop)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.luaentities[id]
+ luaentity_get(L, id);
+ //int object = lua_gettop(L);
+
+ // Set default values that differ from ObjectProperties defaults
+ prop->hp_max = 10;
+
+ /* Read stuff */
+
+ prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
+
+ getboolfield(L, -1, "physical", prop->physical);
+
+ getfloatfield(L, -1, "weight", prop->weight);
+
+ lua_getfield(L, -1, "collisionbox");
+ if(lua_istable(L, -1))
+ prop->collisionbox = read_aabb3f(L, -1, 1.0);
+ lua_pop(L, 1);
+
+ getstringfield(L, -1, "visual", prop->visual);
+
+ getstringfield(L, -1, "mesh", prop->mesh);
+
+ // Deprecated: read object properties directly
+ read_object_properties(L, -1, prop);
+
+ // Read initial_properties
+ lua_getfield(L, -1, "initial_properties");
+ read_object_properties(L, -1, prop);
+ lua_pop(L, 1);
+}
+
+void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.luaentities[id]
+ luaentity_get(L, id);
+ int object = lua_gettop(L);
+ // State: object is at top of stack
+ // Get step function
+ lua_getfield(L, -1, "on_step");
+ if(lua_isnil(L, -1))
+ return;
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, object); // self
+ lua_pushnumber(L, dtime); // dtime
+ // Call with 2 arguments, 0 results
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1));
+}
+
+// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
+// tool_capabilities, direction)
+void scriptapi_luaentity_punch(lua_State *L, u16 id,
+ ServerActiveObject *puncher, float time_from_last_punch,
+ const ToolCapabilities *toolcap, v3f dir)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.luaentities[id]
+ luaentity_get(L, id);
+ int object = lua_gettop(L);
+ // State: object is at top of stack
+ // Get function
+ lua_getfield(L, -1, "on_punch");
+ if(lua_isnil(L, -1))
+ return;
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, object); // self
+ objectref_get_or_create(L, puncher); // Clicker reference
+ lua_pushnumber(L, time_from_last_punch);
+ push_tool_capabilities(L, *toolcap);
+ push_v3f(L, dir);
+ // Call with 5 arguments, 0 results
+ if(lua_pcall(L, 5, 0, 0))
+ script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
+}
+
+// Calls entity:on_rightclick(ObjectRef clicker)
+void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
+ ServerActiveObject *clicker)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.luaentities[id]
+ luaentity_get(L, id);
+ int object = lua_gettop(L);
+ // State: object is at top of stack
+ // Get function
+ lua_getfield(L, -1, "on_rightclick");
+ if(lua_isnil(L, -1))
+ return;
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, object); // self
+ objectref_get_or_create(L, clicker); // Clicker reference
+ // Call with 2 arguments, 0 results
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
+}
diff --git a/src/scriptapi_entity.h b/src/scriptapi_entity.h
new file mode 100644
index 000000000..e08743258
--- /dev/null
+++ b/src/scriptapi_entity.h
@@ -0,0 +1,54 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_ENTITY_H_
+#define LUA_ENTITY_H_
+
+extern "C" {
+#include <lua.h>
+}
+
+#include "object_properties.h"
+#include "content_sao.h"
+#include "tool.h"
+
+/*****************************************************************************/
+/* scriptapi internal */
+/*****************************************************************************/
+void luaentity_get(lua_State *L, u16 id);
+
+/*****************************************************************************/
+/* Minetest interface */
+/*****************************************************************************/
+// Returns true if succesfully added into Lua; false otherwise.
+bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name);
+void scriptapi_luaentity_activate(lua_State *L, u16 id,
+ const std::string &staticdata, u32 dtime_s);
+void scriptapi_luaentity_rm(lua_State *L, u16 id);
+std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id);
+void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
+ ObjectProperties *prop);
+void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime);
+void scriptapi_luaentity_punch(lua_State *L, u16 id,
+ ServerActiveObject *puncher, float time_from_last_punch,
+ const ToolCapabilities *toolcap, v3f dir);
+void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
+ ServerActiveObject *clicker);
+
+#endif /* LUA_ENTITY_H_ */
diff --git a/src/scriptapi_env.cpp b/src/scriptapi_env.cpp
new file mode 100644
index 000000000..4e068e377
--- /dev/null
+++ b/src/scriptapi_env.cpp
@@ -0,0 +1,908 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_env.h"
+#include "nodedef.h"
+#include "gamedef.h"
+#include "map.h"
+#include "daynightratio.h"
+#include "content_sao.h"
+#include "script.h"
+#include "treegen.h"
+#include "util/pointedthing.h"
+#include "scriptapi_types.h"
+#include "scriptapi_noise.h"
+#include "scriptapi_nodemeta.h"
+#include "scriptapi_nodetimer.h"
+#include "scriptapi_object.h"
+#include "scriptapi_common.h"
+#include "scriptapi_item.h"
+#include "scriptapi_node.h"
+
+
+//TODO
+extern void scriptapi_run_callbacks(lua_State *L, int nargs,
+ RunCallbacksMode mode);
+
+
+class LuaABM : public ActiveBlockModifier
+{
+private:
+ lua_State *m_lua;
+ int m_id;
+
+ std::set<std::string> m_trigger_contents;
+ std::set<std::string> m_required_neighbors;
+ float m_trigger_interval;
+ u32 m_trigger_chance;
+public:
+ LuaABM(lua_State *L, int id,
+ const std::set<std::string> &trigger_contents,
+ const std::set<std::string> &required_neighbors,
+ float trigger_interval, u32 trigger_chance):
+ m_lua(L),
+ m_id(id),
+ m_trigger_contents(trigger_contents),
+ m_required_neighbors(required_neighbors),
+ m_trigger_interval(trigger_interval),
+ m_trigger_chance(trigger_chance)
+ {
+ }
+ virtual std::set<std::string> getTriggerContents()
+ {
+ return m_trigger_contents;
+ }
+ virtual std::set<std::string> getRequiredNeighbors()
+ {
+ return m_required_neighbors;
+ }
+ virtual float getTriggerInterval()
+ {
+ return m_trigger_interval;
+ }
+ virtual u32 getTriggerChance()
+ {
+ return m_trigger_chance;
+ }
+ virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
+ u32 active_object_count, u32 active_object_count_wider)
+ {
+ lua_State *L = m_lua;
+
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.registered_abms
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_abms");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int registered_abms = lua_gettop(L);
+
+ // Get minetest.registered_abms[m_id]
+ lua_pushnumber(L, m_id);
+ lua_gettable(L, registered_abms);
+ if(lua_isnil(L, -1))
+ assert(0);
+
+ // Call action
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, "action");
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ push_v3s16(L, p);
+ pushnode(L, n, env->getGameDef()->ndef());
+ lua_pushnumber(L, active_object_count);
+ lua_pushnumber(L, active_object_count_wider);
+ if(lua_pcall(L, 4, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ }
+};
+
+/*
+ EnvRef
+*/
+
+int EnvRef::gc_object(lua_State *L) {
+ EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+EnvRef* EnvRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(EnvRef**)ud; // unbox pointer
+}
+
+// Exported functions
+
+// EnvRef:set_node(pos, node)
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_set_node(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ INodeDefManager *ndef = env->getGameDef()->ndef();
+ // parameters
+ v3s16 pos = read_v3s16(L, 2);
+ MapNode n = readnode(L, 3, ndef);
+ // Do it
+ bool succeeded = env->setNode(pos, n);
+ lua_pushboolean(L, succeeded);
+ return 1;
+}
+
+int EnvRef::l_add_node(lua_State *L)
+{
+ return l_set_node(L);
+}
+
+// EnvRef:remove_node(pos)
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_remove_node(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ // parameters
+ v3s16 pos = read_v3s16(L, 2);
+ // Do it
+ bool succeeded = env->removeNode(pos);
+ lua_pushboolean(L, succeeded);
+ return 1;
+}
+
+// EnvRef:get_node(pos)
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_get_node(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // pos
+ v3s16 pos = read_v3s16(L, 2);
+ // Do it
+ MapNode n = env->getMap().getNodeNoEx(pos);
+ // Return node
+ pushnode(L, n, env->getGameDef()->ndef());
+ return 1;
+}
+
+// EnvRef:get_node_or_nil(pos)
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_get_node_or_nil(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // pos
+ v3s16 pos = read_v3s16(L, 2);
+ // Do it
+ try{
+ MapNode n = env->getMap().getNode(pos);
+ // Return node
+ pushnode(L, n, env->getGameDef()->ndef());
+ return 1;
+ } catch(InvalidPositionException &e)
+ {
+ lua_pushnil(L);
+ return 1;
+ }
+}
+
+// EnvRef:get_node_light(pos, timeofday)
+// pos = {x=num, y=num, z=num}
+// timeofday: nil = current time, 0 = night, 0.5 = day
+int EnvRef::l_get_node_light(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ v3s16 pos = read_v3s16(L, 2);
+ u32 time_of_day = env->getTimeOfDay();
+ if(lua_isnumber(L, 3))
+ time_of_day = 24000.0 * lua_tonumber(L, 3);
+ time_of_day %= 24000;
+ u32 dnr = time_to_daynight_ratio(time_of_day, true);
+ MapNode n = env->getMap().getNodeNoEx(pos);
+ try{
+ MapNode n = env->getMap().getNode(pos);
+ INodeDefManager *ndef = env->getGameDef()->ndef();
+ lua_pushinteger(L, n.getLightBlend(dnr, ndef));
+ return 1;
+ } catch(InvalidPositionException &e)
+ {
+ lua_pushnil(L);
+ return 1;
+ }
+}
+
+// EnvRef:place_node(pos, node)
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_place_node(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ v3s16 pos = read_v3s16(L, 2);
+ MapNode n = readnode(L, 3, env->getGameDef()->ndef());
+
+ // Don't attempt to load non-loaded area as of now
+ MapNode n_old = env->getMap().getNodeNoEx(pos);
+ if(n_old.getContent() == CONTENT_IGNORE){
+ lua_pushboolean(L, false);
+ return 1;
+ }
+ // Create item to place
+ INodeDefManager *ndef = get_server(L)->ndef();
+ IItemDefManager *idef = get_server(L)->idef();
+ ItemStack item(ndef->get(n).name, 1, 0, "", idef);
+ // Make pointed position
+ PointedThing pointed;
+ pointed.type = POINTEDTHING_NODE;
+ pointed.node_abovesurface = pos;
+ pointed.node_undersurface = pos + v3s16(0,-1,0);
+ // Place it with a NULL placer (appears in Lua as a non-functional
+ // ObjectRef)
+ bool success = scriptapi_item_on_place(L, item, NULL, pointed);
+ lua_pushboolean(L, success);
+ return 1;
+}
+
+// EnvRef:dig_node(pos)
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_dig_node(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ v3s16 pos = read_v3s16(L, 2);
+
+ // Don't attempt to load non-loaded area as of now
+ MapNode n = env->getMap().getNodeNoEx(pos);
+ if(n.getContent() == CONTENT_IGNORE){
+ lua_pushboolean(L, false);
+ return 1;
+ }
+ // Dig it out with a NULL digger (appears in Lua as a
+ // non-functional ObjectRef)
+ bool success = scriptapi_node_on_dig(L, pos, n, NULL);
+ lua_pushboolean(L, success);
+ return 1;
+}
+
+// EnvRef:punch_node(pos)
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_punch_node(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ v3s16 pos = read_v3s16(L, 2);
+
+ // Don't attempt to load non-loaded area as of now
+ MapNode n = env->getMap().getNodeNoEx(pos);
+ if(n.getContent() == CONTENT_IGNORE){
+ lua_pushboolean(L, false);
+ return 1;
+ }
+ // Punch it with a NULL puncher (appears in Lua as a non-functional
+ // ObjectRef)
+ bool success = scriptapi_node_on_punch(L, pos, n, NULL);
+ lua_pushboolean(L, success);
+ return 1;
+}
+
+// EnvRef:get_meta(pos)
+int EnvRef::l_get_meta(lua_State *L)
+{
+ //infostream<<"EnvRef::l_get_meta()"<<std::endl;
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ v3s16 p = read_v3s16(L, 2);
+ NodeMetaRef::create(L, p, env);
+ return 1;
+}
+
+// EnvRef:get_node_timer(pos)
+int EnvRef::l_get_node_timer(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ v3s16 p = read_v3s16(L, 2);
+ NodeTimerRef::create(L, p, env);
+ return 1;
+}
+
+// EnvRef:add_entity(pos, entityname) -> ObjectRef or nil
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_add_entity(lua_State *L)
+{
+ //infostream<<"EnvRef::l_add_entity()"<<std::endl;
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // pos
+ v3f pos = checkFloatPos(L, 2);
+ // content
+ const char *name = luaL_checkstring(L, 3);
+ // Do it
+ ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, "");
+ int objectid = env->addActiveObject(obj);
+ // If failed to add, return nothing (reads as nil)
+ if(objectid == 0)
+ return 0;
+ // Return ObjectRef
+ objectref_get_or_create(L, obj);
+ return 1;
+}
+
+// EnvRef:add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_add_item(lua_State *L)
+{
+ //infostream<<"EnvRef::l_add_item()"<<std::endl;
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // pos
+ v3f pos = checkFloatPos(L, 2);
+ // item
+ ItemStack item = read_item(L, 3);
+ if(item.empty() || !item.isKnown(get_server(L)->idef()))
+ return 0;
+ // Use minetest.spawn_item to spawn a __builtin:item
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "spawn_item");
+ if(lua_isnil(L, -1))
+ return 0;
+ lua_pushvalue(L, 2);
+ lua_pushstring(L, item.getItemString().c_str());
+ if(lua_pcall(L, 2, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return 1;
+ /*lua_pushvalue(L, 1);
+ lua_pushstring(L, "__builtin:item");
+ lua_pushstring(L, item.getItemString().c_str());
+ return l_add_entity(L);*/
+ /*// Do it
+ ServerActiveObject *obj = createItemSAO(env, pos, item.getItemString());
+ int objectid = env->addActiveObject(obj);
+ // If failed to add, return nothing (reads as nil)
+ if(objectid == 0)
+ return 0;
+ // Return ObjectRef
+ objectref_get_or_create(L, obj);
+ return 1;*/
+}
+
+// EnvRef:add_rat(pos)
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_add_rat(lua_State *L)
+{
+ infostream<<"EnvRef::l_add_rat(): C++ mobs have been removed."
+ <<" Doing nothing."<<std::endl;
+ return 0;
+}
+
+// EnvRef:add_firefly(pos)
+// pos = {x=num, y=num, z=num}
+int EnvRef::l_add_firefly(lua_State *L)
+{
+ infostream<<"EnvRef::l_add_firefly(): C++ mobs have been removed."
+ <<" Doing nothing."<<std::endl;
+ return 0;
+}
+
+// EnvRef:get_player_by_name(name)
+int EnvRef::l_get_player_by_name(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ const char *name = luaL_checkstring(L, 2);
+ Player *player = env->getPlayer(name);
+ if(player == NULL){
+ lua_pushnil(L);
+ return 1;
+ }
+ PlayerSAO *sao = player->getPlayerSAO();
+ if(sao == NULL){
+ lua_pushnil(L);
+ return 1;
+ }
+ // Put player on stack
+ objectref_get_or_create(L, sao);
+ return 1;
+}
+
+// EnvRef:get_objects_inside_radius(pos, radius)
+int EnvRef::l_get_objects_inside_radius(lua_State *L)
+{
+ // Get the table insert function
+ lua_getglobal(L, "table");
+ lua_getfield(L, -1, "insert");
+ int table_insert = lua_gettop(L);
+ // Get environemnt
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ v3f pos = checkFloatPos(L, 2);
+ float radius = luaL_checknumber(L, 3) * BS;
+ std::set<u16> ids = env->getObjectsInsideRadius(pos, radius);
+ lua_newtable(L);
+ int table = lua_gettop(L);
+ for(std::set<u16>::const_iterator
+ i = ids.begin(); i != ids.end(); i++){
+ ServerActiveObject *obj = env->getActiveObject(*i);
+ // Insert object reference into table
+ lua_pushvalue(L, table_insert);
+ lua_pushvalue(L, table);
+ objectref_get_or_create(L, obj);
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ }
+ return 1;
+}
+
+// EnvRef:set_timeofday(val)
+// val = 0...1
+int EnvRef::l_set_timeofday(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ float timeofday_f = luaL_checknumber(L, 2);
+ assert(timeofday_f >= 0.0 && timeofday_f <= 1.0);
+ int timeofday_mh = (int)(timeofday_f * 24000.0);
+ // This should be set directly in the environment but currently
+ // such changes aren't immediately sent to the clients, so call
+ // the server instead.
+ //env->setTimeOfDay(timeofday_mh);
+ get_server(L)->setTimeOfDay(timeofday_mh);
+ return 0;
+}
+
+// EnvRef:get_timeofday() -> 0...1
+int EnvRef::l_get_timeofday(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ int timeofday_mh = env->getTimeOfDay();
+ float timeofday_f = (float)timeofday_mh / 24000.0;
+ lua_pushnumber(L, timeofday_f);
+ return 1;
+}
+
+
+// EnvRef:find_node_near(pos, radius, nodenames) -> pos or nil
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int EnvRef::l_find_node_near(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ INodeDefManager *ndef = get_server(L)->ndef();
+ v3s16 pos = read_v3s16(L, 2);
+ int radius = luaL_checkinteger(L, 3);
+ std::set<content_t> filter;
+ if(lua_istable(L, 4)){
+ int table = 4;
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
+ ndef->getIds(lua_tostring(L, -1), filter);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ } else if(lua_isstring(L, 4)){
+ ndef->getIds(lua_tostring(L, 4), filter);
+ }
+
+ for(int d=1; d<=radius; d++){
+ std::list<v3s16> list;
+ getFacePositions(list, d);
+ for(std::list<v3s16>::iterator i = list.begin();
+ i != list.end(); ++i){
+ v3s16 p = pos + (*i);
+ content_t c = env->getMap().getNodeNoEx(p).getContent();
+ if(filter.count(c) != 0){
+ push_v3s16(L, p);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+// EnvRef:find_nodes_in_area(minp, maxp, nodenames) -> list of positions
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int EnvRef::l_find_nodes_in_area(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ INodeDefManager *ndef = get_server(L)->ndef();
+ v3s16 minp = read_v3s16(L, 2);
+ v3s16 maxp = read_v3s16(L, 3);
+ std::set<content_t> filter;
+ if(lua_istable(L, 4)){
+ int table = 4;
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
+ ndef->getIds(lua_tostring(L, -1), filter);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ } else if(lua_isstring(L, 4)){
+ ndef->getIds(lua_tostring(L, 4), filter);
+ }
+
+ // Get the table insert function
+ lua_getglobal(L, "table");
+ lua_getfield(L, -1, "insert");
+ int table_insert = lua_gettop(L);
+
+ lua_newtable(L);
+ int table = lua_gettop(L);
+ for(s16 x=minp.X; x<=maxp.X; x++)
+ for(s16 y=minp.Y; y<=maxp.Y; y++)
+ for(s16 z=minp.Z; z<=maxp.Z; z++)
+ {
+ v3s16 p(x,y,z);
+ content_t c = env->getMap().getNodeNoEx(p).getContent();
+ if(filter.count(c) != 0){
+ lua_pushvalue(L, table_insert);
+ lua_pushvalue(L, table);
+ push_v3s16(L, p);
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ }
+ }
+ return 1;
+}
+
+// EnvRef:get_perlin(seeddiff, octaves, persistence, scale)
+// returns world-specific PerlinNoise
+int EnvRef::l_get_perlin(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ int seeddiff = luaL_checkint(L, 2);
+ int octaves = luaL_checkint(L, 3);
+ float persistence = luaL_checknumber(L, 4);
+ float scale = luaL_checknumber(L, 5);
+
+ LuaPerlinNoise *n = new LuaPerlinNoise(seeddiff + int(env->getServerMap().getSeed()), octaves, persistence, scale);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
+ luaL_getmetatable(L, "PerlinNoise");
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+// EnvRef:get_perlin_map(noiseparams, size)
+// returns world-specific PerlinNoiseMap
+int EnvRef::l_get_perlin_map(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if (env == NULL)
+ return 0;
+
+ NoiseParams *np = read_noiseparams(L, 2);
+ if (!np)
+ return 0;
+ v3s16 size = read_v3s16(L, 3);
+
+ int seed = (int)(env->getServerMap().getSeed());
+ LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(np, seed, size);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
+ luaL_getmetatable(L, "PerlinNoiseMap");
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+// EnvRef:clear_objects()
+// clear all objects in the environment
+int EnvRef::l_clear_objects(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ o->m_env->clearAllObjects();
+ return 0;
+}
+
+int EnvRef::l_spawn_tree(lua_State *L)
+{
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ v3s16 p0 = read_v3s16(L, 2);
+
+ treegen::TreeDef tree_def;
+ std::string trunk,leaves,fruit;
+ INodeDefManager *ndef = env->getGameDef()->ndef();
+
+ if(lua_istable(L, 3))
+ {
+ getstringfield(L, 3, "axiom", tree_def.initial_axiom);
+ getstringfield(L, 3, "rules_a", tree_def.rules_a);
+ getstringfield(L, 3, "rules_b", tree_def.rules_b);
+ getstringfield(L, 3, "rules_c", tree_def.rules_c);
+ getstringfield(L, 3, "rules_d", tree_def.rules_d);
+ getstringfield(L, 3, "trunk", trunk);
+ tree_def.trunknode=ndef->getId(trunk);
+ getstringfield(L, 3, "leaves", leaves);
+ tree_def.leavesnode=ndef->getId(leaves);
+ tree_def.leaves2_chance=0;
+ getstringfield(L, 3, "leaves2", leaves);
+ if (leaves !="")
+ {
+ tree_def.leaves2node=ndef->getId(leaves);
+ getintfield(L, 3, "leaves2_chance", tree_def.leaves2_chance);
+ }
+ getintfield(L, 3, "angle", tree_def.angle);
+ getintfield(L, 3, "iterations", tree_def.iterations);
+ getintfield(L, 3, "random_level", tree_def.iterations_random_level);
+ getstringfield(L, 3, "trunk_type", tree_def.trunk_type);
+ getboolfield(L, 3, "thin_branches", tree_def.thin_branches);
+ tree_def.fruit_chance=0;
+ getstringfield(L, 3, "fruit", fruit);
+ if (fruit != "")
+ {
+ tree_def.fruitnode=ndef->getId(fruit);
+ getintfield(L, 3, "fruit_chance",tree_def.fruit_chance);
+ }
+ getintfield(L, 3, "seed", tree_def.seed);
+ }
+ else
+ return 0;
+ treegen::spawn_ltree (env, p0, ndef, tree_def);
+ return 1;
+}
+
+
+EnvRef::EnvRef(ServerEnvironment *env):
+ m_env(env)
+{
+ //infostream<<"EnvRef created"<<std::endl;
+}
+
+EnvRef::~EnvRef()
+{
+ //infostream<<"EnvRef destructing"<<std::endl;
+}
+
+// Creates an EnvRef and leaves it on top of stack
+// Not callable from Lua; all references are created on the C side.
+void EnvRef::create(lua_State *L, ServerEnvironment *env)
+{
+ EnvRef *o = new EnvRef(env);
+ //infostream<<"EnvRef::create: o="<<o<<std::endl;
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
+void EnvRef::set_null(lua_State *L)
+{
+ EnvRef *o = checkobject(L, -1);
+ o->m_env = NULL;
+}
+
+void EnvRef::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Cannot be created from Lua
+ //lua_register(L, className, create_object);
+}
+
+const char EnvRef::className[] = "EnvRef";
+const luaL_reg EnvRef::methods[] = {
+ luamethod(EnvRef, set_node),
+ luamethod(EnvRef, add_node),
+ luamethod(EnvRef, remove_node),
+ luamethod(EnvRef, get_node),
+ luamethod(EnvRef, get_node_or_nil),
+ luamethod(EnvRef, get_node_light),
+ luamethod(EnvRef, place_node),
+ luamethod(EnvRef, dig_node),
+ luamethod(EnvRef, punch_node),
+ luamethod(EnvRef, add_entity),
+ luamethod(EnvRef, add_item),
+ luamethod(EnvRef, add_rat),
+ luamethod(EnvRef, add_firefly),
+ luamethod(EnvRef, get_meta),
+ luamethod(EnvRef, get_node_timer),
+ luamethod(EnvRef, get_player_by_name),
+ luamethod(EnvRef, get_objects_inside_radius),
+ luamethod(EnvRef, set_timeofday),
+ luamethod(EnvRef, get_timeofday),
+ luamethod(EnvRef, find_node_near),
+ luamethod(EnvRef, find_nodes_in_area),
+ luamethod(EnvRef, get_perlin),
+ luamethod(EnvRef, get_perlin_map),
+ luamethod(EnvRef, clear_objects),
+ luamethod(EnvRef, spawn_tree),
+ {0,0}
+};
+
+void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
+ u32 blockseed)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_environment_on_generated"<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.registered_on_generateds
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_on_generateds");
+ // Call callbacks
+ push_v3s16(L, minp);
+ push_v3s16(L, maxp);
+ lua_pushnumber(L, blockseed);
+ scriptapi_run_callbacks(L, 3, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void scriptapi_environment_step(lua_State *L, float dtime)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_environment_step"<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.registered_globalsteps
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_globalsteps");
+ // Call callbacks
+ lua_pushnumber(L, dtime);
+ scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ verbosestream<<"scriptapi_add_environment"<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Create EnvRef on stack
+ EnvRef::create(L, env);
+ int envref = lua_gettop(L);
+
+ // minetest.env = envref
+ lua_getglobal(L, "minetest");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushvalue(L, envref);
+ lua_setfield(L, -2, "env");
+
+ // Store environment as light userdata in registry
+ lua_pushlightuserdata(L, env);
+ lua_setfield(L, LUA_REGISTRYINDEX, "minetest_env");
+
+ /*
+ Add ActiveBlockModifiers to environment
+ */
+
+ // Get minetest.registered_abms
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_abms");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int registered_abms = lua_gettop(L);
+
+ if(lua_istable(L, registered_abms)){
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ int id = lua_tonumber(L, -2);
+ int current_abm = lua_gettop(L);
+
+ std::set<std::string> trigger_contents;
+ lua_getfield(L, current_abm, "nodenames");
+ if(lua_istable(L, -1)){
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
+ trigger_contents.insert(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ } else if(lua_isstring(L, -1)){
+ trigger_contents.insert(lua_tostring(L, -1));
+ }
+ lua_pop(L, 1);
+
+ std::set<std::string> required_neighbors;
+ lua_getfield(L, current_abm, "neighbors");
+ if(lua_istable(L, -1)){
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
+ required_neighbors.insert(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ } else if(lua_isstring(L, -1)){
+ required_neighbors.insert(lua_tostring(L, -1));
+ }
+ lua_pop(L, 1);
+
+ float trigger_interval = 10.0;
+ getfloatfield(L, current_abm, "interval", trigger_interval);
+
+ int trigger_chance = 50;
+ getintfield(L, current_abm, "chance", trigger_chance);
+
+ LuaABM *abm = new LuaABM(L, id, trigger_contents,
+ required_neighbors, trigger_interval, trigger_chance);
+
+ env->addActiveBlockModifier(abm);
+
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+}
diff --git a/src/scriptapi_env.h b/src/scriptapi_env.h
new file mode 100644
index 000000000..1599969a4
--- /dev/null
+++ b/src/scriptapi_env.h
@@ -0,0 +1,164 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_ENVIRONMENT_H_
+#define LUA_ENVIRONMENT_H_
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+#include "environment.h"
+
+/*
+ EnvRef
+*/
+
+class EnvRef
+{
+private:
+ ServerEnvironment *m_env;
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ static int gc_object(lua_State *L) ;
+
+ static EnvRef *checkobject(lua_State *L, int narg);
+
+ // Exported functions
+
+ // EnvRef:set_node(pos, node)
+ // pos = {x=num, y=num, z=num}
+ static int l_set_node(lua_State *L);
+
+ static int l_add_node(lua_State *L);
+
+ // EnvRef:remove_node(pos)
+ // pos = {x=num, y=num, z=num}
+ static int l_remove_node(lua_State *L);
+
+ // EnvRef:get_node(pos)
+ // pos = {x=num, y=num, z=num}
+ static int l_get_node(lua_State *L);
+
+ // EnvRef:get_node_or_nil(pos)
+ // pos = {x=num, y=num, z=num}
+ static int l_get_node_or_nil(lua_State *L);
+
+ // EnvRef:get_node_light(pos, timeofday)
+ // pos = {x=num, y=num, z=num}
+ // timeofday: nil = current time, 0 = night, 0.5 = day
+ static int l_get_node_light(lua_State *L);
+
+ // EnvRef:place_node(pos, node)
+ // pos = {x=num, y=num, z=num}
+ static int l_place_node(lua_State *L);
+
+ // EnvRef:dig_node(pos)
+ // pos = {x=num, y=num, z=num}
+ static int l_dig_node(lua_State *L);
+
+ // EnvRef:punch_node(pos)
+ // pos = {x=num, y=num, z=num}
+ static int l_punch_node(lua_State *L);
+
+ // EnvRef:get_meta(pos)
+ static int l_get_meta(lua_State *L);
+
+ // EnvRef:get_node_timer(pos)
+ static int l_get_node_timer(lua_State *L);
+
+ // EnvRef:add_entity(pos, entityname) -> ObjectRef or nil
+ // pos = {x=num, y=num, z=num}
+ static int l_add_entity(lua_State *L);
+
+ // EnvRef:add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
+ // pos = {x=num, y=num, z=num}
+ static int l_add_item(lua_State *L);
+
+ // EnvRef:add_rat(pos)
+ // pos = {x=num, y=num, z=num}
+ static int l_add_rat(lua_State *L);
+
+ // EnvRef:add_firefly(pos)
+ // pos = {x=num, y=num, z=num}
+ static int l_add_firefly(lua_State *L);
+
+ // EnvRef:get_player_by_name(name)
+ static int l_get_player_by_name(lua_State *L);
+
+ // EnvRef:get_objects_inside_radius(pos, radius)
+ static int l_get_objects_inside_radius(lua_State *L);
+
+ // EnvRef:set_timeofday(val)
+ // val = 0...1
+ static int l_set_timeofday(lua_State *L);
+
+ // EnvRef:get_timeofday() -> 0...1
+ static int l_get_timeofday(lua_State *L);
+
+ // EnvRef:find_node_near(pos, radius, nodenames) -> pos or nil
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_node_near(lua_State *L);
+
+ // EnvRef:find_nodes_in_area(minp, maxp, nodenames) -> list of positions
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_nodes_in_area(lua_State *L);
+
+ // EnvRef:get_perlin(seeddiff, octaves, persistence, scale)
+ // returns world-specific PerlinNoise
+ static int l_get_perlin(lua_State *L);
+
+ // EnvRef:get_perlin_map(noiseparams, size)
+ // returns world-specific PerlinNoiseMap
+ static int l_get_perlin_map(lua_State *L);
+
+ // EnvRef:clear_objects()
+ // clear all objects in the environment
+ static int l_clear_objects(lua_State *L);
+
+ static int l_spawn_tree(lua_State *L);
+
+public:
+ EnvRef(ServerEnvironment *env);
+
+ ~EnvRef();
+
+ // Creates an EnvRef and leaves it on top of stack
+ // Not callable from Lua; all references are created on the C side.
+ static void create(lua_State *L, ServerEnvironment *env);
+
+ static void set_null(lua_State *L);
+
+ static void Register(lua_State *L);
+};
+
+/*****************************************************************************/
+/* Minetest interface */
+/*****************************************************************************/
+// On environment step
+void scriptapi_environment_step(lua_State *L, float dtime);
+// After generating a piece of map
+void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
+ u32 blockseed);
+void scriptapi_add_environment(lua_State *L, ServerEnvironment *env);
+
+#endif /* LUA_ENVIRONMENT_H_ */
diff --git a/src/scriptapi_inventory.cpp b/src/scriptapi_inventory.cpp
new file mode 100644
index 000000000..bb40748db
--- /dev/null
+++ b/src/scriptapi_inventory.cpp
@@ -0,0 +1,726 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_inventory.h"
+#include "server.h"
+#include "script.h"
+#include "log.h"
+#include "scriptapi_types.h"
+#include "scriptapi_common.h"
+#include "scriptapi_inventory.h"
+#include "scriptapi_item.h"
+#include "scriptapi_object.h"
+
+
+/*
+ InvRef
+*/
+InvRef* InvRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(InvRef**)ud; // unbox pointer
+}
+
+Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
+{
+ return get_server(L)->getInventory(ref->m_loc);
+}
+
+InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
+ const char *listname)
+{
+ Inventory *inv = getinv(L, ref);
+ if(!inv)
+ return NULL;
+ return inv->getList(listname);
+}
+
+void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
+{
+ // Inform other things that the inventory has changed
+ get_server(L)->setInventoryModified(ref->m_loc);
+}
+
+// Exported functions
+
+// garbage collector
+int InvRef::gc_object(lua_State *L) {
+ InvRef *o = *(InvRef **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+// is_empty(self, listname) -> true/false
+int InvRef::l_is_empty(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list && list->getUsedSlots() > 0){
+ lua_pushboolean(L, false);
+ } else {
+ lua_pushboolean(L, true);
+ }
+ return 1;
+}
+
+// get_size(self, listname)
+int InvRef::l_get_size(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ lua_pushinteger(L, list->getSize());
+ } else {
+ lua_pushinteger(L, 0);
+ }
+ return 1;
+}
+
+// get_width(self, listname)
+int InvRef::l_get_width(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ lua_pushinteger(L, list->getWidth());
+ } else {
+ lua_pushinteger(L, 0);
+ }
+ return 1;
+}
+
+// set_size(self, listname, size)
+int InvRef::l_set_size(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ int newsize = luaL_checknumber(L, 3);
+ Inventory *inv = getinv(L, ref);
+ if(newsize == 0){
+ inv->deleteList(listname);
+ reportInventoryChange(L, ref);
+ return 0;
+ }
+ InventoryList *list = inv->getList(listname);
+ if(list){
+ list->setSize(newsize);
+ } else {
+ list = inv->addList(listname, newsize);
+ }
+ reportInventoryChange(L, ref);
+ return 0;
+}
+
+// set_width(self, listname, size)
+int InvRef::l_set_width(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ int newwidth = luaL_checknumber(L, 3);
+ Inventory *inv = getinv(L, ref);
+ InventoryList *list = inv->getList(listname);
+ if(list){
+ list->setWidth(newwidth);
+ } else {
+ return 0;
+ }
+ reportInventoryChange(L, ref);
+ return 0;
+}
+
+// get_stack(self, listname, i) -> itemstack
+int InvRef::l_get_stack(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ int i = luaL_checknumber(L, 3) - 1;
+ InventoryList *list = getlist(L, ref, listname);
+ ItemStack item;
+ if(list != NULL && i >= 0 && i < (int) list->getSize())
+ item = list->getItem(i);
+ LuaItemStack::create(L, item);
+ return 1;
+}
+
+// set_stack(self, listname, i, stack) -> true/false
+int InvRef::l_set_stack(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ int i = luaL_checknumber(L, 3) - 1;
+ ItemStack newitem = read_item(L, 4);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list != NULL && i >= 0 && i < (int) list->getSize()){
+ list->changeItem(i, newitem);
+ reportInventoryChange(L, ref);
+ lua_pushboolean(L, true);
+ } else {
+ lua_pushboolean(L, false);
+ }
+ return 1;
+}
+
+// get_list(self, listname) -> list or nil
+int InvRef::l_get_list(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ Inventory *inv = getinv(L, ref);
+ inventory_get_list_to_lua(inv, listname, L);
+ return 1;
+}
+
+// set_list(self, listname, list)
+int InvRef::l_set_list(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ Inventory *inv = getinv(L, ref);
+ InventoryList *list = inv->getList(listname);
+ if(list)
+ inventory_set_list_from_lua(inv, listname, L, 3,
+ list->getSize());
+ else
+ inventory_set_list_from_lua(inv, listname, L, 3);
+ reportInventoryChange(L, ref);
+ return 0;
+}
+
+// add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
+// Returns the leftover stack
+int InvRef::l_add_item(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ ItemStack item = read_item(L, 3);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ ItemStack leftover = list->addItem(item);
+ if(leftover.count != item.count)
+ reportInventoryChange(L, ref);
+ LuaItemStack::create(L, leftover);
+ } else {
+ LuaItemStack::create(L, item);
+ }
+ return 1;
+}
+
+// room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
+// Returns true if the item completely fits into the list
+int InvRef::l_room_for_item(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ ItemStack item = read_item(L, 3);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ lua_pushboolean(L, list->roomForItem(item));
+ } else {
+ lua_pushboolean(L, false);
+ }
+ return 1;
+}
+
+// contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
+// Returns true if the list contains the given count of the given item name
+int InvRef::l_contains_item(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ ItemStack item = read_item(L, 3);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ lua_pushboolean(L, list->containsItem(item));
+ } else {
+ lua_pushboolean(L, false);
+ }
+ return 1;
+}
+
+// remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
+// Returns the items that were actually removed
+int InvRef::l_remove_item(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ ItemStack item = read_item(L, 3);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ ItemStack removed = list->removeItem(item);
+ if(!removed.empty())
+ reportInventoryChange(L, ref);
+ LuaItemStack::create(L, removed);
+ } else {
+ LuaItemStack::create(L, ItemStack());
+ }
+ return 1;
+}
+
+// get_location() -> location (like minetest.get_inventory(location))
+int InvRef::l_get_location(lua_State *L)
+{
+ InvRef *ref = checkobject(L, 1);
+ const InventoryLocation &loc = ref->m_loc;
+ switch(loc.type){
+ case InventoryLocation::PLAYER:
+ lua_newtable(L);
+ lua_pushstring(L, "player");
+ lua_setfield(L, -2, "type");
+ lua_pushstring(L, loc.name.c_str());
+ lua_setfield(L, -2, "name");
+ return 1;
+ case InventoryLocation::NODEMETA:
+ lua_newtable(L);
+ lua_pushstring(L, "nodemeta");
+ lua_setfield(L, -2, "type");
+ push_v3s16(L, loc.p);
+ lua_setfield(L, -2, "name");
+ return 1;
+ case InventoryLocation::DETACHED:
+ lua_newtable(L);
+ lua_pushstring(L, "detached");
+ lua_setfield(L, -2, "type");
+ lua_pushstring(L, loc.name.c_str());
+ lua_setfield(L, -2, "name");
+ return 1;
+ case InventoryLocation::UNDEFINED:
+ case InventoryLocation::CURRENT_PLAYER:
+ break;
+ }
+ lua_newtable(L);
+ lua_pushstring(L, "undefined");
+ lua_setfield(L, -2, "type");
+ return 1;
+}
+
+
+InvRef::InvRef(const InventoryLocation &loc):
+ m_loc(loc)
+{
+}
+
+InvRef::~InvRef()
+{
+}
+
+// Creates an InvRef and leaves it on top of stack
+// Not callable from Lua; all references are created on the C side.
+void InvRef::create(lua_State *L, const InventoryLocation &loc)
+{
+ InvRef *o = new InvRef(loc);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+void InvRef::createPlayer(lua_State *L, Player *player)
+{
+ InventoryLocation loc;
+ loc.setPlayer(player->getName());
+ create(L, loc);
+}
+void InvRef::createNodeMeta(lua_State *L, v3s16 p)
+{
+ InventoryLocation loc;
+ loc.setNodeMeta(p);
+ create(L, loc);
+}
+
+void InvRef::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Cannot be created from Lua
+ //lua_register(L, className, create_object);
+}
+
+const char InvRef::className[] = "InvRef";
+const luaL_reg InvRef::methods[] = {
+ luamethod(InvRef, is_empty),
+ luamethod(InvRef, get_size),
+ luamethod(InvRef, set_size),
+ luamethod(InvRef, get_width),
+ luamethod(InvRef, set_width),
+ luamethod(InvRef, get_stack),
+ luamethod(InvRef, set_stack),
+ luamethod(InvRef, get_list),
+ luamethod(InvRef, set_list),
+ luamethod(InvRef, add_item),
+ luamethod(InvRef, room_for_item),
+ luamethod(InvRef, contains_item),
+ luamethod(InvRef, remove_item),
+ luamethod(InvRef, get_location),
+ {0,0}
+};
+
+void inventory_get_list_to_lua(Inventory *inv, const char *name,
+ lua_State *L)
+{
+ InventoryList *invlist = inv->getList(name);
+ if(invlist == NULL){
+ lua_pushnil(L);
+ return;
+ }
+ std::vector<ItemStack> items;
+ for(u32 i=0; i<invlist->getSize(); i++)
+ items.push_back(invlist->getItem(i));
+ push_items(L, items);
+}
+
+void inventory_set_list_from_lua(Inventory *inv, const char *name,
+ lua_State *L, int tableindex, int forcesize)
+{
+ if(tableindex < 0)
+ tableindex = lua_gettop(L) + 1 + tableindex;
+ // If nil, delete list
+ if(lua_isnil(L, tableindex)){
+ inv->deleteList(name);
+ return;
+ }
+ // Otherwise set list
+ std::vector<ItemStack> items = read_items(L, tableindex);
+ int listsize = (forcesize != -1) ? forcesize : items.size();
+ InventoryList *invlist = inv->addList(name, listsize);
+ int index = 0;
+ for(std::vector<ItemStack>::const_iterator
+ i = items.begin(); i != items.end(); i++){
+ if(forcesize != -1 && index == forcesize)
+ break;
+ invlist->changeItem(index, *i);
+ index++;
+ }
+ while(forcesize != -1 && index < forcesize){
+ invlist->deleteItem(index);
+ index++;
+ }
+}
+
+// get_inventory(location)
+int l_get_inventory(lua_State *L)
+{
+ InventoryLocation loc;
+
+ std::string type = checkstringfield(L, 1, "type");
+ if(type == "player"){
+ std::string name = checkstringfield(L, 1, "name");
+ loc.setPlayer(name);
+ } else if(type == "node"){
+ lua_getfield(L, 1, "pos");
+ v3s16 pos = check_v3s16(L, -1);
+ loc.setNodeMeta(pos);
+ } else if(type == "detached"){
+ std::string name = checkstringfield(L, 1, "name");
+ loc.setDetached(name);
+ }
+
+ if(get_server(L)->getInventory(loc) != NULL)
+ InvRef::create(L, loc);
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+/*
+ Detached inventory callbacks
+*/
+
+// Retrieves minetest.detached_inventories[name][callbackname]
+// If that is nil or on error, return false and stack is unchanged
+// If that is a function, returns true and pushes the
+// function onto the stack
+static bool get_detached_inventory_callback(lua_State *L,
+ const std::string &name, const char *callbackname)
+{
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "detached_inventories");
+ lua_remove(L, -2);
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, name.c_str());
+ lua_remove(L, -2);
+ // Should be a table
+ if(lua_type(L, -1) != LUA_TTABLE)
+ {
+ errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
+ lua_pop(L, 1);
+ return false;
+ }
+ lua_getfield(L, -1, callbackname);
+ lua_remove(L, -2);
+ // Should be a function or nil
+ if(lua_type(L, -1) == LUA_TFUNCTION)
+ {
+ return true;
+ }
+ else if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1);
+ return false;
+ }
+ else
+ {
+ errorstream<<"Detached inventory \""<<name<<"\" callback \""
+ <<callbackname<<"\" is not a function"<<std::endl;
+ lua_pop(L, 1);
+ return false;
+ }
+}
+
+// Return number of accepted items to be moved
+int scriptapi_detached_inventory_allow_move(lua_State *L,
+ const std::string &name,
+ const std::string &from_list, int from_index,
+ const std::string &to_list, int to_index,
+ int count, ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Push callback function on stack
+ if(!get_detached_inventory_callback(L, name, "allow_move"))
+ return count;
+
+ // function(inv, from_list, from_index, to_list, to_index, count, player)
+ // inv
+ InventoryLocation loc;
+ loc.setDetached(name);
+ InvRef::create(L, loc);
+ // from_list
+ lua_pushstring(L, from_list.c_str());
+ // from_index
+ lua_pushinteger(L, from_index + 1);
+ // to_list
+ lua_pushstring(L, to_list.c_str());
+ // to_index
+ lua_pushinteger(L, to_index + 1);
+ // count
+ lua_pushinteger(L, count);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 7, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnumber(L, -1))
+ throw LuaError(L, "allow_move should return a number");
+ return luaL_checkinteger(L, -1);
+}
+
+// Return number of accepted items to be put
+int scriptapi_detached_inventory_allow_put(lua_State *L,
+ const std::string &name,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Push callback function on stack
+ if(!get_detached_inventory_callback(L, name, "allow_put"))
+ return stack.count; // All will be accepted
+
+ // Call function(inv, listname, index, stack, player)
+ // inv
+ InventoryLocation loc;
+ loc.setDetached(name);
+ InvRef::create(L, loc);
+ // listname
+ lua_pushstring(L, listname.c_str());
+ // index
+ lua_pushinteger(L, index + 1);
+ // stack
+ LuaItemStack::create(L, stack);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnumber(L, -1))
+ throw LuaError(L, "allow_put should return a number");
+ return luaL_checkinteger(L, -1);
+}
+
+// Return number of accepted items to be taken
+int scriptapi_detached_inventory_allow_take(lua_State *L,
+ const std::string &name,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Push callback function on stack
+ if(!get_detached_inventory_callback(L, name, "allow_take"))
+ return stack.count; // All will be accepted
+
+ // Call function(inv, listname, index, stack, player)
+ // inv
+ InventoryLocation loc;
+ loc.setDetached(name);
+ InvRef::create(L, loc);
+ // listname
+ lua_pushstring(L, listname.c_str());
+ // index
+ lua_pushinteger(L, index + 1);
+ // stack
+ LuaItemStack::create(L, stack);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnumber(L, -1))
+ throw LuaError(L, "allow_take should return a number");
+ return luaL_checkinteger(L, -1);
+}
+
+// Report moved items
+void scriptapi_detached_inventory_on_move(lua_State *L,
+ const std::string &name,
+ const std::string &from_list, int from_index,
+ const std::string &to_list, int to_index,
+ int count, ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Push callback function on stack
+ if(!get_detached_inventory_callback(L, name, "on_move"))
+ return;
+
+ // function(inv, from_list, from_index, to_list, to_index, count, player)
+ // inv
+ InventoryLocation loc;
+ loc.setDetached(name);
+ InvRef::create(L, loc);
+ // from_list
+ lua_pushstring(L, from_list.c_str());
+ // from_index
+ lua_pushinteger(L, from_index + 1);
+ // to_list
+ lua_pushstring(L, to_list.c_str());
+ // to_index
+ lua_pushinteger(L, to_index + 1);
+ // count
+ lua_pushinteger(L, count);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 7, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+// Report put items
+void scriptapi_detached_inventory_on_put(lua_State *L,
+ const std::string &name,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Push callback function on stack
+ if(!get_detached_inventory_callback(L, name, "on_put"))
+ return;
+
+ // Call function(inv, listname, index, stack, player)
+ // inv
+ InventoryLocation loc;
+ loc.setDetached(name);
+ InvRef::create(L, loc);
+ // listname
+ lua_pushstring(L, listname.c_str());
+ // index
+ lua_pushinteger(L, index + 1);
+ // stack
+ LuaItemStack::create(L, stack);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+// Report taken items
+void scriptapi_detached_inventory_on_take(lua_State *L,
+ const std::string &name,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Push callback function on stack
+ if(!get_detached_inventory_callback(L, name, "on_take"))
+ return;
+
+ // Call function(inv, listname, index, stack, player)
+ // inv
+ InventoryLocation loc;
+ loc.setDetached(name);
+ InvRef::create(L, loc);
+ // listname
+ lua_pushstring(L, listname.c_str());
+ // index
+ lua_pushinteger(L, index + 1);
+ // stack
+ LuaItemStack::create(L, stack);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+// create_detached_inventory_raw(name)
+int l_create_detached_inventory_raw(lua_State *L)
+{
+ const char *name = luaL_checkstring(L, 1);
+ if(get_server(L)->createDetachedInventory(name) != NULL){
+ InventoryLocation loc;
+ loc.setDetached(name);
+ InvRef::create(L, loc);
+ }else{
+ lua_pushnil(L);
+ }
+ return 1;
+}
diff --git a/src/scriptapi_inventory.h b/src/scriptapi_inventory.h
new file mode 100644
index 000000000..14f4fe026
--- /dev/null
+++ b/src/scriptapi_inventory.h
@@ -0,0 +1,165 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_INVENTORY_H_
+#define LUA_INVENTORY_H_
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+#include "inventorymanager.h"
+#include "player.h"
+#include "serverobject.h"
+#include "inventory.h"
+
+/*
+ InvRef
+*/
+
+class InvRef
+{
+private:
+ InventoryLocation m_loc;
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ static InvRef *checkobject(lua_State *L, int narg);
+
+ static Inventory* getinv(lua_State *L, InvRef *ref);
+
+ static InventoryList* getlist(lua_State *L, InvRef *ref,
+ const char *listname);
+
+ static void reportInventoryChange(lua_State *L, InvRef *ref);
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ // is_empty(self, listname) -> true/false
+ static int l_is_empty(lua_State *L);
+
+ // get_size(self, listname)
+ static int l_get_size(lua_State *L);
+
+ // get_width(self, listname)
+ static int l_get_width(lua_State *L);
+
+ // set_size(self, listname, size)
+ static int l_set_size(lua_State *L);
+
+ // set_width(self, listname, size)
+ static int l_set_width(lua_State *L);
+
+ // get_stack(self, listname, i) -> itemstack
+ static int l_get_stack(lua_State *L);
+
+ // set_stack(self, listname, i, stack) -> true/false
+ static int l_set_stack(lua_State *L);
+
+ // get_list(self, listname) -> list or nil
+ static int l_get_list(lua_State *L);
+
+ // set_list(self, listname, list)
+ static int l_set_list(lua_State *L);
+
+ // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
+ // Returns the leftover stack
+ static int l_add_item(lua_State *L);
+
+ // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
+ // Returns true if the item completely fits into the list
+ static int l_room_for_item(lua_State *L);
+
+ // contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
+ // Returns true if the list contains the given count of the given item name
+ static int l_contains_item(lua_State *L);
+
+ // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
+ // Returns the items that were actually removed
+ static int l_remove_item(lua_State *L);
+
+ // get_location() -> location (like minetest.get_inventory(location))
+ static int l_get_location(lua_State *L);
+
+public:
+ InvRef(const InventoryLocation &loc);
+
+ ~InvRef();
+
+ // Creates an InvRef and leaves it on top of stack
+ // Not callable from Lua; all references are created on the C side.
+ static void create(lua_State *L, const InventoryLocation &loc);
+ static void createPlayer(lua_State *L, Player *player);
+ static void createNodeMeta(lua_State *L, v3s16 p);
+ static void Register(lua_State *L);
+};
+
+void inventory_get_list_to_lua(Inventory *inv, const char *name,lua_State *L);
+void inventory_set_list_from_lua(Inventory *inv, const char *name,
+ lua_State *L, int tableindex, int forcesize=-1);
+
+/*****************************************************************************/
+/* Minetest interface */
+/*****************************************************************************/
+/* Detached inventory callbacks */
+// Return number of accepted items to be moved
+int scriptapi_detached_inventory_allow_move(lua_State *L,
+ const std::string &name,
+ const std::string &from_list, int from_index,
+ const std::string &to_list, int to_index,
+ int count, ServerActiveObject *player);
+// Return number of accepted items to be put
+int scriptapi_detached_inventory_allow_put(lua_State *L,
+ const std::string &name,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player);
+// Return number of accepted items to be taken
+int scriptapi_detached_inventory_allow_take(lua_State *L,
+ const std::string &name,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player);
+// Report moved items
+void scriptapi_detached_inventory_on_move(lua_State *L,
+ const std::string &name,
+ const std::string &from_list, int from_index,
+ const std::string &to_list, int to_index,
+ int count, ServerActiveObject *player);
+// Report put items
+void scriptapi_detached_inventory_on_put(lua_State *L,
+ const std::string &name,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player);
+// Report taken items
+void scriptapi_detached_inventory_on_take(lua_State *L,
+ const std::string &name,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player);
+
+/*****************************************************************************/
+/* Mod API */
+/*****************************************************************************/
+int l_create_detached_inventory_raw(lua_State *L);
+int l_get_inventory(lua_State *L);
+
+#endif /* LUA_INVENTORY_H_ */
diff --git a/src/scriptapi_item.cpp b/src/scriptapi_item.cpp
new file mode 100644
index 000000000..b266d856d
--- /dev/null
+++ b/src/scriptapi_item.cpp
@@ -0,0 +1,718 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "server.h"
+#include "script.h"
+#include "tool.h"
+#include "nodedef.h"
+#include "util/pointedthing.h"
+#include "scriptapi_item.h"
+#include "scriptapi_types.h"
+#include "scriptapi_common.h"
+#include "scriptapi_object.h"
+#include "scriptapi_content.h"
+
+
+struct EnumString es_ItemType[] =
+{
+ {ITEM_NONE, "none"},
+ {ITEM_NODE, "node"},
+ {ITEM_CRAFT, "craft"},
+ {ITEM_TOOL, "tool"},
+ {0, NULL},
+};
+
+
+/*
+ ItemDefinition
+*/
+
+ItemDefinition read_item_definition(lua_State *L, int index,
+ ItemDefinition default_def)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ // Read the item definition
+ ItemDefinition def = default_def;
+
+ def.type = (ItemType)getenumfield(L, index, "type",
+ es_ItemType, ITEM_NONE);
+ getstringfield(L, index, "name", def.name);
+ getstringfield(L, index, "description", def.description);
+ getstringfield(L, index, "inventory_image", def.inventory_image);
+ getstringfield(L, index, "wield_image", def.wield_image);
+
+ lua_getfield(L, index, "wield_scale");
+ if(lua_istable(L, -1)){
+ def.wield_scale = check_v3f(L, -1);
+ }
+ lua_pop(L, 1);
+
+ def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
+ if(def.stack_max == 0)
+ def.stack_max = 1;
+
+ lua_getfield(L, index, "on_use");
+ def.usable = lua_isfunction(L, -1);
+ lua_pop(L, 1);
+
+ getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
+
+ warn_if_field_exists(L, index, "tool_digging_properties",
+ "deprecated: use tool_capabilities");
+
+ lua_getfield(L, index, "tool_capabilities");
+ if(lua_istable(L, -1)){
+ def.tool_capabilities = new ToolCapabilities(
+ read_tool_capabilities(L, -1));
+ }
+
+ // If name is "" (hand), ensure there are ToolCapabilities
+ // because it will be looked up there whenever any other item has
+ // no ToolCapabilities
+ if(def.name == "" && def.tool_capabilities == NULL){
+ def.tool_capabilities = new ToolCapabilities();
+ }
+
+ lua_getfield(L, index, "groups");
+ read_groups(L, -1, def.groups);
+ lua_pop(L, 1);
+
+ lua_getfield(L, index, "sounds");
+ if(lua_istable(L, -1)){
+ lua_getfield(L, -1, "place");
+ read_soundspec(L, -1, def.sound_place);
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
+ // Client shall immediately place this node when player places the item.
+ // Server will update the precise end result a moment later.
+ // "" = no prediction
+ getstringfield(L, index, "node_placement_prediction",
+ def.node_placement_prediction);
+
+ return def;
+}
+
+// register_item_raw({lots of stuff})
+int l_register_item_raw(lua_State *L)
+{
+ luaL_checktype(L, 1, LUA_TTABLE);
+ int table = 1;
+
+ // Get the writable item and node definition managers from the server
+ IWritableItemDefManager *idef =
+ get_server(L)->getWritableItemDefManager();
+ IWritableNodeDefManager *ndef =
+ get_server(L)->getWritableNodeDefManager();
+
+ // Check if name is defined
+ std::string name;
+ lua_getfield(L, table, "name");
+ if(lua_isstring(L, -1)){
+ name = lua_tostring(L, -1);
+ verbosestream<<"register_item_raw: "<<name<<std::endl;
+ } else {
+ throw LuaError(L, "register_item_raw: name is not defined or not a string");
+ }
+
+ // Check if on_use is defined
+
+ ItemDefinition def;
+ // Set a distinctive default value to check if this is set
+ def.node_placement_prediction = "__default";
+
+ // Read the item definition
+ def = read_item_definition(L, table, def);
+
+ // Default to having client-side placement prediction for nodes
+ // ("" in item definition sets it off)
+ if(def.node_placement_prediction == "__default"){
+ if(def.type == ITEM_NODE)
+ def.node_placement_prediction = name;
+ else
+ def.node_placement_prediction = "";
+ }
+
+ // Register item definition
+ idef->registerItem(def);
+
+ // Read the node definition (content features) and register it
+ if(def.type == ITEM_NODE)
+ {
+ ContentFeatures f = read_content_features(L, table);
+ ndef->set(f.name, f);
+ }
+
+ return 0; /* number of results */
+}
+
+// register_alias_raw(name, convert_to_name)
+int l_register_alias_raw(lua_State *L)
+{
+ std::string name = luaL_checkstring(L, 1);
+ std::string convert_to = luaL_checkstring(L, 2);
+
+ // Get the writable item definition manager from the server
+ IWritableItemDefManager *idef =
+ get_server(L)->getWritableItemDefManager();
+
+ idef->registerAlias(name, convert_to);
+
+ return 0; /* number of results */
+}
+
+// Retrieves minetest.registered_items[name][callbackname]
+// If that is nil or on error, return false and stack is unchanged
+// If that is a function, returns true and pushes the
+// function onto the stack
+// If minetest.registered_items[name] doesn't exist, minetest.nodedef_default
+// is tried instead so unknown items can still be manipulated to some degree
+bool get_item_callback(lua_State *L,
+ const char *name, const char *callbackname)
+{
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_items");
+ lua_remove(L, -2);
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, name);
+ lua_remove(L, -2);
+ // Should be a table
+ if(lua_type(L, -1) != LUA_TTABLE)
+ {
+ // Report error and clean up
+ errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
+ lua_pop(L, 1);
+
+ // Try minetest.nodedef_default instead
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "nodedef_default");
+ lua_remove(L, -2);
+ luaL_checktype(L, -1, LUA_TTABLE);
+ }
+ lua_getfield(L, -1, callbackname);
+ lua_remove(L, -2);
+ // Should be a function or nil
+ if(lua_type(L, -1) == LUA_TFUNCTION)
+ {
+ return true;
+ }
+ else if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1);
+ return false;
+ }
+ else
+ {
+ errorstream<<"Item \""<<name<<"\" callback \""
+ <<callbackname<<" is not a function"<<std::endl;
+ lua_pop(L, 1);
+ return false;
+ }
+}
+
+bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
+ ServerActiveObject *dropper, v3f pos)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Push callback function on stack
+ if(!get_item_callback(L, item.name.c_str(), "on_drop"))
+ return false;
+
+ // Call function
+ LuaItemStack::create(L, item);
+ objectref_get_or_create(L, dropper);
+ pushFloatPos(L, pos);
+ if(lua_pcall(L, 3, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnil(L, -1))
+ item = read_item(L, -1);
+ return true;
+}
+
+bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
+ ServerActiveObject *placer, const PointedThing &pointed)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Push callback function on stack
+ if(!get_item_callback(L, item.name.c_str(), "on_place"))
+ return false;
+
+ // Call function
+ LuaItemStack::create(L, item);
+ objectref_get_or_create(L, placer);
+ push_pointed_thing(L, pointed);
+ if(lua_pcall(L, 3, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnil(L, -1))
+ item = read_item(L, -1);
+ return true;
+}
+
+bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
+ ServerActiveObject *user, const PointedThing &pointed)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ // Push callback function on stack
+ if(!get_item_callback(L, item.name.c_str(), "on_use"))
+ return false;
+
+ // Call function
+ LuaItemStack::create(L, item);
+ objectref_get_or_create(L, user);
+ push_pointed_thing(L, pointed);
+ if(lua_pcall(L, 3, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnil(L, -1))
+ item = read_item(L, -1);
+ return true;
+}
+
+// garbage collector
+int LuaItemStack::gc_object(lua_State *L)
+{
+ LuaItemStack *o = *(LuaItemStack **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+// is_empty(self) -> true/false
+int LuaItemStack::l_is_empty(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushboolean(L, item.empty());
+ return 1;
+}
+
+// get_name(self) -> string
+int LuaItemStack::l_get_name(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushstring(L, item.name.c_str());
+ return 1;
+}
+
+// get_count(self) -> number
+int LuaItemStack::l_get_count(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.count);
+ return 1;
+}
+
+// get_wear(self) -> number
+int LuaItemStack::l_get_wear(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.wear);
+ return 1;
+}
+
+// get_metadata(self) -> string
+int LuaItemStack::l_get_metadata(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
+ return 1;
+}
+
+// clear(self) -> true
+int LuaItemStack::l_clear(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ o->m_stack.clear();
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// replace(self, itemstack or itemstring or table or nil) -> true
+int LuaItemStack::l_replace(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ o->m_stack = read_item(L, 2);
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// to_string(self) -> string
+int LuaItemStack::l_to_string(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ std::string itemstring = o->m_stack.getItemString();
+ lua_pushstring(L, itemstring.c_str());
+ return 1;
+}
+
+// to_table(self) -> table or nil
+int LuaItemStack::l_to_table(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ const ItemStack &item = o->m_stack;
+ if(item.empty())
+ {
+ lua_pushnil(L);
+ }
+ else
+ {
+ lua_newtable(L);
+ lua_pushstring(L, item.name.c_str());
+ lua_setfield(L, -2, "name");
+ lua_pushinteger(L, item.count);
+ lua_setfield(L, -2, "count");
+ lua_pushinteger(L, item.wear);
+ lua_setfield(L, -2, "wear");
+ lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
+ lua_setfield(L, -2, "metadata");
+ }
+ return 1;
+}
+
+// get_stack_max(self) -> number
+int LuaItemStack::l_get_stack_max(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.getStackMax(get_server(L)->idef()));
+ return 1;
+}
+
+// get_free_space(self) -> number
+int LuaItemStack::l_get_free_space(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.freeSpace(get_server(L)->idef()));
+ return 1;
+}
+
+// is_known(self) -> true/false
+// Checks if the item is defined.
+int LuaItemStack::l_is_known(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ bool is_known = item.isKnown(get_server(L)->idef());
+ lua_pushboolean(L, is_known);
+ return 1;
+}
+
+// get_definition(self) -> table
+// Returns the item definition table from minetest.registered_items,
+// or a fallback one (name="unknown")
+int LuaItemStack::l_get_definition(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+
+ // Get minetest.registered_items[name]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_items");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, item.name.c_str());
+ if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "unknown");
+ }
+ return 1;
+}
+
+// get_tool_capabilities(self) -> table
+// Returns the effective tool digging properties.
+// Returns those of the hand ("") if this item has none associated.
+int LuaItemStack::l_get_tool_capabilities(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ const ToolCapabilities &prop =
+ item.getToolCapabilities(get_server(L)->idef());
+ push_tool_capabilities(L, prop);
+ return 1;
+}
+
+// add_wear(self, amount) -> true/false
+// The range for "amount" is [0,65535]. Wear is only added if the item
+// is a tool. Adding wear might destroy the item.
+// Returns true if the item is (or was) a tool.
+int LuaItemStack::l_add_wear(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ int amount = lua_tointeger(L, 2);
+ bool result = item.addWear(amount, get_server(L)->idef());
+ lua_pushboolean(L, result);
+ return 1;
+}
+
+// add_item(self, itemstack or itemstring or table or nil) -> itemstack
+// Returns leftover item stack
+int LuaItemStack::l_add_item(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ ItemStack newitem = read_item(L, 2);
+ ItemStack leftover = item.addItem(newitem, get_server(L)->idef());
+ create(L, leftover);
+ return 1;
+}
+
+// item_fits(self, itemstack or itemstring or table or nil) -> true/false, itemstack
+// First return value is true iff the new item fits fully into the stack
+// Second return value is the would-be-left-over item stack
+int LuaItemStack::l_item_fits(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ ItemStack newitem = read_item(L, 2);
+ ItemStack restitem;
+ bool fits = item.itemFits(newitem, &restitem, get_server(L)->idef());
+ lua_pushboolean(L, fits); // first return value
+ create(L, restitem); // second return value
+ return 2;
+}
+
+// take_item(self, takecount=1) -> itemstack
+int LuaItemStack::l_take_item(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ u32 takecount = 1;
+ if(!lua_isnone(L, 2))
+ takecount = luaL_checkinteger(L, 2);
+ ItemStack taken = item.takeItem(takecount);
+ create(L, taken);
+ return 1;
+}
+
+// peek_item(self, peekcount=1) -> itemstack
+int LuaItemStack::l_peek_item(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ u32 peekcount = 1;
+ if(!lua_isnone(L, 2))
+ peekcount = lua_tointeger(L, 2);
+ ItemStack peekaboo = item.peekItem(peekcount);
+ create(L, peekaboo);
+ return 1;
+}
+
+LuaItemStack::LuaItemStack(const ItemStack &item):
+ m_stack(item)
+{
+}
+
+LuaItemStack::~LuaItemStack()
+{
+}
+
+const ItemStack& LuaItemStack::getItem() const
+{
+ return m_stack;
+}
+ItemStack& LuaItemStack::getItem()
+{
+ return m_stack;
+}
+
+// LuaItemStack(itemstack or itemstring or table or nil)
+// Creates an LuaItemStack and leaves it on top of stack
+int LuaItemStack::create_object(lua_State *L)
+{
+ ItemStack item = read_item(L, 1);
+ LuaItemStack *o = new LuaItemStack(item);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+// Not callable from Lua
+int LuaItemStack::create(lua_State *L, const ItemStack &item)
+{
+ LuaItemStack *o = new LuaItemStack(item);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+LuaItemStack* LuaItemStack::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(LuaItemStack**)ud; // unbox pointer
+}
+
+void LuaItemStack::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Can be created from Lua (LuaItemStack(itemstack or itemstring or table or nil))
+ lua_register(L, className, create_object);
+}
+
+const char LuaItemStack::className[] = "ItemStack";
+const luaL_reg LuaItemStack::methods[] = {
+ luamethod(LuaItemStack, is_empty),
+ luamethod(LuaItemStack, get_name),
+ luamethod(LuaItemStack, get_count),
+ luamethod(LuaItemStack, get_wear),
+ luamethod(LuaItemStack, get_metadata),
+ luamethod(LuaItemStack, clear),
+ luamethod(LuaItemStack, replace),
+ luamethod(LuaItemStack, to_string),
+ luamethod(LuaItemStack, to_table),
+ luamethod(LuaItemStack, get_stack_max),
+ luamethod(LuaItemStack, get_free_space),
+ luamethod(LuaItemStack, is_known),
+ luamethod(LuaItemStack, get_definition),
+ luamethod(LuaItemStack, get_tool_capabilities),
+ luamethod(LuaItemStack, add_wear),
+ luamethod(LuaItemStack, add_item),
+ luamethod(LuaItemStack, item_fits),
+ luamethod(LuaItemStack, take_item),
+ luamethod(LuaItemStack, peek_item),
+ {0,0}
+};
+
+ItemStack read_item(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ if(lua_isnil(L, index))
+ {
+ return ItemStack();
+ }
+ else if(lua_isuserdata(L, index))
+ {
+ // Convert from LuaItemStack
+ LuaItemStack *o = LuaItemStack::checkobject(L, index);
+ return o->getItem();
+ }
+ else if(lua_isstring(L, index))
+ {
+ // Convert from itemstring
+ std::string itemstring = lua_tostring(L, index);
+ IItemDefManager *idef = get_server(L)->idef();
+ try
+ {
+ ItemStack item;
+ item.deSerialize(itemstring, idef);
+ return item;
+ }
+ catch(SerializationError &e)
+ {
+ infostream<<"WARNING: unable to create item from itemstring"
+ <<": "<<itemstring<<std::endl;
+ return ItemStack();
+ }
+ }
+ else if(lua_istable(L, index))
+ {
+ // Convert from table
+ IItemDefManager *idef = get_server(L)->idef();
+ std::string name = getstringfield_default(L, index, "name", "");
+ int count = getintfield_default(L, index, "count", 1);
+ int wear = getintfield_default(L, index, "wear", 0);
+ std::string metadata = getstringfield_default(L, index, "metadata", "");
+ return ItemStack(name, count, wear, metadata, idef);
+ }
+ else
+ {
+ throw LuaError(L, "Expecting itemstack, itemstring, table or nil");
+ }
+}
+
+std::vector<ItemStack> read_items(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ std::vector<ItemStack> items;
+ luaL_checktype(L, index, LUA_TTABLE);
+ lua_pushnil(L);
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ items.push_back(read_item(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ return items;
+}
+
+// creates a table of ItemStacks
+void push_items(lua_State *L, const std::vector<ItemStack> &items)
+{
+ // Get the table insert function
+ lua_getglobal(L, "table");
+ lua_getfield(L, -1, "insert");
+ int table_insert = lua_gettop(L);
+ // Create and fill table
+ lua_newtable(L);
+ int table = lua_gettop(L);
+ for(u32 i=0; i<items.size(); i++){
+ ItemStack item = items[i];
+ lua_pushvalue(L, table_insert);
+ lua_pushvalue(L, table);
+ LuaItemStack::create(L, item);
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ }
+ lua_remove(L, -2); // Remove table
+ lua_remove(L, -2); // Remove insert
+}
diff --git a/src/scriptapi_item.h b/src/scriptapi_item.h
new file mode 100644
index 000000000..e0f213990
--- /dev/null
+++ b/src/scriptapi_item.h
@@ -0,0 +1,166 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_ITEM_H_
+#define LUA_ITEM_H_
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+#include <vector>
+
+#include "itemdef.h"
+#include "content_sao.h"
+#include "util/pointedthing.h"
+#include "inventory.h"
+
+#include "inventory.h"
+
+ItemStack read_item(lua_State *L, int index);
+std::vector<ItemStack> read_items(lua_State *L, int index);
+void push_items(lua_State *L, const std::vector<ItemStack> &items);
+
+class LuaItemStack
+{
+private:
+ ItemStack m_stack;
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ // is_empty(self) -> true/false
+ static int l_is_empty(lua_State *L);
+
+ // get_name(self) -> string
+ static int l_get_name(lua_State *L);
+
+ // get_count(self) -> number
+ static int l_get_count(lua_State *L);
+
+ // get_wear(self) -> number
+ static int l_get_wear(lua_State *L);
+
+ // get_metadata(self) -> string
+ static int l_get_metadata(lua_State *L);
+
+ // clear(self) -> true
+ static int l_clear(lua_State *L);
+
+ // replace(self, itemstack or itemstring or table or nil) -> true
+ static int l_replace(lua_State *L);
+
+ // to_string(self) -> string
+ static int l_to_string(lua_State *L);
+
+ // to_table(self) -> table or nil
+ static int l_to_table(lua_State *L);
+
+ // get_stack_max(self) -> number
+ static int l_get_stack_max(lua_State *L);
+
+ // get_free_space(self) -> number
+ static int l_get_free_space(lua_State *L);
+
+ // is_known(self) -> true/false
+ // Checks if the item is defined.
+ static int l_is_known(lua_State *L);
+
+ // get_definition(self) -> table
+ // Returns the item definition table from minetest.registered_items,
+ // or a fallback one (name="unknown")
+ static int l_get_definition(lua_State *L);
+
+ // get_tool_capabilities(self) -> table
+ // Returns the effective tool digging properties.
+ // Returns those of the hand ("") if this item has none associated.
+ static int l_get_tool_capabilities(lua_State *L);
+
+ // add_wear(self, amount) -> true/false
+ // The range for "amount" is [0,65535]. Wear is only added if the item
+ // is a tool. Adding wear might destroy the item.
+ // Returns true if the item is (or was) a tool.
+ static int l_add_wear(lua_State *L);
+
+ // add_item(self, itemstack or itemstring or table or nil) -> itemstack
+ // Returns leftover item stack
+ static int l_add_item(lua_State *L);
+
+ // item_fits(self, itemstack or itemstring or table or nil) -> true/false, itemstack
+ // First return value is true iff the new item fits fully into the stack
+ // Second return value is the would-be-left-over item stack
+ static int l_item_fits(lua_State *L);
+
+ // take_item(self, takecount=1) -> itemstack
+ static int l_take_item(lua_State *L);
+
+ // peek_item(self, peekcount=1) -> itemstack
+ static int l_peek_item(lua_State *L);
+
+public:
+ LuaItemStack(const ItemStack &item);
+ ~LuaItemStack();
+
+ const ItemStack& getItem() const;
+ ItemStack& getItem();
+
+ // LuaItemStack(itemstack or itemstring or table or nil)
+ // Creates an LuaItemStack and leaves it on top of stack
+ static int create_object(lua_State *L);
+ // Not callable from Lua
+ static int create(lua_State *L, const ItemStack &item);
+ static LuaItemStack* checkobject(lua_State *L, int narg);
+ static void Register(lua_State *L);
+
+};
+
+/*****************************************************************************/
+/* Mod API */
+/*****************************************************************************/
+int l_register_item_raw(lua_State *L);
+int l_register_alias_raw(lua_State *L);
+
+/*****************************************************************************/
+/* scriptapi internal */
+/*****************************************************************************/
+bool get_item_callback(lua_State *L,
+ const char *name, const char *callbackname);
+ItemDefinition read_item_definition(lua_State *L, int index,
+ ItemDefinition default_def = ItemDefinition());
+
+extern struct EnumString es_ItemType[];
+
+/*****************************************************************************/
+/* Minetest interface */
+/*****************************************************************************/
+bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
+ ServerActiveObject *dropper, v3f pos);
+bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
+ ServerActiveObject *placer, const PointedThing &pointed);
+bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
+ ServerActiveObject *user, const PointedThing &pointed);
+
+
+#endif /* LUA_ITEM_H_ */
diff --git a/src/scriptapi_node.cpp b/src/scriptapi_node.cpp
new file mode 100644
index 000000000..5ffcaeb9d
--- /dev/null
+++ b/src/scriptapi_node.cpp
@@ -0,0 +1,243 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_node.h"
+#include "util/pointedthing.h"
+#include "script.h"
+#include "scriptapi_common.h"
+#include "scriptapi_types.h"
+#include "scriptapi_item.h"
+#include "scriptapi_object.h"
+
+
+struct EnumString es_DrawType[] =
+{
+ {NDT_NORMAL, "normal"},
+ {NDT_AIRLIKE, "airlike"},
+ {NDT_LIQUID, "liquid"},
+ {NDT_FLOWINGLIQUID, "flowingliquid"},
+ {NDT_GLASSLIKE, "glasslike"},
+ {NDT_ALLFACES, "allfaces"},
+ {NDT_ALLFACES_OPTIONAL, "allfaces_optional"},
+ {NDT_TORCHLIKE, "torchlike"},
+ {NDT_SIGNLIKE, "signlike"},
+ {NDT_PLANTLIKE, "plantlike"},
+ {NDT_FENCELIKE, "fencelike"},
+ {NDT_RAILLIKE, "raillike"},
+ {NDT_NODEBOX, "nodebox"},
+ {0, NULL},
+};
+
+struct EnumString es_ContentParamType[] =
+{
+ {CPT_NONE, "none"},
+ {CPT_LIGHT, "light"},
+ {0, NULL},
+};
+
+struct EnumString es_ContentParamType2[] =
+{
+ {CPT2_NONE, "none"},
+ {CPT2_FULL, "full"},
+ {CPT2_FLOWINGLIQUID, "flowingliquid"},
+ {CPT2_FACEDIR, "facedir"},
+ {CPT2_WALLMOUNTED, "wallmounted"},
+ {0, NULL},
+};
+
+struct EnumString es_LiquidType[] =
+{
+ {LIQUID_NONE, "none"},
+ {LIQUID_FLOWING, "flowing"},
+ {LIQUID_SOURCE, "source"},
+ {0, NULL},
+};
+
+struct EnumString es_NodeBoxType[] =
+{
+ {NODEBOX_REGULAR, "regular"},
+ {NODEBOX_FIXED, "fixed"},
+ {NODEBOX_WALLMOUNTED, "wallmounted"},
+ {0, NULL},
+};
+
+
+bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node,
+ ServerActiveObject *puncher)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_punch"))
+ return false;
+
+ // Call function
+ push_v3s16(L, p);
+ pushnode(L, node, ndef);
+ objectref_get_or_create(L, puncher);
+ if(lua_pcall(L, 3, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return true;
+}
+
+bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
+ ServerActiveObject *digger)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_dig"))
+ return false;
+
+ // Call function
+ push_v3s16(L, p);
+ pushnode(L, node, ndef);
+ objectref_get_or_create(L, digger);
+ if(lua_pcall(L, 3, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return true;
+}
+
+void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_construct"))
+ return;
+
+ // Call function
+ push_v3s16(L, p);
+ if(lua_pcall(L, 1, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_destruct"))
+ return;
+
+ // Call function
+ push_v3s16(L, p);
+ if(lua_pcall(L, 1, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+void scriptapi_node_after_destruct(lua_State *L, v3s16 p, MapNode node)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "after_destruct"))
+ return;
+
+ // Call function
+ push_v3s16(L, p);
+ pushnode(L, node, ndef);
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+bool scriptapi_node_on_timer(lua_State *L, v3s16 p, MapNode node, f32 dtime)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_timer"))
+ return false;
+
+ // Call function
+ push_v3s16(L, p);
+ lua_pushnumber(L,dtime);
+ if(lua_pcall(L, 2, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if((bool)lua_isboolean(L,-1) && (bool)lua_toboolean(L,-1) == true)
+ return true;
+
+ return false;
+}
+
+void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
+ const std::string &formname,
+ const std::map<std::string, std::string> &fields,
+ ServerActiveObject *sender)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_receive_fields"))
+ return;
+
+ // Call function
+ // param 1
+ push_v3s16(L, p);
+ // param 2
+ lua_pushstring(L, formname.c_str());
+ // param 3
+ lua_newtable(L);
+ for(std::map<std::string, std::string>::const_iterator
+ i = fields.begin(); i != fields.end(); i++){
+ const std::string &name = i->first;
+ const std::string &value = i->second;
+ lua_pushstring(L, name.c_str());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
+ }
+ // param 4
+ objectref_get_or_create(L, sender);
+ if(lua_pcall(L, 4, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
diff --git a/src/scriptapi_node.h b/src/scriptapi_node.h
new file mode 100644
index 000000000..665b58bfc
--- /dev/null
+++ b/src/scriptapi_node.h
@@ -0,0 +1,55 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_NODE_H_
+#define LUA_NODE_H_
+
+#include <iostream>
+#include <map>
+
+extern "C" {
+#include <lua.h>
+}
+
+#include "content_sao.h"
+#include "map.h"
+
+/*****************************************************************************/
+/* Minetest interface */
+/*****************************************************************************/
+bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node,
+ ServerActiveObject *puncher);
+bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
+ ServerActiveObject *digger);
+void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node);
+void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node);
+void scriptapi_node_after_destruct(lua_State *L, v3s16 p, MapNode node);
+bool scriptapi_node_on_timer(lua_State *L, v3s16 p, MapNode node, f32 dtime);
+void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
+ const std::string &formname,
+ const std::map<std::string, std::string> &fields,
+ ServerActiveObject *sender);
+
+extern struct EnumString es_DrawType[];
+extern struct EnumString es_ContentParamType[];
+extern struct EnumString es_ContentParamType2[];
+extern struct EnumString es_LiquidType[];
+extern struct EnumString es_NodeBoxType[];
+
+#endif /* LUA_NODE_H_ */
diff --git a/src/scriptapi_nodemeta.cpp b/src/scriptapi_nodemeta.cpp
new file mode 100644
index 000000000..b66c9a023
--- /dev/null
+++ b/src/scriptapi_nodemeta.cpp
@@ -0,0 +1,571 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_nodemeta.h"
+#include "map.h"
+#include "script.h"
+#include "scriptapi_types.h"
+#include "scriptapi_inventory.h"
+#include "scriptapi_common.h"
+#include "scriptapi_item.h"
+#include "scriptapi_object.h"
+
+
+/*
+ NodeMetaRef
+*/
+NodeMetaRef* NodeMetaRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(NodeMetaRef**)ud; // unbox pointer
+}
+
+NodeMetadata* NodeMetaRef::getmeta(NodeMetaRef *ref, bool auto_create)
+{
+ NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
+ if(meta == NULL && auto_create)
+ {
+ meta = new NodeMetadata(ref->m_env->getGameDef());
+ ref->m_env->getMap().setNodeMetadata(ref->m_p, meta);
+ }
+ return meta;
+}
+
+void NodeMetaRef::reportMetadataChange(NodeMetaRef *ref)
+{
+ // NOTE: This same code is in rollback_interface.cpp
+ // Inform other things that the metadata has changed
+ v3s16 blockpos = getNodeBlockPos(ref->m_p);
+ MapEditEvent event;
+ event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
+ event.p = blockpos;
+ ref->m_env->getMap().dispatchEvent(&event);
+ // Set the block to be saved
+ MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos);
+ if(block)
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ "NodeMetaRef::reportMetadataChange");
+}
+
+// Exported functions
+
+// garbage collector
+int NodeMetaRef::gc_object(lua_State *L) {
+ NodeMetaRef *o = *(NodeMetaRef **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+// get_string(self, name)
+int NodeMetaRef::l_get_string(lua_State *L)
+{
+ NodeMetaRef *ref = checkobject(L, 1);
+ std::string name = luaL_checkstring(L, 2);
+
+ NodeMetadata *meta = getmeta(ref, false);
+ if(meta == NULL){
+ lua_pushlstring(L, "", 0);
+ return 1;
+ }
+ std::string str = meta->getString(name);
+ lua_pushlstring(L, str.c_str(), str.size());
+ return 1;
+}
+
+// set_string(self, name, var)
+int NodeMetaRef::l_set_string(lua_State *L)
+{
+ NodeMetaRef *ref = checkobject(L, 1);
+ std::string name = luaL_checkstring(L, 2);
+ size_t len = 0;
+ const char *s = lua_tolstring(L, 3, &len);
+ std::string str(s, len);
+
+ NodeMetadata *meta = getmeta(ref, !str.empty());
+ if(meta == NULL || str == meta->getString(name))
+ return 0;
+ meta->setString(name, str);
+ reportMetadataChange(ref);
+ return 0;
+}
+
+// get_int(self, name)
+int NodeMetaRef::l_get_int(lua_State *L)
+{
+ NodeMetaRef *ref = checkobject(L, 1);
+ std::string name = lua_tostring(L, 2);
+
+ NodeMetadata *meta = getmeta(ref, false);
+ if(meta == NULL){
+ lua_pushnumber(L, 0);
+ return 1;
+ }
+ std::string str = meta->getString(name);
+ lua_pushnumber(L, stoi(str));
+ return 1;
+}
+
+// set_int(self, name, var)
+int NodeMetaRef::l_set_int(lua_State *L)
+{
+ NodeMetaRef *ref = checkobject(L, 1);
+ std::string name = lua_tostring(L, 2);
+ int a = lua_tointeger(L, 3);
+ std::string str = itos(a);
+
+ NodeMetadata *meta = getmeta(ref, true);
+ if(meta == NULL || str == meta->getString(name))
+ return 0;
+ meta->setString(name, str);
+ reportMetadataChange(ref);
+ return 0;
+}
+
+// get_float(self, name)
+int NodeMetaRef::l_get_float(lua_State *L)
+{
+ NodeMetaRef *ref = checkobject(L, 1);
+ std::string name = lua_tostring(L, 2);
+
+ NodeMetadata *meta = getmeta(ref, false);
+ if(meta == NULL){
+ lua_pushnumber(L, 0);
+ return 1;
+ }
+ std::string str = meta->getString(name);
+ lua_pushnumber(L, stof(str));
+ return 1;
+}
+
+// set_float(self, name, var)
+int NodeMetaRef::l_set_float(lua_State *L)
+{
+ NodeMetaRef *ref = checkobject(L, 1);
+ std::string name = lua_tostring(L, 2);
+ float a = lua_tonumber(L, 3);
+ std::string str = ftos(a);
+
+ NodeMetadata *meta = getmeta(ref, true);
+ if(meta == NULL || str == meta->getString(name))
+ return 0;
+ meta->setString(name, str);
+ reportMetadataChange(ref);
+ return 0;
+}
+
+// get_inventory(self)
+int NodeMetaRef::l_get_inventory(lua_State *L)
+{
+ NodeMetaRef *ref = checkobject(L, 1);
+ getmeta(ref, true); // try to ensure the metadata exists
+ InvRef::createNodeMeta(L, ref->m_p);
+ return 1;
+}
+
+// to_table(self)
+int NodeMetaRef::l_to_table(lua_State *L)
+{
+ NodeMetaRef *ref = checkobject(L, 1);
+
+ NodeMetadata *meta = getmeta(ref, true);
+ if(meta == NULL){
+ lua_pushnil(L);
+ return 1;
+ }
+ lua_newtable(L);
+ // fields
+ lua_newtable(L);
+ {
+ std::map<std::string, std::string> fields = meta->getStrings();
+ for(std::map<std::string, std::string>::const_iterator
+ i = fields.begin(); i != fields.end(); i++){
+ const std::string &name = i->first;
+ const std::string &value = i->second;
+ lua_pushlstring(L, name.c_str(), name.size());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
+ }
+ }
+ lua_setfield(L, -2, "fields");
+ // inventory
+ lua_newtable(L);
+ Inventory *inv = meta->getInventory();
+ if(inv){
+ std::vector<const InventoryList*> lists = inv->getLists();
+ for(std::vector<const InventoryList*>::const_iterator
+ i = lists.begin(); i != lists.end(); i++){
+ inventory_get_list_to_lua(inv, (*i)->getName().c_str(), L);
+ lua_setfield(L, -2, (*i)->getName().c_str());
+ }
+ }
+ lua_setfield(L, -2, "inventory");
+ return 1;
+}
+
+// from_table(self, table)
+int NodeMetaRef::l_from_table(lua_State *L)
+{
+ NodeMetaRef *ref = checkobject(L, 1);
+ int base = 2;
+
+ if(lua_isnil(L, base)){
+ // No metadata
+ ref->m_env->getMap().removeNodeMetadata(ref->m_p);
+ lua_pushboolean(L, true);
+ return 1;
+ }
+
+ // Has metadata; clear old one first
+ ref->m_env->getMap().removeNodeMetadata(ref->m_p);
+ // Create new metadata
+ NodeMetadata *meta = getmeta(ref, true);
+ // Set fields
+ lua_getfield(L, base, "fields");
+ int fieldstable = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, fieldstable) != 0){
+ // key at index -2 and value at index -1
+ std::string name = lua_tostring(L, -2);
+ size_t cl;
+ const char *cs = lua_tolstring(L, -1, &cl);
+ std::string value(cs, cl);
+ meta->setString(name, value);
+ lua_pop(L, 1); // removes value, keeps key for next iteration
+ }
+ // Set inventory
+ Inventory *inv = meta->getInventory();
+ lua_getfield(L, base, "inventory");
+ int inventorytable = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, inventorytable) != 0){
+ // key at index -2 and value at index -1
+ std::string name = lua_tostring(L, -2);
+ inventory_set_list_from_lua(inv, name.c_str(), L, -1);
+ lua_pop(L, 1); // removes value, keeps key for next iteration
+ }
+ reportMetadataChange(ref);
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+
+NodeMetaRef::NodeMetaRef(v3s16 p, ServerEnvironment *env):
+ m_p(p),
+ m_env(env)
+{
+}
+
+NodeMetaRef::~NodeMetaRef()
+{
+}
+
+// Creates an NodeMetaRef and leaves it on top of stack
+// Not callable from Lua; all references are created on the C side.
+void NodeMetaRef::create(lua_State *L, v3s16 p, ServerEnvironment *env)
+{
+ NodeMetaRef *o = new NodeMetaRef(p, env);
+ //infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
+void NodeMetaRef::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Cannot be created from Lua
+ //lua_register(L, className, create_object);
+}
+
+const char NodeMetaRef::className[] = "NodeMetaRef";
+const luaL_reg NodeMetaRef::methods[] = {
+ luamethod(NodeMetaRef, get_string),
+ luamethod(NodeMetaRef, set_string),
+ luamethod(NodeMetaRef, get_int),
+ luamethod(NodeMetaRef, set_int),
+ luamethod(NodeMetaRef, get_float),
+ luamethod(NodeMetaRef, set_float),
+ luamethod(NodeMetaRef, get_inventory),
+ luamethod(NodeMetaRef, to_table),
+ luamethod(NodeMetaRef, from_table),
+ {0,0}
+};
+
+/*
+ Node metadata inventory callbacks
+*/
+
+// Return number of accepted items to be moved
+int scriptapi_nodemeta_inventory_allow_move(lua_State *L, v3s16 p,
+ const std::string &from_list, int from_index,
+ const std::string &to_list, int to_index,
+ int count, ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return 0;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(),
+ "allow_metadata_inventory_move"))
+ return count;
+
+ // function(pos, from_list, from_index, to_list, to_index, count, player)
+ // pos
+ push_v3s16(L, p);
+ // from_list
+ lua_pushstring(L, from_list.c_str());
+ // from_index
+ lua_pushinteger(L, from_index + 1);
+ // to_list
+ lua_pushstring(L, to_list.c_str());
+ // to_index
+ lua_pushinteger(L, to_index + 1);
+ // count
+ lua_pushinteger(L, count);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 7, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnumber(L, -1))
+ throw LuaError(L, "allow_metadata_inventory_move should return a number");
+ return luaL_checkinteger(L, -1);
+}
+
+// Return number of accepted items to be put
+int scriptapi_nodemeta_inventory_allow_put(lua_State *L, v3s16 p,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return 0;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(),
+ "allow_metadata_inventory_put"))
+ return stack.count;
+
+ // Call function(pos, listname, index, stack, player)
+ // pos
+ push_v3s16(L, p);
+ // listname
+ lua_pushstring(L, listname.c_str());
+ // index
+ lua_pushinteger(L, index + 1);
+ // stack
+ LuaItemStack::create(L, stack);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnumber(L, -1))
+ throw LuaError(L, "allow_metadata_inventory_put should return a number");
+ return luaL_checkinteger(L, -1);
+}
+
+// Return number of accepted items to be taken
+int scriptapi_nodemeta_inventory_allow_take(lua_State *L, v3s16 p,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return 0;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(),
+ "allow_metadata_inventory_take"))
+ return stack.count;
+
+ // Call function(pos, listname, index, count, player)
+ // pos
+ push_v3s16(L, p);
+ // listname
+ lua_pushstring(L, listname.c_str());
+ // index
+ lua_pushinteger(L, index + 1);
+ // stack
+ LuaItemStack::create(L, stack);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnumber(L, -1))
+ throw LuaError(L, "allow_metadata_inventory_take should return a number");
+ return luaL_checkinteger(L, -1);
+}
+
+// Report moved items
+void scriptapi_nodemeta_inventory_on_move(lua_State *L, v3s16 p,
+ const std::string &from_list, int from_index,
+ const std::string &to_list, int to_index,
+ int count, ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(),
+ "on_metadata_inventory_move"))
+ return;
+
+ // function(pos, from_list, from_index, to_list, to_index, count, player)
+ // pos
+ push_v3s16(L, p);
+ // from_list
+ lua_pushstring(L, from_list.c_str());
+ // from_index
+ lua_pushinteger(L, from_index + 1);
+ // to_list
+ lua_pushstring(L, to_list.c_str());
+ // to_index
+ lua_pushinteger(L, to_index + 1);
+ // count
+ lua_pushinteger(L, count);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 7, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+// Report put items
+void scriptapi_nodemeta_inventory_on_put(lua_State *L, v3s16 p,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(),
+ "on_metadata_inventory_put"))
+ return;
+
+ // Call function(pos, listname, index, stack, player)
+ // pos
+ push_v3s16(L, p);
+ // listname
+ lua_pushstring(L, listname.c_str());
+ // index
+ lua_pushinteger(L, index + 1);
+ // stack
+ LuaItemStack::create(L, stack);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+// Report taken items
+void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // If node doesn't exist, we don't know what callback to call
+ MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+ if(node.getContent() == CONTENT_IGNORE)
+ return;
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(),
+ "on_metadata_inventory_take"))
+ return;
+
+ // Call function(pos, listname, index, stack, player)
+ // pos
+ push_v3s16(L, p);
+ // listname
+ lua_pushstring(L, listname.c_str());
+ // index
+ lua_pushinteger(L, index + 1);
+ // stack
+ LuaItemStack::create(L, stack);
+ // player
+ objectref_get_or_create(L, player);
+ if(lua_pcall(L, 5, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
diff --git a/src/scriptapi_nodemeta.h b/src/scriptapi_nodemeta.h
new file mode 100644
index 000000000..017abe181
--- /dev/null
+++ b/src/scriptapi_nodemeta.h
@@ -0,0 +1,123 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef LUA_NODEMETA_H_
+#define LUA_NODEMETA_H_
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+#include "environment.h"
+#include "nodemetadata.h"
+
+/*
+ NodeMetaRef
+*/
+
+class NodeMetaRef
+{
+private:
+ v3s16 m_p;
+ ServerEnvironment *m_env;
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ static NodeMetaRef *checkobject(lua_State *L, int narg);
+
+ static NodeMetadata* getmeta(NodeMetaRef *ref, bool auto_create);
+
+ static void reportMetadataChange(NodeMetaRef *ref);
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ // get_string(self, name)
+ static int l_get_string(lua_State *L);
+
+ // set_string(self, name, var)
+ static int l_set_string(lua_State *L);
+
+ // get_int(self, name)
+ static int l_get_int(lua_State *L);
+
+ // set_int(self, name, var)
+ static int l_set_int(lua_State *L);
+
+ // get_float(self, name)
+ static int l_get_float(lua_State *L);
+
+ // set_float(self, name, var)
+ static int l_set_float(lua_State *L);
+
+ // get_inventory(self)
+ static int l_get_inventory(lua_State *L);
+
+ // to_table(self)
+ static int l_to_table(lua_State *L);
+
+ // from_table(self, table)
+ static int l_from_table(lua_State *L);
+
+public:
+ NodeMetaRef(v3s16 p, ServerEnvironment *env);
+
+ ~NodeMetaRef();
+
+ // Creates an NodeMetaRef and leaves it on top of stack
+ // Not callable from Lua; all references are created on the C side.
+ static void create(lua_State *L, v3s16 p, ServerEnvironment *env);
+
+ static void Register(lua_State *L);
+};
+
+/*****************************************************************************/
+/* Minetest interface */
+/*****************************************************************************/
+// Return number of accepted items to be moved
+int scriptapi_nodemeta_inventory_allow_move(lua_State *L, v3s16 p,
+ const std::string &from_list, int from_index,
+ const std::string &to_list, int to_index,
+ int count, ServerActiveObject *player);
+// Return number of accepted items to be put
+int scriptapi_nodemeta_inventory_allow_put(lua_State *L, v3s16 p,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player);
+// Return number of accepted items to be taken
+int scriptapi_nodemeta_inventory_allow_take(lua_State *L, v3s16 p,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player);
+// Report moved items
+void scriptapi_nodemeta_inventory_on_move(lua_State *L, v3s16 p,
+ const std::string &from_list, int from_index,
+ const std::string &to_list, int to_index,
+ int count, ServerActiveObject *player);
+// Report put items
+void scriptapi_nodemeta_inventory_on_put(lua_State *L, v3s16 p,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player);
+// Report taken items
+void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
+ const std::string &listname, int index, ItemStack &stack,
+ ServerActiveObject *player);
+
+#endif //LUA_NODEMETA_H_
diff --git a/src/scriptapi_nodetimer.cpp b/src/scriptapi_nodetimer.cpp
new file mode 100644
index 000000000..5e3289aee
--- /dev/null
+++ b/src/scriptapi_nodetimer.cpp
@@ -0,0 +1,166 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_nodetimer.h"
+#include "map.h"
+
+
+int NodeTimerRef::gc_object(lua_State *L) {
+ NodeTimerRef *o = *(NodeTimerRef **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+NodeTimerRef* NodeTimerRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(NodeTimerRef**)ud; // unbox pointer
+}
+
+int NodeTimerRef::l_set(lua_State *L)
+{
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ f32 t = luaL_checknumber(L,2);
+ f32 e = luaL_checknumber(L,3);
+ env->getMap().setNodeTimer(o->m_p,NodeTimer(t,e));
+ return 0;
+}
+
+int NodeTimerRef::l_start(lua_State *L)
+{
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ f32 t = luaL_checknumber(L,2);
+ env->getMap().setNodeTimer(o->m_p,NodeTimer(t,0));
+ return 0;
+}
+
+int NodeTimerRef::l_stop(lua_State *L)
+{
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ env->getMap().removeNodeTimer(o->m_p);
+ return 0;
+}
+
+int NodeTimerRef::l_is_started(lua_State *L)
+{
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ NodeTimer t = env->getMap().getNodeTimer(o->m_p);
+ lua_pushboolean(L,(t.timeout != 0));
+ return 1;
+}
+
+int NodeTimerRef::l_get_timeout(lua_State *L)
+{
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ NodeTimer t = env->getMap().getNodeTimer(o->m_p);
+ lua_pushnumber(L,t.timeout);
+ return 1;
+}
+
+int NodeTimerRef::l_get_elapsed(lua_State *L)
+{
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ NodeTimer t = env->getMap().getNodeTimer(o->m_p);
+ lua_pushnumber(L,t.elapsed);
+ return 1;
+}
+
+
+NodeTimerRef::NodeTimerRef(v3s16 p, ServerEnvironment *env):
+ m_p(p),
+ m_env(env)
+{
+}
+
+NodeTimerRef::~NodeTimerRef()
+{
+}
+
+// Creates an NodeTimerRef and leaves it on top of stack
+// Not callable from Lua; all references are created on the C side.
+void NodeTimerRef::create(lua_State *L, v3s16 p, ServerEnvironment *env)
+{
+ NodeTimerRef *o = new NodeTimerRef(p, env);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
+void NodeTimerRef::set_null(lua_State *L)
+{
+ NodeTimerRef *o = checkobject(L, -1);
+ o->m_env = NULL;
+}
+
+void NodeTimerRef::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Cannot be created from Lua
+ //lua_register(L, className, create_object);
+}
+
+const char NodeTimerRef::className[] = "NodeTimerRef";
+const luaL_reg NodeTimerRef::methods[] = {
+ luamethod(NodeTimerRef, start),
+ luamethod(NodeTimerRef, set),
+ luamethod(NodeTimerRef, stop),
+ luamethod(NodeTimerRef, is_started),
+ luamethod(NodeTimerRef, get_timeout),
+ luamethod(NodeTimerRef, get_elapsed),
+ {0,0}
+};
diff --git a/src/scriptapi_nodetimer.h b/src/scriptapi_nodetimer.h
new file mode 100644
index 000000000..a4536d947
--- /dev/null
+++ b/src/scriptapi_nodetimer.h
@@ -0,0 +1,70 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_NODETIMER_H_
+#define LUA_NODETIMER_H_
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+#include "environment.h"
+
+class NodeTimerRef
+{
+private:
+ v3s16 m_p;
+ ServerEnvironment *m_env;
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ static int gc_object(lua_State *L);
+
+ static NodeTimerRef *checkobject(lua_State *L, int narg);
+
+ static int l_set(lua_State *L);
+
+ static int l_start(lua_State *L);
+
+ static int l_stop(lua_State *L);
+
+ static int l_is_started(lua_State *L);
+
+ static int l_get_timeout(lua_State *L);
+
+ static int l_get_elapsed(lua_State *L);
+
+public:
+ NodeTimerRef(v3s16 p, ServerEnvironment *env);
+ ~NodeTimerRef();
+
+ // Creates an NodeTimerRef and leaves it on top of stack
+ // Not callable from Lua; all references are created on the C side.
+ static void create(lua_State *L, v3s16 p, ServerEnvironment *env);
+
+ static void set_null(lua_State *L);
+
+ static void Register(lua_State *L);
+};
+
+
+
+#endif /* LUA_NODETIMER_H_ */
diff --git a/src/scriptapi_noise.cpp b/src/scriptapi_noise.cpp
new file mode 100644
index 000000000..2c1a83c4c
--- /dev/null
+++ b/src/scriptapi_noise.cpp
@@ -0,0 +1,388 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_noise.h"
+#include "scriptapi_types.h"
+#include "script.h"
+
+// garbage collector
+int LuaPerlinNoise::gc_object(lua_State *L)
+{
+ LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+int LuaPerlinNoise::l_get2d(lua_State *L)
+{
+ LuaPerlinNoise *o = checkobject(L, 1);
+ v2f pos2d = read_v2f(L,2);
+ lua_Number val = noise2d_perlin(pos2d.X/o->scale, pos2d.Y/o->scale, o->seed, o->octaves, o->persistence);
+ lua_pushnumber(L, val);
+ return 1;
+}
+int LuaPerlinNoise::l_get3d(lua_State *L)
+{
+ LuaPerlinNoise *o = checkobject(L, 1);
+ v3f pos3d = read_v3f(L,2);
+ lua_Number val = noise3d_perlin(pos3d.X/o->scale, pos3d.Y/o->scale, pos3d.Z/o->scale, o->seed, o->octaves, o->persistence);
+ lua_pushnumber(L, val);
+ return 1;
+}
+
+
+LuaPerlinNoise::LuaPerlinNoise(int a_seed, int a_octaves, float a_persistence,
+ float a_scale):
+ seed(a_seed),
+ octaves(a_octaves),
+ persistence(a_persistence),
+ scale(a_scale)
+{
+}
+
+LuaPerlinNoise::~LuaPerlinNoise()
+{
+}
+
+// LuaPerlinNoise(seed, octaves, persistence, scale)
+// Creates an LuaPerlinNoise and leaves it on top of stack
+int LuaPerlinNoise::create_object(lua_State *L)
+{
+ int seed = luaL_checkint(L, 1);
+ int octaves = luaL_checkint(L, 2);
+ float persistence = luaL_checknumber(L, 3);
+ float scale = luaL_checknumber(L, 4);
+ LuaPerlinNoise *o = new LuaPerlinNoise(seed, octaves, persistence, scale);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+LuaPerlinNoise* LuaPerlinNoise::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(LuaPerlinNoise**)ud; // unbox pointer
+}
+
+void LuaPerlinNoise::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Can be created from Lua (PerlinNoise(seed, octaves, persistence)
+ lua_register(L, className, create_object);
+}
+
+const char LuaPerlinNoise::className[] = "PerlinNoise";
+const luaL_reg LuaPerlinNoise::methods[] = {
+ luamethod(LuaPerlinNoise, get2d),
+ luamethod(LuaPerlinNoise, get3d),
+ {0,0}
+};
+
+/*
+ PerlinNoiseMap
+ */
+
+
+int LuaPerlinNoiseMap::gc_object(lua_State *L)
+{
+ LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+int LuaPerlinNoiseMap::l_get2dMap(lua_State *L)
+{
+ int i = 0;
+
+ LuaPerlinNoiseMap *o = checkobject(L, 1);
+ v2f p = read_v2f(L, 2);
+
+ Noise *n = o->noise;
+ n->perlinMap2D(p.X, p.Y);
+
+ lua_newtable(L);
+ for (int y = 0; y != n->sy; y++) {
+ lua_newtable(L);
+ for (int x = 0; x != n->sx; x++) {
+ float noiseval = n->np->offset + n->np->scale * n->result[i++];
+ lua_pushnumber(L, noiseval);
+ lua_rawseti(L, -2, x + 1);
+ }
+ lua_rawseti(L, -2, y + 1);
+ }
+ return 1;
+}
+
+int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
+{
+ int i = 0;
+
+ LuaPerlinNoiseMap *o = checkobject(L, 1);
+ v3f p = read_v3f(L, 2);
+
+ Noise *n = o->noise;
+ n->perlinMap3D(p.X, p.Y, p.Z);
+
+ lua_newtable(L);
+ for (int z = 0; z != n->sz; z++) {
+ lua_newtable(L);
+ for (int y = 0; y != n->sy; y++) {
+ lua_newtable(L);
+ for (int x = 0; x != n->sx; x++) {
+ lua_pushnumber(L, n->np->offset + n->np->scale * n->result[i++]);
+ lua_rawseti(L, -2, x + 1);
+ }
+ lua_rawseti(L, -2, y + 1);
+ }
+ lua_rawseti(L, -2, z + 1);
+ }
+ return 1;
+}
+
+LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size) {
+ noise = new Noise(np, seed, size.X, size.Y, size.Z);
+}
+
+LuaPerlinNoiseMap::~LuaPerlinNoiseMap()
+{
+ delete noise->np;
+ delete noise;
+}
+
+// LuaPerlinNoiseMap(np, size)
+// Creates an LuaPerlinNoiseMap and leaves it on top of stack
+int LuaPerlinNoiseMap::create_object(lua_State *L)
+{
+ NoiseParams *np = read_noiseparams(L, 1);
+ if (!np)
+ return 0;
+ v3s16 size = read_v3s16(L, 2);
+
+ LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(np, 0, size);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+LuaPerlinNoiseMap* LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud)
+ luaL_typerror(L, narg, className);
+
+ return *(LuaPerlinNoiseMap **)ud; // unbox pointer
+}
+
+void LuaPerlinNoiseMap::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Can be created from Lua (PerlinNoiseMap(np, size)
+ lua_register(L, className, create_object);
+}
+
+const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
+const luaL_reg LuaPerlinNoiseMap::methods[] = {
+ luamethod(LuaPerlinNoiseMap, get2dMap),
+ luamethod(LuaPerlinNoiseMap, get3dMap),
+ {0,0}
+};
+
+/*
+ NoiseParams
+*/
+NoiseParams *read_noiseparams(lua_State *L, int index)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ if (!lua_istable(L, index))
+ return NULL;
+
+ NoiseParams *np = new NoiseParams;
+
+ np->offset = getfloatfield_default(L, index, "offset", 0.0);
+ np->scale = getfloatfield_default(L, index, "scale", 0.0);
+ lua_getfield(L, index, "spread");
+ np->spread = read_v3f(L, -1);
+ lua_pop(L, 1);
+ np->seed = getintfield_default(L, index, "seed", 0);
+ np->octaves = getintfield_default(L, index, "octaves", 0);
+ np->persist = getfloatfield_default(L, index, "persist", 0.0);
+
+ return np;
+}
+
+
+/*
+ LuaPseudoRandom
+*/
+
+// garbage collector
+int LuaPseudoRandom::gc_object(lua_State *L)
+{
+ LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+// next(self, min=0, max=32767) -> get next value
+int LuaPseudoRandom::l_next(lua_State *L)
+{
+ LuaPseudoRandom *o = checkobject(L, 1);
+ int min = 0;
+ int max = 32767;
+ lua_settop(L, 3); // Fill 2 and 3 with nil if they don't exist
+ if(!lua_isnil(L, 2))
+ min = luaL_checkinteger(L, 2);
+ if(!lua_isnil(L, 3))
+ max = luaL_checkinteger(L, 3);
+ if(max < min){
+ errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
+ throw LuaError(L, "PseudoRandom.next(): max < min");
+ }
+ if(max - min != 32767 && max - min > 32767/5)
+ throw LuaError(L, "PseudoRandom.next() max-min is not 32767 and is > 32768/5. This is disallowed due to the bad random distribution the implementation would otherwise make.");
+ PseudoRandom &pseudo = o->m_pseudo;
+ int val = pseudo.next();
+ val = (val % (max-min+1)) + min;
+ lua_pushinteger(L, val);
+ return 1;
+}
+
+
+LuaPseudoRandom::LuaPseudoRandom(int seed):
+ m_pseudo(seed)
+{
+}
+
+LuaPseudoRandom::~LuaPseudoRandom()
+{
+}
+
+const PseudoRandom& LuaPseudoRandom::getItem() const
+{
+ return m_pseudo;
+}
+PseudoRandom& LuaPseudoRandom::getItem()
+{
+ return m_pseudo;
+}
+
+// LuaPseudoRandom(seed)
+// Creates an LuaPseudoRandom and leaves it on top of stack
+int LuaPseudoRandom::create_object(lua_State *L)
+{
+ int seed = luaL_checknumber(L, 1);
+ LuaPseudoRandom *o = new LuaPseudoRandom(seed);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+LuaPseudoRandom* LuaPseudoRandom::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(LuaPseudoRandom**)ud; // unbox pointer
+}
+
+void LuaPseudoRandom::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Can be created from Lua (LuaPseudoRandom(seed))
+ lua_register(L, className, create_object);
+}
+
+const char LuaPseudoRandom::className[] = "PseudoRandom";
+const luaL_reg LuaPseudoRandom::methods[] = {
+ luamethod(LuaPseudoRandom, next),
+ {0,0}
+};
diff --git a/src/scriptapi_noise.h b/src/scriptapi_noise.h
new file mode 100644
index 000000000..a02383fde
--- /dev/null
+++ b/src/scriptapi_noise.h
@@ -0,0 +1,133 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_PERLIN_H_
+#define LUA_PERLIN_H_
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+#include "noise.h"
+
+class LuaPerlinNoise
+{
+private:
+ int seed;
+ int octaves;
+ float persistence;
+ float scale;
+ static const char className[];
+ static const luaL_reg methods[];
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ static int l_get2d(lua_State *L);
+ static int l_get3d(lua_State *L);
+
+public:
+ LuaPerlinNoise(int a_seed, int a_octaves, float a_persistence,
+ float a_scale);
+
+ ~LuaPerlinNoise();
+
+ // LuaPerlinNoise(seed, octaves, persistence, scale)
+ // Creates an LuaPerlinNoise and leaves it on top of stack
+ static int create_object(lua_State *L);
+
+ static LuaPerlinNoise* checkobject(lua_State *L, int narg);
+
+ static void Register(lua_State *L);
+};
+
+/*
+ PerlinNoiseMap
+ */
+class LuaPerlinNoiseMap
+{
+private:
+ Noise *noise;
+ static const char className[];
+ static const luaL_reg methods[];
+
+ static int gc_object(lua_State *L);
+
+ static int l_get2dMap(lua_State *L);
+
+ static int l_get3dMap(lua_State *L);
+
+public:
+ LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size);
+
+ ~LuaPerlinNoiseMap();
+
+ // LuaPerlinNoiseMap(np, size)
+ // Creates an LuaPerlinNoiseMap and leaves it on top of stack
+ static int create_object(lua_State *L);
+
+ static LuaPerlinNoiseMap *checkobject(lua_State *L, int narg);
+
+ static void Register(lua_State *L);
+};
+
+/*
+ LuaPseudoRandom
+*/
+
+
+class LuaPseudoRandom
+{
+private:
+ PseudoRandom m_pseudo;
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ // next(self, min=0, max=32767) -> get next value
+ static int l_next(lua_State *L);
+
+public:
+ LuaPseudoRandom(int seed);
+
+ ~LuaPseudoRandom();
+
+ const PseudoRandom& getItem() const;
+ PseudoRandom& getItem();
+
+ // LuaPseudoRandom(seed)
+ // Creates an LuaPseudoRandom and leaves it on top of stack
+ static int create_object(lua_State *L);
+
+ static LuaPseudoRandom* checkobject(lua_State *L, int narg);
+
+ static void Register(lua_State *L);
+};
+
+NoiseParams *read_noiseparams(lua_State *L, int index);
+
+#endif /* LUA_PERLIN_H_ */
diff --git a/src/scriptapi_object.cpp b/src/scriptapi_object.cpp
new file mode 100644
index 000000000..a0f93cbba
--- /dev/null
+++ b/src/scriptapi_object.cpp
@@ -0,0 +1,945 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_object.h"
+#include "log.h"
+#include "tool.h"
+#include "scriptapi_types.h"
+#include "scriptapi_inventory.h"
+#include "scriptapi_item.h"
+#include "scriptapi_entity.h"
+#include "scriptapi_common.h"
+
+/*
+ ObjectRef
+*/
+
+
+ObjectRef* ObjectRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(ObjectRef**)ud; // unbox pointer
+}
+
+ServerActiveObject* ObjectRef::getobject(ObjectRef *ref)
+{
+ ServerActiveObject *co = ref->m_object;
+ return co;
+}
+
+LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref)
+{
+ ServerActiveObject *obj = getobject(ref);
+ if(obj == NULL)
+ return NULL;
+ if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
+ return NULL;
+ return (LuaEntitySAO*)obj;
+}
+
+PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
+{
+ ServerActiveObject *obj = getobject(ref);
+ if(obj == NULL)
+ return NULL;
+ if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
+ return NULL;
+ return (PlayerSAO*)obj;
+}
+
+Player* ObjectRef::getplayer(ObjectRef *ref)
+{
+ PlayerSAO *playersao = getplayersao(ref);
+ if(playersao == NULL)
+ return NULL;
+ return playersao->getPlayer();
+}
+
+// Exported functions
+
+// garbage collector
+int ObjectRef::gc_object(lua_State *L) {
+ ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
+ //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
+ delete o;
+ return 0;
+}
+
+// remove(self)
+int ObjectRef::l_remove(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ verbosestream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
+ co->m_removed = true;
+ return 0;
+}
+
+// getpos(self)
+// returns: {x=num, y=num, z=num}
+int ObjectRef::l_getpos(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ v3f pos = co->getBasePosition() / BS;
+ lua_newtable(L);
+ lua_pushnumber(L, pos.X);
+ lua_setfield(L, -2, "x");
+ lua_pushnumber(L, pos.Y);
+ lua_setfield(L, -2, "y");
+ lua_pushnumber(L, pos.Z);
+ lua_setfield(L, -2, "z");
+ return 1;
+}
+
+// setpos(self, pos)
+int ObjectRef::l_setpos(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ //LuaEntitySAO *co = getluaobject(ref);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // pos
+ v3f pos = checkFloatPos(L, 2);
+ // Do it
+ co->setPos(pos);
+ return 0;
+}
+
+// moveto(self, pos, continuous=false)
+int ObjectRef::l_moveto(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ //LuaEntitySAO *co = getluaobject(ref);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // pos
+ v3f pos = checkFloatPos(L, 2);
+ // continuous
+ bool continuous = lua_toboolean(L, 3);
+ // Do it
+ co->moveTo(pos, continuous);
+ return 0;
+}
+
+// punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
+int ObjectRef::l_punch(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ObjectRef *puncher_ref = checkobject(L, 2);
+ ServerActiveObject *co = getobject(ref);
+ ServerActiveObject *puncher = getobject(puncher_ref);
+ if(co == NULL) return 0;
+ if(puncher == NULL) return 0;
+ v3f dir;
+ if(lua_type(L, 5) != LUA_TTABLE)
+ dir = co->getBasePosition() - puncher->getBasePosition();
+ else
+ dir = read_v3f(L, 5);
+ float time_from_last_punch = 1000000;
+ if(lua_isnumber(L, 3))
+ time_from_last_punch = lua_tonumber(L, 3);
+ ToolCapabilities toolcap = read_tool_capabilities(L, 4);
+ dir.normalize();
+ // Do it
+ co->punch(dir, &toolcap, puncher, time_from_last_punch);
+ return 0;
+}
+
+// right_click(self, clicker); clicker = an another ObjectRef
+int ObjectRef::l_right_click(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ObjectRef *ref2 = checkobject(L, 2);
+ ServerActiveObject *co = getobject(ref);
+ ServerActiveObject *co2 = getobject(ref2);
+ if(co == NULL) return 0;
+ if(co2 == NULL) return 0;
+ // Do it
+ co->rightClick(co2);
+ return 0;
+}
+
+// set_hp(self, hp)
+// hp = number of hitpoints (2 * number of hearts)
+// returns: nil
+int ObjectRef::l_set_hp(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ luaL_checknumber(L, 2);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ int hp = lua_tonumber(L, 2);
+ /*infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
+ <<" hp="<<hp<<std::endl;*/
+ // Do it
+ co->setHP(hp);
+ // Return
+ return 0;
+}
+
+// get_hp(self)
+// returns: number of hitpoints (2 * number of hearts)
+// 0 if not applicable to this type of object
+int ObjectRef::l_get_hp(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL){
+ // Default hp is 1
+ lua_pushnumber(L, 1);
+ return 1;
+ }
+ int hp = co->getHP();
+ /*infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
+ <<" hp="<<hp<<std::endl;*/
+ // Return
+ lua_pushnumber(L, hp);
+ return 1;
+}
+
+// get_inventory(self)
+int ObjectRef::l_get_inventory(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ InventoryLocation loc = co->getInventoryLocation();
+ if(get_server(L)->getInventory(loc) != NULL)
+ InvRef::create(L, loc);
+ else
+ lua_pushnil(L); // An object may have no inventory (nil)
+ return 1;
+}
+
+// get_wield_list(self)
+int ObjectRef::l_get_wield_list(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ lua_pushstring(L, co->getWieldList().c_str());
+ return 1;
+}
+
+// get_wield_index(self)
+int ObjectRef::l_get_wield_index(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ lua_pushinteger(L, co->getWieldIndex() + 1);
+ return 1;
+}
+
+// get_wielded_item(self)
+int ObjectRef::l_get_wielded_item(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL){
+ // Empty ItemStack
+ LuaItemStack::create(L, ItemStack());
+ return 1;
+ }
+ // Do it
+ LuaItemStack::create(L, co->getWieldedItem());
+ return 1;
+}
+
+// set_wielded_item(self, itemstack or itemstring or table or nil)
+int ObjectRef::l_set_wielded_item(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ ItemStack item = read_item(L, 2);
+ bool success = co->setWieldedItem(item);
+ lua_pushboolean(L, success);
+ return 1;
+}
+
+// set_armor_groups(self, groups)
+int ObjectRef::l_set_armor_groups(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ ItemGroupList groups;
+ read_groups(L, 2, groups);
+ co->setArmorGroups(groups);
+ return 0;
+}
+
+// set_animation(self, frame_range, frame_speed, frame_blend)
+int ObjectRef::l_set_animation(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ v2f frames = v2f(1, 1);
+ if(!lua_isnil(L, 2))
+ frames = read_v2f(L, 2);
+ float frame_speed = 15;
+ if(!lua_isnil(L, 3))
+ frame_speed = lua_tonumber(L, 3);
+ float frame_blend = 0;
+ if(!lua_isnil(L, 4))
+ frame_blend = lua_tonumber(L, 4);
+ co->setAnimation(frames, frame_speed, frame_blend);
+ return 0;
+}
+
+// set_bone_position(self, std::string bone, v3f position, v3f rotation)
+int ObjectRef::l_set_bone_position(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ std::string bone = "";
+ if(!lua_isnil(L, 2))
+ bone = lua_tostring(L, 2);
+ v3f position = v3f(0, 0, 0);
+ if(!lua_isnil(L, 3))
+ position = read_v3f(L, 3);
+ v3f rotation = v3f(0, 0, 0);
+ if(!lua_isnil(L, 4))
+ rotation = read_v3f(L, 4);
+ co->setBonePosition(bone, position, rotation);
+ return 0;
+}
+
+// set_attach(self, parent, bone, position, rotation)
+int ObjectRef::l_set_attach(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ObjectRef *parent_ref = checkobject(L, 2);
+ ServerActiveObject *co = getobject(ref);
+ ServerActiveObject *parent = getobject(parent_ref);
+ if(co == NULL) return 0;
+ if(parent == NULL) return 0;
+ // Do it
+ std::string bone = "";
+ if(!lua_isnil(L, 3))
+ bone = lua_tostring(L, 3);
+ v3f position = v3f(0, 0, 0);
+ if(!lua_isnil(L, 4))
+ position = read_v3f(L, 4);
+ v3f rotation = v3f(0, 0, 0);
+ if(!lua_isnil(L, 5))
+ rotation = read_v3f(L, 5);
+ co->setAttachment(parent->getId(), bone, position, rotation);
+ return 0;
+}
+
+// set_detach(self)
+int ObjectRef::l_set_detach(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
+ return 0;
+}
+
+// set_properties(self, properties)
+int ObjectRef::l_set_properties(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ ObjectProperties *prop = co->accessObjectProperties();
+ if(!prop)
+ return 0;
+ read_object_properties(L, 2, prop);
+ co->notifyObjectPropertiesModified();
+ return 0;
+}
+
+/* LuaEntitySAO-only */
+
+// setvelocity(self, {x=num, y=num, z=num})
+int ObjectRef::l_setvelocity(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ v3f pos = checkFloatPos(L, 2);
+ // Do it
+ co->setVelocity(pos);
+ return 0;
+}
+
+// getvelocity(self)
+int ObjectRef::l_getvelocity(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ v3f v = co->getVelocity();
+ pushFloatPos(L, v);
+ return 1;
+}
+
+// setacceleration(self, {x=num, y=num, z=num})
+int ObjectRef::l_setacceleration(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ // pos
+ v3f pos = checkFloatPos(L, 2);
+ // Do it
+ co->setAcceleration(pos);
+ return 0;
+}
+
+// getacceleration(self)
+int ObjectRef::l_getacceleration(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ v3f v = co->getAcceleration();
+ pushFloatPos(L, v);
+ return 1;
+}
+
+// setyaw(self, radians)
+int ObjectRef::l_setyaw(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
+ // Do it
+ co->setYaw(yaw);
+ return 0;
+}
+
+// getyaw(self)
+int ObjectRef::l_getyaw(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ float yaw = co->getYaw() * core::DEGTORAD;
+ lua_pushnumber(L, yaw);
+ return 1;
+}
+
+// settexturemod(self, mod)
+int ObjectRef::l_settexturemod(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ std::string mod = luaL_checkstring(L, 2);
+ co->setTextureMod(mod);
+ return 0;
+}
+
+// setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
+// select_horiz_by_yawpitch=false)
+int ObjectRef::l_setsprite(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ v2s16 p(0,0);
+ if(!lua_isnil(L, 2))
+ p = read_v2s16(L, 2);
+ int num_frames = 1;
+ if(!lua_isnil(L, 3))
+ num_frames = lua_tonumber(L, 3);
+ float framelength = 0.2;
+ if(!lua_isnil(L, 4))
+ framelength = lua_tonumber(L, 4);
+ bool select_horiz_by_yawpitch = false;
+ if(!lua_isnil(L, 5))
+ select_horiz_by_yawpitch = lua_toboolean(L, 5);
+ co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
+ return 0;
+}
+
+// DEPRECATED
+// get_entity_name(self)
+int ObjectRef::l_get_entity_name(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ std::string name = co->getName();
+ lua_pushstring(L, name.c_str());
+ return 1;
+}
+
+// get_luaentity(self)
+int ObjectRef::l_get_luaentity(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if(co == NULL) return 0;
+ // Do it
+ luaentity_get(L, co->getId());
+ return 1;
+}
+
+/* Player-only */
+
+// is_player(self)
+int ObjectRef::l_is_player(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ lua_pushboolean(L, (player != NULL));
+ return 1;
+}
+
+// get_player_name(self)
+int ObjectRef::l_get_player_name(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if(player == NULL){
+ lua_pushlstring(L, "", 0);
+ return 1;
+ }
+ // Do it
+ lua_pushstring(L, player->getName());
+ return 1;
+}
+
+// get_look_dir(self)
+int ObjectRef::l_get_look_dir(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if(player == NULL) return 0;
+ // Do it
+ float pitch = player->getRadPitch();
+ float yaw = player->getRadYaw();
+ v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw));
+ push_v3f(L, v);
+ return 1;
+}
+
+// get_look_pitch(self)
+int ObjectRef::l_get_look_pitch(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if(player == NULL) return 0;
+ // Do it
+ lua_pushnumber(L, player->getRadPitch());
+ return 1;
+}
+
+// get_look_yaw(self)
+int ObjectRef::l_get_look_yaw(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if(player == NULL) return 0;
+ // Do it
+ lua_pushnumber(L, player->getRadYaw());
+ return 1;
+}
+
+// set_look_pitch(self, radians)
+int ObjectRef::l_set_look_pitch(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ PlayerSAO* co = getplayersao(ref);
+ if(co == NULL) return 0;
+ float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
+ // Do it
+ co->setPitch(pitch);
+ return 1;
+}
+
+// set_look_yaw(self, radians)
+int ObjectRef::l_set_look_yaw(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ PlayerSAO* co = getplayersao(ref);
+ if(co == NULL) return 0;
+ float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
+ // Do it
+ co->setYaw(yaw);
+ return 1;
+}
+
+// set_inventory_formspec(self, formspec)
+int ObjectRef::l_set_inventory_formspec(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if(player == NULL) return 0;
+ std::string formspec = luaL_checkstring(L, 2);
+
+ player->inventory_formspec = formspec;
+ get_server(L)->reportInventoryFormspecModified(player->getName());
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// get_inventory_formspec(self) -> formspec
+int ObjectRef::l_get_inventory_formspec(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if(player == NULL) return 0;
+
+ std::string formspec = player->inventory_formspec;
+ lua_pushlstring(L, formspec.c_str(), formspec.size());
+ return 1;
+}
+
+// get_player_control(self)
+int ObjectRef::l_get_player_control(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if(player == NULL){
+ lua_pushlstring(L, "", 0);
+ return 1;
+ }
+ // Do it
+ PlayerControl control = player->getPlayerControl();
+ lua_newtable(L);
+ lua_pushboolean(L, control.up);
+ lua_setfield(L, -2, "up");
+ lua_pushboolean(L, control.down);
+ lua_setfield(L, -2, "down");
+ lua_pushboolean(L, control.left);
+ lua_setfield(L, -2, "left");
+ lua_pushboolean(L, control.right);
+ lua_setfield(L, -2, "right");
+ lua_pushboolean(L, control.jump);
+ lua_setfield(L, -2, "jump");
+ lua_pushboolean(L, control.aux1);
+ lua_setfield(L, -2, "aux1");
+ lua_pushboolean(L, control.sneak);
+ lua_setfield(L, -2, "sneak");
+ lua_pushboolean(L, control.LMB);
+ lua_setfield(L, -2, "LMB");
+ lua_pushboolean(L, control.RMB);
+ lua_setfield(L, -2, "RMB");
+ return 1;
+}
+
+// get_player_control_bits(self)
+int ObjectRef::l_get_player_control_bits(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if(player == NULL){
+ lua_pushlstring(L, "", 0);
+ return 1;
+ }
+ // Do it
+ lua_pushnumber(L, player->keyPressed);
+ return 1;
+}
+
+
+ObjectRef::ObjectRef(ServerActiveObject *object):
+ m_object(object)
+{
+ //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
+}
+
+ObjectRef::~ObjectRef()
+{
+ /*if(m_object)
+ infostream<<"ObjectRef destructing for id="
+ <<m_object->getId()<<std::endl;
+ else
+ infostream<<"ObjectRef destructing for id=unknown"<<std::endl;*/
+}
+
+// Creates an ObjectRef and leaves it on top of stack
+// Not callable from Lua; all references are created on the C side.
+void ObjectRef::create(lua_State *L, ServerActiveObject *object)
+{
+ ObjectRef *o = new ObjectRef(object);
+ //infostream<<"ObjectRef::create: o="<<o<<std::endl;
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
+void ObjectRef::set_null(lua_State *L)
+{
+ ObjectRef *o = checkobject(L, -1);
+ o->m_object = NULL;
+}
+
+void ObjectRef::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Cannot be created from Lua
+ //lua_register(L, className, create_object);
+}
+
+const char ObjectRef::className[] = "ObjectRef";
+const luaL_reg ObjectRef::methods[] = {
+ // ServerActiveObject
+ luamethod(ObjectRef, remove),
+ luamethod(ObjectRef, getpos),
+ luamethod(ObjectRef, setpos),
+ luamethod(ObjectRef, moveto),
+ luamethod(ObjectRef, punch),
+ luamethod(ObjectRef, right_click),
+ luamethod(ObjectRef, set_hp),
+ luamethod(ObjectRef, get_hp),
+ luamethod(ObjectRef, get_inventory),
+ luamethod(ObjectRef, get_wield_list),
+ luamethod(ObjectRef, get_wield_index),
+ luamethod(ObjectRef, get_wielded_item),
+ luamethod(ObjectRef, set_wielded_item),
+ luamethod(ObjectRef, set_armor_groups),
+ luamethod(ObjectRef, set_animation),
+ luamethod(ObjectRef, set_bone_position),
+ luamethod(ObjectRef, set_attach),
+ luamethod(ObjectRef, set_detach),
+ luamethod(ObjectRef, set_properties),
+ // LuaEntitySAO-only
+ luamethod(ObjectRef, setvelocity),
+ luamethod(ObjectRef, getvelocity),
+ luamethod(ObjectRef, setacceleration),
+ luamethod(ObjectRef, getacceleration),
+ luamethod(ObjectRef, setyaw),
+ luamethod(ObjectRef, getyaw),
+ luamethod(ObjectRef, settexturemod),
+ luamethod(ObjectRef, setsprite),
+ luamethod(ObjectRef, get_entity_name),
+ luamethod(ObjectRef, get_luaentity),
+ // Player-only
+ luamethod(ObjectRef, is_player),
+ luamethod(ObjectRef, get_player_name),
+ luamethod(ObjectRef, get_look_dir),
+ luamethod(ObjectRef, get_look_pitch),
+ luamethod(ObjectRef, get_look_yaw),
+ luamethod(ObjectRef, set_look_yaw),
+ luamethod(ObjectRef, set_look_pitch),
+ luamethod(ObjectRef, set_inventory_formspec),
+ luamethod(ObjectRef, get_inventory_formspec),
+ luamethod(ObjectRef, get_player_control),
+ luamethod(ObjectRef, get_player_control_bits),
+ {0,0}
+};
+
+// Creates a new anonymous reference if cobj=NULL or id=0
+void objectref_get_or_create(lua_State *L,
+ ServerActiveObject *cobj)
+{
+ if(cobj == NULL || cobj->getId() == 0){
+ ObjectRef::create(L, cobj);
+ } else {
+ objectref_get(L, cobj->getId());
+ }
+}
+
+void objectref_get(lua_State *L, u16 id)
+{
+ // Get minetest.object_refs[i]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "object_refs");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnumber(L, id);
+ lua_gettable(L, -2);
+ lua_remove(L, -2); // object_refs
+ lua_remove(L, -2); // minetest
+}
+
+/*
+ ObjectProperties
+*/
+
+void read_object_properties(lua_State *L, int index,
+ ObjectProperties *prop)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+ if(!lua_istable(L, index))
+ return;
+
+ prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
+
+ getboolfield(L, -1, "physical", prop->physical);
+
+ getfloatfield(L, -1, "weight", prop->weight);
+
+ lua_getfield(L, -1, "collisionbox");
+ if(lua_istable(L, -1))
+ prop->collisionbox = read_aabb3f(L, -1, 1.0);
+ lua_pop(L, 1);
+
+ getstringfield(L, -1, "visual", prop->visual);
+
+ getstringfield(L, -1, "mesh", prop->mesh);
+
+ lua_getfield(L, -1, "visual_size");
+ if(lua_istable(L, -1))
+ prop->visual_size = read_v2f(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "textures");
+ if(lua_istable(L, -1)){
+ prop->textures.clear();
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ if(lua_isstring(L, -1))
+ prop->textures.push_back(lua_tostring(L, -1));
+ else
+ prop->textures.push_back("");
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "colors");
+ if(lua_istable(L, -1)){
+ prop->colors.clear();
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ if(lua_isstring(L, -1))
+ prop->colors.push_back(readARGB8(L, -1));
+ else
+ prop->colors.push_back(video::SColor(255, 255, 255, 255));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "spritediv");
+ if(lua_istable(L, -1))
+ prop->spritediv = read_v2s16(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "initial_sprite_basepos");
+ if(lua_istable(L, -1))
+ prop->initial_sprite_basepos = read_v2s16(L, -1);
+ lua_pop(L, 1);
+
+ getboolfield(L, -1, "is_visible", prop->is_visible);
+ getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
+ getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
+}
+
+/*
+ object_reference
+*/
+
+void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Create object on stack
+ ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
+ int object = lua_gettop(L);
+
+ // Get minetest.object_refs table
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "object_refs");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int objectstable = lua_gettop(L);
+
+ // object_refs[id] = object
+ lua_pushnumber(L, cobj->getId()); // Push id
+ lua_pushvalue(L, object); // Copy object to top of stack
+ lua_settable(L, objectstable);
+}
+
+void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.object_refs table
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "object_refs");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int objectstable = lua_gettop(L);
+
+ // Get object_refs[id]
+ lua_pushnumber(L, cobj->getId()); // Push id
+ lua_gettable(L, objectstable);
+ // Set object reference to NULL
+ ObjectRef::set_null(L);
+ lua_pop(L, 1); // pop object
+
+ // Set object_refs[id] = nil
+ lua_pushnumber(L, cobj->getId()); // Push id
+ lua_pushnil(L);
+ lua_settable(L, objectstable);
+}
diff --git a/src/scriptapi_object.h b/src/scriptapi_object.h
new file mode 100644
index 000000000..a37abbb78
--- /dev/null
+++ b/src/scriptapi_object.h
@@ -0,0 +1,220 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_OBJECT_H_
+#define LUA_OBJECT_H_
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+#include "serverobject.h"
+#include "content_sao.h"
+#include "player.h"
+
+/*
+ ObjectRef
+*/
+
+class ObjectRef
+{
+private:
+ ServerActiveObject *m_object;
+
+ static const char className[];
+ static const luaL_reg methods[];
+public:
+ static ObjectRef *checkobject(lua_State *L, int narg);
+
+ static ServerActiveObject* getobject(ObjectRef *ref);
+private:
+ static LuaEntitySAO* getluaobject(ObjectRef *ref);
+
+ static PlayerSAO* getplayersao(ObjectRef *ref);
+
+ static Player* getplayer(ObjectRef *ref);
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ // remove(self)
+ static int l_remove(lua_State *L);
+
+ // getpos(self)
+ // returns: {x=num, y=num, z=num}
+ static int l_getpos(lua_State *L);
+
+ // setpos(self, pos)
+ static int l_setpos(lua_State *L);
+
+ // moveto(self, pos, continuous=false)
+ static int l_moveto(lua_State *L);
+
+ // punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
+ static int l_punch(lua_State *L);
+
+ // right_click(self, clicker); clicker = an another ObjectRef
+ static int l_right_click(lua_State *L);
+
+ // set_hp(self, hp)
+ // hp = number of hitpoints (2 * number of hearts)
+ // returns: nil
+ static int l_set_hp(lua_State *L);
+
+ // get_hp(self)
+ // returns: number of hitpoints (2 * number of hearts)
+ // 0 if not applicable to this type of object
+ static int l_get_hp(lua_State *L);
+
+ // get_inventory(self)
+ static int l_get_inventory(lua_State *L);
+
+ // get_wield_list(self)
+ static int l_get_wield_list(lua_State *L);
+
+ // get_wield_index(self)
+ static int l_get_wield_index(lua_State *L);
+
+ // get_wielded_item(self)
+ static int l_get_wielded_item(lua_State *L);
+
+ // set_wielded_item(self, itemstack or itemstring or table or nil)
+ static int l_set_wielded_item(lua_State *L);
+
+ // set_armor_groups(self, groups)
+ static int l_set_armor_groups(lua_State *L);
+
+ // set_animation(self, frame_range, frame_speed, frame_blend)
+ static int l_set_animation(lua_State *L);
+
+ // set_bone_position(self, std::string bone, v3f position, v3f rotation)
+ static int l_set_bone_position(lua_State *L);
+
+ // set_attach(self, parent, bone, position, rotation)
+ static int l_set_attach(lua_State *L);
+
+ // set_detach(self)
+ static int l_set_detach(lua_State *L);
+
+ // set_properties(self, properties)
+ static int l_set_properties(lua_State *L);
+
+ /* LuaEntitySAO-only */
+
+ // setvelocity(self, {x=num, y=num, z=num})
+ static int l_setvelocity(lua_State *L);
+
+ // getvelocity(self)
+ static int l_getvelocity(lua_State *L);
+
+ // setacceleration(self, {x=num, y=num, z=num})
+ static int l_setacceleration(lua_State *L);
+
+ // getacceleration(self)
+ static int l_getacceleration(lua_State *L);
+
+ // setyaw(self, radians)
+ static int l_setyaw(lua_State *L);
+
+ // getyaw(self)
+ static int l_getyaw(lua_State *L);
+
+ // settexturemod(self, mod)
+ static int l_settexturemod(lua_State *L);
+
+ // setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
+ // select_horiz_by_yawpitch=false)
+ static int l_setsprite(lua_State *L);
+
+ // DEPRECATED
+ // get_entity_name(self)
+ static int l_get_entity_name(lua_State *L);
+
+ // get_luaentity(self)
+ static int l_get_luaentity(lua_State *L);
+
+ /* Player-only */
+
+ // is_player(self)
+ static int l_is_player(lua_State *L);
+
+ // get_player_name(self)
+ static int l_get_player_name(lua_State *L);
+
+ // get_look_dir(self)
+ static int l_get_look_dir(lua_State *L);
+
+ // get_look_pitch(self)
+ static int l_get_look_pitch(lua_State *L);
+
+ // get_look_yaw(self)
+ static int l_get_look_yaw(lua_State *L);
+
+ // set_look_pitch(self, radians)
+ static int l_set_look_pitch(lua_State *L);
+
+ // set_look_yaw(self, radians)
+ static int l_set_look_yaw(lua_State *L);
+
+ // set_inventory_formspec(self, formspec)
+ static int l_set_inventory_formspec(lua_State *L);
+
+ // get_inventory_formspec(self) -> formspec
+ static int l_get_inventory_formspec(lua_State *L);
+
+ // get_player_control(self)
+ static int l_get_player_control(lua_State *L);
+
+ // get_player_control_bits(self)
+ static int l_get_player_control_bits(lua_State *L);
+
+public:
+ ObjectRef(ServerActiveObject *object);
+
+ ~ObjectRef();
+
+ // Creates an ObjectRef and leaves it on top of stack
+ // Not callable from Lua; all references are created on the C side.
+ static void create(lua_State *L, ServerActiveObject *object);
+
+ static void set_null(lua_State *L);
+
+ static void Register(lua_State *L);
+};
+
+/*****************************************************************************/
+/* scriptapi internal */
+/*****************************************************************************/
+// Creates a new anonymous reference if cobj=NULL or id=0
+void objectref_get_or_create(lua_State *L,
+ ServerActiveObject *cobj);
+void objectref_get(lua_State *L, u16 id);
+void read_object_properties(lua_State *L, int index,
+ ObjectProperties *prop);
+
+/*****************************************************************************/
+/* Minetest interface */
+/*****************************************************************************/
+void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj);
+void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj);
+
+#endif /* LUA_OBJECT_H_ */
diff --git a/src/scriptapi_particles.cpp b/src/scriptapi_particles.cpp
new file mode 100644
index 000000000..dc9b3776e
--- /dev/null
+++ b/src/scriptapi_particles.cpp
@@ -0,0 +1,143 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_particles.h"
+#include "server.h"
+#include "script.h"
+#include "scriptapi_types.h"
+#include "scriptapi_common.h"
+
+// add_particle(pos, velocity, acceleration, expirationtime,
+// size, collisiondetection, texture, player)
+// pos/velocity/acceleration = {x=num, y=num, z=num}
+// expirationtime = num (seconds)
+// size = num
+// texture = e.g."default_wood.png"
+int l_add_particle(lua_State *L)
+{
+ // Get server from registry
+ Server *server = get_server(L);
+ // Get parameters
+ v3f pos = check_v3f(L, 1);
+ v3f vel = check_v3f(L, 2);
+ v3f acc = check_v3f(L, 3);
+ float expirationtime = luaL_checknumber(L, 4);
+ float size = luaL_checknumber(L, 5);
+ bool collisiondetection = lua_toboolean(L, 6);
+ std::string texture = luaL_checkstring(L, 7);
+
+ if (lua_gettop(L) == 8) // only spawn for a single player
+ {
+ const char *playername = luaL_checkstring(L, 8);
+ server->spawnParticle(playername,
+ pos, vel, acc, expirationtime,
+ size, collisiondetection, texture);
+ }
+ else // spawn for all players
+ {
+ server->spawnParticleAll(pos, vel, acc,
+ expirationtime, size, collisiondetection, texture);
+ }
+ return 1;
+}
+
+// add_particlespawner(amount, time,
+// minpos, maxpos,
+// minvel, maxvel,
+// minacc, maxacc,
+// minexptime, maxexptime,
+// minsize, maxsize,
+// collisiondetection,
+// texture,
+// player)
+// minpos/maxpos/minvel/maxvel/minacc/maxacc = {x=num, y=num, z=num}
+// minexptime/maxexptime = num (seconds)
+// minsize/maxsize = num
+// collisiondetection = bool
+// texture = e.g."default_wood.png"
+int l_add_particlespawner(lua_State *L)
+{
+ // Get server from registry
+ Server *server = get_server(L);
+ // Get parameters
+ u16 amount = luaL_checknumber(L, 1);
+ float time = luaL_checknumber(L, 2);
+ v3f minpos = check_v3f(L, 3);
+ v3f maxpos = check_v3f(L, 4);
+ v3f minvel = check_v3f(L, 5);
+ v3f maxvel = check_v3f(L, 6);
+ v3f minacc = check_v3f(L, 7);
+ v3f maxacc = check_v3f(L, 8);
+ float minexptime = luaL_checknumber(L, 9);
+ float maxexptime = luaL_checknumber(L, 10);
+ float minsize = luaL_checknumber(L, 11);
+ float maxsize = luaL_checknumber(L, 12);
+ bool collisiondetection = lua_toboolean(L, 13);
+ std::string texture = luaL_checkstring(L, 14);
+
+ if (lua_gettop(L) == 15) // only spawn for a single player
+ {
+ const char *playername = luaL_checkstring(L, 15);
+ u32 id = server->addParticleSpawner(playername,
+ amount, time,
+ minpos, maxpos,
+ minvel, maxvel,
+ minacc, maxacc,
+ minexptime, maxexptime,
+ minsize, maxsize,
+ collisiondetection,
+ texture);
+ lua_pushnumber(L, id);
+ }
+ else // spawn for all players
+ {
+ u32 id = server->addParticleSpawnerAll( amount, time,
+ minpos, maxpos,
+ minvel, maxvel,
+ minacc, maxacc,
+ minexptime, maxexptime,
+ minsize, maxsize,
+ collisiondetection,
+ texture);
+ lua_pushnumber(L, id);
+ }
+ return 1;
+}
+
+// delete_particlespawner(id, player)
+// player (string) is optional
+int l_delete_particlespawner(lua_State *L)
+{
+ // Get server from registry
+ Server *server = get_server(L);
+ // Get parameters
+ u32 id = luaL_checknumber(L, 1);
+
+ if (lua_gettop(L) == 2) // only delete for one player
+ {
+ const char *playername = luaL_checkstring(L, 2);
+ server->deleteParticleSpawner(playername, id);
+ }
+ else // delete for all players
+ {
+ server->deleteParticleSpawnerAll(id);
+ }
+ return 1;
+}
diff --git a/src/scriptapi_particles.h b/src/scriptapi_particles.h
new file mode 100644
index 000000000..4b37d7ce1
--- /dev/null
+++ b/src/scriptapi_particles.h
@@ -0,0 +1,32 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_PARTICLES_H_
+#define LUA_PARTICLES_H_
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+int l_add_particle(lua_State *L);
+int l_add_particlespawner(lua_State *L);
+int l_delete_particlespawner(lua_State *L);
+
+#endif
diff --git a/src/scriptapi_types.cpp b/src/scriptapi_types.cpp
new file mode 100644
index 000000000..3d06f1623
--- /dev/null
+++ b/src/scriptapi_types.cpp
@@ -0,0 +1,372 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "scriptapi.h"
+#include "scriptapi_types.h"
+
+extern "C" {
+#include <lauxlib.h>
+}
+
+#include "util/numeric.h"
+#include "nodedef.h"
+
+/*
+ C struct <-> Lua table converter functions
+*/
+
+void push_v3f(lua_State *L, v3f p)
+{
+ lua_newtable(L);
+ lua_pushnumber(L, p.X);
+ lua_setfield(L, -2, "x");
+ lua_pushnumber(L, p.Y);
+ lua_setfield(L, -2, "y");
+ lua_pushnumber(L, p.Z);
+ lua_setfield(L, -2, "z");
+}
+
+v2s16 read_v2s16(lua_State *L, int index)
+{
+ v2s16 p;
+ luaL_checktype(L, index, LUA_TTABLE);
+ lua_getfield(L, index, "x");
+ p.X = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, index, "y");
+ p.Y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ return p;
+}
+
+v2f read_v2f(lua_State *L, int index)
+{
+ v2f p;
+ luaL_checktype(L, index, LUA_TTABLE);
+ lua_getfield(L, index, "x");
+ p.X = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, index, "y");
+ p.Y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ return p;
+}
+
+v3f read_v3f(lua_State *L, int index)
+{
+ v3f pos;
+ luaL_checktype(L, index, LUA_TTABLE);
+ lua_getfield(L, index, "x");
+ pos.X = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, index, "y");
+ pos.Y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, index, "z");
+ pos.Z = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ return pos;
+}
+
+v3f check_v3f(lua_State *L, int index)
+{
+ v3f pos;
+ luaL_checktype(L, index, LUA_TTABLE);
+ lua_getfield(L, index, "x");
+ pos.X = luaL_checknumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, index, "y");
+ pos.Y = luaL_checknumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, index, "z");
+ pos.Z = luaL_checknumber(L, -1);
+ lua_pop(L, 1);
+ return pos;
+}
+
+void pushFloatPos(lua_State *L, v3f p)
+{
+ p /= BS;
+ push_v3f(L, p);
+}
+
+v3f checkFloatPos(lua_State *L, int index)
+{
+ return check_v3f(L, index) * BS;
+}
+
+void push_v3s16(lua_State *L, v3s16 p)
+{
+ lua_newtable(L);
+ lua_pushnumber(L, p.X);
+ lua_setfield(L, -2, "x");
+ lua_pushnumber(L, p.Y);
+ lua_setfield(L, -2, "y");
+ lua_pushnumber(L, p.Z);
+ lua_setfield(L, -2, "z");
+}
+
+v3s16 read_v3s16(lua_State *L, int index)
+{
+ // Correct rounding at <0
+ v3f pf = read_v3f(L, index);
+ return floatToInt(pf, 1.0);
+}
+
+v3s16 check_v3s16(lua_State *L, int index)
+{
+ // Correct rounding at <0
+ v3f pf = check_v3f(L, index);
+ return floatToInt(pf, 1.0);
+}
+
+video::SColor readARGB8(lua_State *L, int index)
+{
+ video::SColor color;
+ luaL_checktype(L, index, LUA_TTABLE);
+ lua_getfield(L, index, "a");
+ if(lua_isnumber(L, -1))
+ color.setAlpha(lua_tonumber(L, -1));
+ lua_pop(L, 1);
+ lua_getfield(L, index, "r");
+ color.setRed(lua_tonumber(L, -1));
+ lua_pop(L, 1);
+ lua_getfield(L, index, "g");
+ color.setGreen(lua_tonumber(L, -1));
+ lua_pop(L, 1);
+ lua_getfield(L, index, "b");
+ color.setBlue(lua_tonumber(L, -1));
+ lua_pop(L, 1);
+ return color;
+}
+
+aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
+{
+ aabb3f box;
+ if(lua_istable(L, index)){
+ lua_rawgeti(L, index, 1);
+ box.MinEdge.X = lua_tonumber(L, -1) * scale;
+ lua_pop(L, 1);
+ lua_rawgeti(L, index, 2);
+ box.MinEdge.Y = lua_tonumber(L, -1) * scale;
+ lua_pop(L, 1);
+ lua_rawgeti(L, index, 3);
+ box.MinEdge.Z = lua_tonumber(L, -1) * scale;
+ lua_pop(L, 1);
+ lua_rawgeti(L, index, 4);
+ box.MaxEdge.X = lua_tonumber(L, -1) * scale;
+ lua_pop(L, 1);
+ lua_rawgeti(L, index, 5);
+ box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
+ lua_pop(L, 1);
+ lua_rawgeti(L, index, 6);
+ box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
+ lua_pop(L, 1);
+ }
+ return box;
+}
+
+std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
+{
+ std::vector<aabb3f> boxes;
+ if(lua_istable(L, index)){
+ int n = lua_objlen(L, index);
+ // Check if it's a single box or a list of boxes
+ bool possibly_single_box = (n == 6);
+ for(int i = 1; i <= n && possibly_single_box; i++){
+ lua_rawgeti(L, index, i);
+ if(!lua_isnumber(L, -1))
+ possibly_single_box = false;
+ lua_pop(L, 1);
+ }
+ if(possibly_single_box){
+ // Read a single box
+ boxes.push_back(read_aabb3f(L, index, scale));
+ } else {
+ // Read a list of boxes
+ for(int i = 1; i <= n; i++){
+ lua_rawgeti(L, index, i);
+ boxes.push_back(read_aabb3f(L, -1, scale));
+ lua_pop(L, 1);
+ }
+ }
+ }
+ return boxes;
+}
+
+/*
+ Table field getters
+*/
+
+bool getstringfield(lua_State *L, int table,
+ const char *fieldname, std::string &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isstring(L, -1)){
+ size_t len = 0;
+ const char *ptr = lua_tolstring(L, -1, &len);
+ result.assign(ptr, len);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+bool getintfield(lua_State *L, int table,
+ const char *fieldname, int &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isnumber(L, -1)){
+ result = lua_tonumber(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+bool getfloatfield(lua_State *L, int table,
+ const char *fieldname, float &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isnumber(L, -1)){
+ result = lua_tonumber(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+bool getboolfield(lua_State *L, int table,
+ const char *fieldname, bool &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isboolean(L, -1)){
+ result = lua_toboolean(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+std::string checkstringfield(lua_State *L, int table,
+ const char *fieldname)
+{
+ lua_getfield(L, table, fieldname);
+ std::string s = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
+ return s;
+}
+
+std::string getstringfield_default(lua_State *L, int table,
+ const char *fieldname, const std::string &default_)
+{
+ std::string result = default_;
+ getstringfield(L, table, fieldname, result);
+ return result;
+}
+
+int getintfield_default(lua_State *L, int table,
+ const char *fieldname, int default_)
+{
+ int result = default_;
+ getintfield(L, table, fieldname, result);
+ return result;
+}
+
+float getfloatfield_default(lua_State *L, int table,
+ const char *fieldname, float default_)
+{
+ float result = default_;
+ getfloatfield(L, table, fieldname, result);
+ return result;
+}
+
+bool getboolfield_default(lua_State *L, int table,
+ const char *fieldname, bool default_)
+{
+ bool result = default_;
+ getboolfield(L, table, fieldname, result);
+ return result;
+}
+
+void setintfield(lua_State *L, int table,
+ const char *fieldname, int value)
+{
+ lua_pushinteger(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
+void setfloatfield(lua_State *L, int table,
+ const char *fieldname, float value)
+{
+ lua_pushnumber(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
+void setboolfield(lua_State *L, int table,
+ const char *fieldname, bool value)
+{
+ lua_pushboolean(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
+
+/* minetest specific types */
+MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
+{
+ lua_getfield(L, index, "name");
+ const char *name = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
+ u8 param1;
+ lua_getfield(L, index, "param1");
+ if(lua_isnil(L, -1))
+ param1 = 0;
+ else
+ param1 = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ u8 param2;
+ lua_getfield(L, index, "param2");
+ if(lua_isnil(L, -1))
+ param2 = 0;
+ else
+ param2 = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ return MapNode(ndef, name, param1, param2);
+}
+
+void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
+{
+ lua_newtable(L);
+ lua_pushstring(L, ndef->get(n).name.c_str());
+ lua_setfield(L, -2, "name");
+ lua_pushnumber(L, n.getParam1());
+ lua_setfield(L, -2, "param1");
+ lua_pushnumber(L, n.getParam2());
+ lua_setfield(L, -2, "param2");
+}
diff --git a/src/scriptapi_types.h b/src/scriptapi_types.h
new file mode 100644
index 000000000..e3a611a9d
--- /dev/null
+++ b/src/scriptapi_types.h
@@ -0,0 +1,87 @@
+/*
+Minetest-c55
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef LUA_TYPES_H_
+#define LUA_TYPES_H_
+
+#include <iostream>
+#include <map>
+#include <vector>
+
+#include "irrlichttypes_bloated.h"
+#include "porting.h"
+#include "map.h"
+
+extern "C" {
+#include <lua.h>
+}
+
+std::string getstringfield_default (lua_State *L, int table,
+ const char *fieldname, const std::string &default_);
+bool getboolfield_default(lua_State *L, int table,
+ const char *fieldname, bool default_);
+float getfloatfield_default(lua_State *L, int table,
+ const char *fieldname, float default_);
+int getintfield_default (lua_State *L, int table,
+ const char *fieldname, int default_);
+
+bool getstringfield(lua_State *L, int table,
+ const char *fieldname, std::string &result);
+bool getintfield(lua_State *L, int table,
+ const char *fieldname, int &result);
+void read_groups (lua_State *L, int index,
+ std::map<std::string, int> &result);
+bool getboolfield(lua_State *L, int table,
+ const char *fieldname, bool &result);
+bool getfloatfield(lua_State *L, int table,
+ const char *fieldname, float &result);
+
+std::string checkstringfield(lua_State *L, int table,
+ const char *fieldname);
+
+void setintfield(lua_State *L, int table,
+ const char *fieldname, int value);
+void setfloatfield(lua_State *L, int table,
+ const char *fieldname, float value);
+void setboolfield(lua_State *L, int table,
+ const char *fieldname, bool value);
+
+
+v3f checkFloatPos (lua_State *L, int index);
+v3f check_v3f (lua_State *L, int index);
+v3s16 check_v3s16 (lua_State *L, int index);
+
+v3f read_v3f (lua_State *L, int index);
+v2f read_v2f (lua_State *L, int index);
+v2s16 read_v2s16 (lua_State *L, int index);
+video::SColor readARGB8 (lua_State *L, int index);
+aabb3f read_aabb3f (lua_State *L, int index, f32 scale);
+v3s16 read_v3s16 (lua_State *L, int index);
+std::vector<aabb3f>
+ read_aabb3f_vector (lua_State *L, int index, f32 scale);
+
+void push_v3s16 (lua_State *L, v3s16 p);
+void pushFloatPos (lua_State *L, v3f p);
+void push_v3f (lua_State *L, v3f p);
+
+
+MapNode readnode(lua_State *L, int index, INodeDefManager *ndef);
+void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef);
+
+#endif /* LUA_TYPES_H_ */
diff --git a/src/server.cpp b/src/server.cpp
index 41a7a4289..c4dd0ab0f 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include <iostream>
#include <queue>
+#include <algorithm>
#include "clientserver.h"
#include "map.h"
#include "jmutexautolock.h"
@@ -58,6 +59,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/mathconstants.h"
#include "rollback.h"
#include "util/serialize.h"
+#include "defaultsettings.h"
void * ServerThread::Thread()
{
@@ -126,7 +128,7 @@ v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
}
void RemoteClient::GetNextBlocks(Server *server, float dtime,
- core::array<PrioritySortedBlockTransfer> &dest)
+ std::vector<PrioritySortedBlockTransfer> &dest)
{
DSTACK(__FUNCTION_NAME);
@@ -274,11 +276,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
Get the border/face dot coordinates of a "d-radiused"
box
*/
- core::list<v3s16> list;
+ std::list<v3s16> list;
getFacePositions(list, d);
- core::list<v3s16>::Iterator li;
- for(li=list.begin(); li!=list.end(); li++)
+ std::list<v3s16>::iterator li;
+ for(li=list.begin(); li!=list.end(); ++li)
{
v3s16 p = *li + center;
@@ -305,7 +307,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
}
// Don't send blocks that are currently being transferred
- if(m_blocks_sending.find(p) != NULL)
+ if(m_blocks_sending.find(p) != m_blocks_sending.end())
continue;
/*
@@ -382,7 +384,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
Don't send already sent blocks
*/
{
- if(m_blocks_sent.find(p) != NULL)
+ if(m_blocks_sent.find(p) != m_blocks_sent.end())
{
continue;
}
@@ -554,21 +556,21 @@ queue_full_break:
void RemoteClient::GotBlock(v3s16 p)
{
- if(m_blocks_sending.find(p) != NULL)
- m_blocks_sending.remove(p);
+ if(m_blocks_sending.find(p) != m_blocks_sending.end())
+ m_blocks_sending.erase(p);
else
{
/*infostream<<"RemoteClient::GotBlock(): Didn't find in"
" m_blocks_sending"<<std::endl;*/
m_excess_gotblocks++;
}
- m_blocks_sent.insert(p, true);
+ m_blocks_sent.insert(p);
}
void RemoteClient::SentBlock(v3s16 p)
{
- if(m_blocks_sending.find(p) == NULL)
- m_blocks_sending.insert(p, 0.0);
+ if(m_blocks_sending.find(p) == m_blocks_sending.end())
+ m_blocks_sending[p] = 0.0;
else
infostream<<"RemoteClient::SentBlock(): Sent block"
" already in m_blocks_sending"<<std::endl;
@@ -578,26 +580,26 @@ void RemoteClient::SetBlockNotSent(v3s16 p)
{
m_nearest_unsent_d = 0;
- if(m_blocks_sending.find(p) != NULL)
- m_blocks_sending.remove(p);
- if(m_blocks_sent.find(p) != NULL)
- m_blocks_sent.remove(p);
+ if(m_blocks_sending.find(p) != m_blocks_sending.end())
+ m_blocks_sending.erase(p);
+ if(m_blocks_sent.find(p) != m_blocks_sent.end())
+ m_blocks_sent.erase(p);
}
-void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
+void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
{
m_nearest_unsent_d = 0;
- for(core::map<v3s16, MapBlock*>::Iterator
- i = blocks.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = blocks.begin();
+ i != blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
+ v3s16 p = i->first;
- if(m_blocks_sending.find(p) != NULL)
- m_blocks_sending.remove(p);
- if(m_blocks_sent.find(p) != NULL)
- m_blocks_sent.remove(p);
+ if(m_blocks_sending.find(p) != m_blocks_sending.end())
+ m_blocks_sending.erase(p);
+ if(m_blocks_sent.find(p) != m_blocks_sent.end())
+ m_blocks_sent.erase(p);
}
}
@@ -651,7 +653,6 @@ Server::Server(
m_craftdef(createCraftDefManager()),
m_event(new EventManager()),
m_thread(this),
- //m_emergethread(this),
m_time_of_day_send_timer(0),
m_uptime(0),
m_shutdown_requested(false),
@@ -687,9 +688,19 @@ Server::Server(
infostream<<"- config: "<<m_path_config<<std::endl;
infostream<<"- game: "<<m_gamespec.path<<std::endl;
+ // Initialize default settings and override defaults with those provided
+ // by the game
+ set_default_settings(g_settings);
+ Settings gamedefaults;
+ getGameMinetestConfig(gamespec.path, gamedefaults);
+ override_default_settings(g_settings, &gamedefaults);
+
// Create biome definition manager
m_biomedef = new BiomeDefManager(this);
-
+
+ // Create emerge manager
+ m_emerge = new EmergeManager(this, m_biomedef);
+
// Create rollback manager
std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
m_rollback = createRollbackManager(rollback_path, this);
@@ -736,10 +747,10 @@ Server::Server(
}
// complain about mods declared to be loaded, but not found
for(std::vector<ModSpec>::iterator it = m_mods.begin();
- it != m_mods.end(); ++it)
+ it != m_mods.end(); ++it)
load_mod_names.erase((*it).name);
for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
- it != unsatisfied_mods.end(); ++it)
+ it != unsatisfied_mods.end(); ++it)
load_mod_names.erase((*it).name);
if(!load_mod_names.empty())
{
@@ -805,9 +816,6 @@ Server::Server(
// Add default biomes after nodedef had its aliases added
m_biomedef->addDefaultBiomes();
- // Create emerge manager
- m_emerge = new EmergeManager(this, m_biomedef);
-
// Initialize Environment
ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
m_env = new ServerEnvironment(servermap, m_lua, this, this);
@@ -854,13 +862,13 @@ Server::~Server()
/*
Send the message to clients
*/
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
// Get client and check that it is valid
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
@@ -909,13 +917,13 @@ Server::~Server()
{
JMutexAutoLock clientslock(m_con_mutex);
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
// Delete client
- delete i.getNode()->getValue();
+ delete i->second;
}
}
@@ -1073,11 +1081,11 @@ void Server::AsyncRunStep()
//JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
+ RemoteClient *client = i->second;
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
// Send as reliable
@@ -1117,11 +1125,11 @@ void Server::AsyncRunStep()
ScopeProfiler sp(g_profiler, "Server: handle players");
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
+ RemoteClient *client = i->second;
PlayerSAO *playersao = getPlayerSAO(client->peer_id);
if(playersao == NULL)
continue;
@@ -1161,7 +1169,7 @@ void Server::AsyncRunStep()
ScopeProfiler sp(g_profiler, "Server: liquid transform");
- core::map<v3s16, MapBlock*> modified_blocks;
+ std::map<v3s16, MapBlock*> modified_blocks;
m_env->getMap().transformLiquids(modified_blocks);
#if 0
/*
@@ -1186,11 +1194,11 @@ void Server::AsyncRunStep()
JMutexAutoLock lock2(m_con_mutex);
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
+ RemoteClient *client = i->second;
if(modified_blocks.size() > 0)
{
@@ -1212,12 +1220,12 @@ void Server::AsyncRunStep()
m_clients_number = 0;
if(m_clients.size() != 0)
infostream<<"Players:"<<std::endl;
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
//u16 peer_id = i.getNode()->getKey();
- RemoteClient *client = i.getNode()->getValue();
+ RemoteClient *client = i->second;
Player *player = m_env->getPlayer(client->peer_id);
if(player==NULL)
continue;
@@ -1235,7 +1243,7 @@ void Server::AsyncRunStep()
float &counter = m_masterserver_timer;
if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
{
- ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
+ ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id);
counter = 0.01;
}
counter += dtime;
@@ -1259,11 +1267,11 @@ void Server::AsyncRunStep()
s16 radius = g_settings->getS16("active_object_send_range_blocks");
radius *= MAP_BLOCKSIZE;
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
+ RemoteClient *client = i->second;
// If definitions and textures have not been sent, don't
// send objects either
@@ -1281,8 +1289,8 @@ void Server::AsyncRunStep()
}
v3s16 pos = floatToInt(player->getPosition(), BS);
- core::map<u16, bool> removed_objects;
- core::map<u16, bool> added_objects;
+ std::set<u16> removed_objects;
+ std::set<u16> added_objects;
m_env->getRemovedActiveObjects(pos, radius,
client->m_known_objects, removed_objects);
m_env->getAddedActiveObjects(pos, radius,
@@ -1302,20 +1310,20 @@ void Server::AsyncRunStep()
// Handle removed objects
writeU16((u8*)buf, removed_objects.size());
data_buffer.append(buf, 2);
- for(core::map<u16, bool>::Iterator
- i = removed_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<u16>::iterator
+ i = removed_objects.begin();
+ i != removed_objects.end(); ++i)
{
// Get object
- u16 id = i.getNode()->getKey();
+ u16 id = *i;
ServerActiveObject* obj = m_env->getActiveObject(id);
// Add to data buffer for sending
- writeU16((u8*)buf, i.getNode()->getKey());
+ writeU16((u8*)buf, id);
data_buffer.append(buf, 2);
// Remove from known objects
- client->m_known_objects.remove(i.getNode()->getKey());
+ client->m_known_objects.erase(id);
if(obj && obj->m_known_by_count > 0)
obj->m_known_by_count--;
@@ -1324,12 +1332,12 @@ void Server::AsyncRunStep()
// Handle added objects
writeU16((u8*)buf, added_objects.size());
data_buffer.append(buf, 2);
- for(core::map<u16, bool>::Iterator
- i = added_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<u16>::iterator
+ i = added_objects.begin();
+ i != added_objects.end(); ++i)
{
// Get object
- u16 id = i.getNode()->getKey();
+ u16 id = *i;
ServerActiveObject* obj = m_env->getActiveObject(id);
// Get object type
@@ -1353,7 +1361,7 @@ void Server::AsyncRunStep()
data_buffer.append(serializeLongString(""));
// Add to known objects
- client->m_known_objects.insert(i.getNode()->getKey(), false);
+ client->m_known_objects.insert(id);
if(obj)
obj->m_known_by_count++;
@@ -1412,7 +1420,7 @@ void Server::AsyncRunStep()
// Key = object id
// Value = data sent by object
- core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
+ std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
// Get active object messages from environment
for(;;)
@@ -1421,43 +1429,43 @@ void Server::AsyncRunStep()
if(aom.id == 0)
break;
- core::list<ActiveObjectMessage>* message_list = NULL;
- core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
+ std::list<ActiveObjectMessage>* message_list = NULL;
+ std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
n = buffered_messages.find(aom.id);
- if(n == NULL)
+ if(n == buffered_messages.end())
{
- message_list = new core::list<ActiveObjectMessage>;
- buffered_messages.insert(aom.id, message_list);
+ message_list = new std::list<ActiveObjectMessage>;
+ buffered_messages[aom.id] = message_list;
}
else
{
- message_list = n->getValue();
+ message_list = n->second;
}
message_list->push_back(aom);
}
// Route data to every client
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
+ RemoteClient *client = i->second;
std::string reliable_data;
std::string unreliable_data;
// Go through all objects in message buffer
- for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
- j = buffered_messages.getIterator();
- j.atEnd()==false; j++)
+ for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
+ j = buffered_messages.begin();
+ j != buffered_messages.end(); ++j)
{
// If object is not known by client, skip it
- u16 id = j.getNode()->getKey();
- if(client->m_known_objects.find(id) == NULL)
+ u16 id = j->first;
+ if(client->m_known_objects.find(id) == client->m_known_objects.end())
continue;
// Get message list of object
- core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
+ std::list<ActiveObjectMessage>* list = j->second;
// Go through every message
- for(core::list<ActiveObjectMessage>::Iterator
- k = list->begin(); k != list->end(); k++)
+ for(std::list<ActiveObjectMessage>::iterator
+ k = list->begin(); k != list->end(); ++k)
{
// Compose the full new data with header
ActiveObjectMessage aom = *k;
@@ -1508,11 +1516,11 @@ void Server::AsyncRunStep()
}
// Clear buffered_messages
- for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
- i = buffered_messages.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
+ i = buffered_messages.begin();
+ i != buffered_messages.end(); ++i)
{
- delete i.getNode()->getValue();
+ delete i->second;
}
}
@@ -1546,7 +1554,7 @@ void Server::AsyncRunStep()
// Players far away from the change are stored here.
// Instead of sending the changes, MapBlocks are set not sent
// for them.
- core::list<u16> far_players;
+ std::list<u16> far_players;
if(event->type == MEET_ADDNODE)
{
@@ -1580,12 +1588,11 @@ void Server::AsyncRunStep()
{
infostream<<"Server: MEET_OTHER"<<std::endl;
prof.add("MEET_OTHER", 1);
- for(core::map<v3s16, bool>::Iterator
- i = event->modified_blocks.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<v3s16>::iterator
+ i = event->modified_blocks.begin();
+ i != event->modified_blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
- setBlockNotSent(p);
+ setBlockNotSent(*i);
}
}
else
@@ -1601,19 +1608,18 @@ void Server::AsyncRunStep()
if(far_players.size() > 0)
{
// Convert list format to that wanted by SetBlocksNotSent
- core::map<v3s16, MapBlock*> modified_blocks2;
- for(core::map<v3s16, bool>::Iterator
- i = event->modified_blocks.getIterator();
- i.atEnd()==false; i++)
+ std::map<v3s16, MapBlock*> modified_blocks2;
+ for(std::set<v3s16>::iterator
+ i = event->modified_blocks.begin();
+ i != event->modified_blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
- modified_blocks2.insert(p,
- m_env->getMap().getBlockNoCreateNoEx(p));
+ modified_blocks2[*i] =
+ m_env->getMap().getBlockNoCreateNoEx(*i);
}
// Set blocks not sent
- for(core::list<u16>::Iterator
+ for(std::list<u16>::iterator
i = far_players.begin();
- i != far_players.end(); i++)
+ i != far_players.end(); ++i)
{
u16 peer_id = *i;
RemoteClient *client = getClient(peer_id);
@@ -1792,7 +1798,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
u8 client_max = data[2];
u8 our_max = SER_FMT_VER_HIGHEST;
// Use the highest version supported by both
- u8 deployed = core::min_(client_max, our_max);
+ u8 deployed = std::min(client_max, our_max);
// If it's lower than the lowest supported, give up.
if(deployed < SER_FMT_VER_LOWEST)
deployed = SER_FMT_VER_INVALID;
@@ -2074,7 +2080,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
SendMovement(m_con, peer_id);
// Send item definitions
- SendItemDef(m_con, peer_id, m_itemdef);
+ SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
// Send node definitions
SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
@@ -2143,12 +2149,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
{
std::ostringstream os(std::ios_base::binary);
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
// Get player
@@ -2520,13 +2526,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
/*
Send the message to clients
*/
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
// Get client and check that it is valid
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
@@ -2651,7 +2657,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
- core::list<MediaRequest> tosend;
+ std::list<MediaRequest> tosend;
u16 numfiles = readU16(is);
infostream<<"Sending "<<numfiles<<" files to "
@@ -3189,19 +3195,19 @@ void Server::setInventoryModified(const InventoryLocation &loc)
}
}
-core::list<PlayerInfo> Server::getPlayerInfo()
+std::list<PlayerInfo> Server::getPlayerInfo()
{
DSTACK(__FUNCTION_NAME);
JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);
- core::list<PlayerInfo> list;
+ std::list<PlayerInfo> list;
- core::list<Player*> players = m_env->getPlayers();
+ std::list<Player*> players = m_env->getPlayers();
- core::list<Player*>::Iterator i;
+ std::list<Player*>::iterator i;
for(i = players.begin();
- i != players.end(); i++)
+ i != players.end(); ++i)
{
PlayerInfo info;
@@ -3336,7 +3342,7 @@ void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
}
void Server::SendItemDef(con::Connection &con, u16 peer_id,
- IItemDefManager *itemdef)
+ IItemDefManager *itemdef, u16 protocol_version)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
@@ -3348,7 +3354,7 @@ void Server::SendItemDef(con::Connection &con, u16 peer_id,
*/
writeU16(os, TOCLIENT_ITEMDEF);
std::ostringstream tmp_os(std::ios::binary);
- itemdef->serialize(tmp_os);
+ itemdef->serialize(tmp_os, protocol_version);
std::ostringstream tmp_os2(std::ios::binary);
compressZlib(tmp_os.str(), tmp_os2);
os<<serializeLongString(tmp_os2.str());
@@ -3468,15 +3474,141 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, co
m_con.Send(peer_id, 0, data, true);
}
+// Spawns a particle on peer with peer_id
+void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ std::ostringstream os(std::ios_base::binary);
+ writeU16(os, TOCLIENT_SPAWN_PARTICLE);
+ writeV3F1000(os, pos);
+ writeV3F1000(os, velocity);
+ writeV3F1000(os, acceleration);
+ writeF1000(os, expirationtime);
+ writeF1000(os, size);
+ writeU8(os, collisiondetection);
+ os<<serializeLongString(texture);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
+// Spawns a particle on all peers
+void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
+{
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); i++)
+ {
+ // Get client and check that it is valid
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
+ if(client->serialization_version == SER_FMT_VER_INVALID)
+ continue;
+
+ SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
+ expirationtime, size, collisiondetection, texture);
+ }
+}
+
+// Adds a ParticleSpawner on peer with peer_id
+void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
+ v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
+ float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ std::ostringstream os(std::ios_base::binary);
+ writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
+
+ writeU16(os, amount);
+ writeF1000(os, spawntime);
+ writeV3F1000(os, minpos);
+ writeV3F1000(os, maxpos);
+ writeV3F1000(os, minvel);
+ writeV3F1000(os, maxvel);
+ writeV3F1000(os, minacc);
+ writeV3F1000(os, maxacc);
+ writeF1000(os, minexptime);
+ writeF1000(os, maxexptime);
+ writeF1000(os, minsize);
+ writeF1000(os, maxsize);
+ writeU8(os, collisiondetection);
+ os<<serializeLongString(texture);
+ writeU32(os, id);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
+// Adds a ParticleSpawner on all peers
+void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
+ v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
+ float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
+{
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); i++)
+ {
+ // Get client and check that it is valid
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
+ if(client->serialization_version == SER_FMT_VER_INVALID)
+ continue;
+
+ SendAddParticleSpawner(client->peer_id, amount, spawntime,
+ minpos, maxpos, minvel, maxvel, minacc, maxacc,
+ minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
+ }
+}
+
+void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ std::ostringstream os(std::ios_base::binary);
+ writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
+
+ writeU16(os, id);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendDeleteParticleSpawnerAll(u32 id)
+{
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); i++)
+ {
+ // Get client and check that it is valid
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
+ if(client->serialization_version == SER_FMT_VER_INVALID)
+ continue;
+
+ SendDeleteParticleSpawner(client->peer_id, id);
+ }
+}
+
void Server::BroadcastChatMessage(const std::wstring &message)
{
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
// Get client and check that it is valid
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
@@ -3595,10 +3727,10 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
}
else
{
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator(); i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin(); i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
+ RemoteClient *client = i->second;
Player *player = m_env->getPlayer(client->peer_id);
if(!player)
continue;
@@ -3668,7 +3800,7 @@ void Server::stopSound(s32 handle)
}
void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
- core::list<u16> *far_players, float far_d_nodes)
+ std::list<u16> *far_players, float far_d_nodes)
{
float maxd = far_d_nodes*BS;
v3f p_f = intToFloat(p, BS);
@@ -3681,13 +3813,13 @@ void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
writeS16(&reply[4], p.Y);
writeS16(&reply[6], p.Z);
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
// Get client and check that it is valid
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
@@ -3717,18 +3849,18 @@ void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
}
void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
- core::list<u16> *far_players, float far_d_nodes)
+ std::list<u16> *far_players, float far_d_nodes)
{
float maxd = far_d_nodes*BS;
v3f p_f = intToFloat(p, BS);
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
// Get client and check that it is valid
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
@@ -3768,11 +3900,11 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
void Server::setBlockNotSent(v3s16 p)
{
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
+ RemoteClient *client = i->second;
client->SetBlockNotSent(p);
}
}
@@ -3839,19 +3971,19 @@ void Server::SendBlocks(float dtime)
ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
- core::array<PrioritySortedBlockTransfer> queue;
+ std::vector<PrioritySortedBlockTransfer> queue;
s32 total_sending = 0;
{
ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
// If definitions and textures have not been sent, don't
// send MapBlocks either
@@ -3870,7 +4002,7 @@ void Server::SendBlocks(float dtime)
// Sort.
// Lowest priority number comes first.
// Lowest is most important.
- queue.sort();
+ std::sort(queue.begin(), queue.end());
for(u32 i=0; i<queue.size(); i++)
{
@@ -4017,7 +4149,7 @@ void Server::sendMediaAnnouncement(u16 peer_id)
verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
<<std::endl;
- core::list<SendableMediaAnnouncement> file_announcements;
+ std::list<SendableMediaAnnouncement> file_announcements;
for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
i != m_media.end(); i++){
@@ -4043,9 +4175,9 @@ void Server::sendMediaAnnouncement(u16 peer_id)
writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
writeU16(os, file_announcements.size());
- for(core::list<SendableMediaAnnouncement>::Iterator
+ for(std::list<SendableMediaAnnouncement>::iterator
j = file_announcements.begin();
- j != file_announcements.end(); j++){
+ j != file_announcements.end(); ++j){
os<<serializeString(j->name);
os<<serializeString(j->sha1_digest);
}
@@ -4074,7 +4206,7 @@ struct SendableMedia
};
void Server::sendRequestedMedia(u16 peer_id,
- const core::list<MediaRequest> &tosend)
+ const std::list<MediaRequest> &tosend)
{
DSTACK(__FUNCTION_NAME);
@@ -4086,13 +4218,13 @@ void Server::sendRequestedMedia(u16 peer_id,
// Put 5kB in one bunch (this is not accurate)
u32 bytes_per_bunch = 5000;
- core::array< core::list<SendableMedia> > file_bunches;
- file_bunches.push_back(core::list<SendableMedia>());
+ std::vector< std::list<SendableMedia> > file_bunches;
+ file_bunches.push_back(std::list<SendableMedia>());
u32 file_size_bunch_total = 0;
- for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
- i != tosend.end(); i++)
+ for(std::list<MediaRequest>::const_iterator i = tosend.begin();
+ i != tosend.end(); ++i)
{
if(m_media.find(i->name) == m_media.end()){
errorstream<<"Server::sendRequestedMedia(): Client asked for "
@@ -4138,7 +4270,7 @@ void Server::sendRequestedMedia(u16 peer_id,
// Start next bunch if got enough data
if(file_size_bunch_total >= bytes_per_bunch){
- file_bunches.push_back(core::list<SendableMedia>());
+ file_bunches.push_back(std::list<SendableMedia>());
file_size_bunch_total = 0;
}
@@ -4169,9 +4301,9 @@ void Server::sendRequestedMedia(u16 peer_id,
writeU16(os, i);
writeU32(os, file_bunches[i].size());
- for(core::list<SendableMedia>::Iterator
+ for(std::list<SendableMedia>::iterator
j = file_bunches[i].begin();
- j != file_bunches[i].end(); j++){
+ j != file_bunches[i].end(); ++j){
os<<serializeString(j->name);
os<<serializeLongString(j->data);
}
@@ -4212,10 +4344,10 @@ void Server::sendDetachedInventoryToAll(const std::string &name)
{
DSTACK(__FUNCTION_NAME);
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++){
- RemoteClient *client = i.getNode()->getValue();
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i){
+ RemoteClient *client = i->second;
sendDetachedInventory(name, client->peer_id);
}
}
@@ -4299,11 +4431,11 @@ RemoteClient* Server::getClient(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
//JMutexAutoLock lock(m_con_mutex);
- core::map<u16, RemoteClient*>::Node *n;
+ std::map<u16, RemoteClient*>::iterator n;
n = m_clients.find(peer_id);
// A client should exist for all peers
- assert(n != NULL);
- return n->getValue();
+ assert(n != m_clients.end());
+ return n->second;
}
std::wstring Server::getStatusString()
@@ -4315,15 +4447,15 @@ std::wstring Server::getStatusString()
// Uptime
os<<L", uptime="<<m_uptime.get();
// Information about clients
- core::map<u16, RemoteClient*>::Iterator i;
+ std::map<u16, RemoteClient*>::iterator i;
bool first;
os<<L", clients={";
- for(i = m_clients.getIterator(), first = true;
- i.atEnd() == false; i++)
+ for(i = m_clients.begin(), first = true;
+ i != m_clients.end(); ++i)
{
// Get client and check that it is valid
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
// Get player
@@ -4363,10 +4495,10 @@ bool Server::checkPriv(const std::string &name, const std::string &priv)
void Server::reportPrivsModified(const std::string &name)
{
if(name == ""){
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++){
- RemoteClient *client = i.getNode()->getValue();
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i){
+ RemoteClient *client = i->second;
Player *player = m_env->getPlayer(client->peer_id);
reportPrivsModified(player->getName());
}
@@ -4426,6 +4558,111 @@ void Server::notifyPlayers(const std::wstring msg)
BroadcastChatMessage(msg);
}
+void Server::spawnParticle(const char *playername, v3f pos,
+ v3f velocity, v3f acceleration,
+ float expirationtime, float size, bool
+ collisiondetection, std::string texture)
+{
+ Player *player = m_env->getPlayer(playername);
+ if(!player)
+ return;
+ SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
+ expirationtime, size, collisiondetection, texture);
+}
+
+void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
+ float expirationtime, float size,
+ bool collisiondetection, std::string texture)
+{
+ SendSpawnParticleAll(pos, velocity, acceleration,
+ expirationtime, size, collisiondetection, texture);
+}
+
+u32 Server::addParticleSpawner(const char *playername,
+ u16 amount, float spawntime,
+ v3f minpos, v3f maxpos,
+ v3f minvel, v3f maxvel,
+ v3f minacc, v3f maxacc,
+ float minexptime, float maxexptime,
+ float minsize, float maxsize,
+ bool collisiondetection, std::string texture)
+{
+ Player *player = m_env->getPlayer(playername);
+ if(!player)
+ return -1;
+
+ u32 id = 0;
+ for(;;) // look for unused particlespawner id
+ {
+ id++;
+ if (std::find(m_particlespawner_ids.begin(),
+ m_particlespawner_ids.end(), id)
+ == m_particlespawner_ids.end())
+ {
+ m_particlespawner_ids.push_back(id);
+ break;
+ }
+ }
+
+ SendAddParticleSpawner(player->peer_id, amount, spawntime,
+ minpos, maxpos, minvel, maxvel, minacc, maxacc,
+ minexptime, maxexptime, minsize, maxsize,
+ collisiondetection, texture, id);
+
+ return id;
+}
+
+u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
+ v3f minpos, v3f maxpos,
+ v3f minvel, v3f maxvel,
+ v3f minacc, v3f maxacc,
+ float minexptime, float maxexptime,
+ float minsize, float maxsize,
+ bool collisiondetection, std::string texture)
+{
+ u32 id = 0;
+ for(;;) // look for unused particlespawner id
+ {
+ id++;
+ if (std::find(m_particlespawner_ids.begin(),
+ m_particlespawner_ids.end(), id)
+ == m_particlespawner_ids.end())
+ {
+ m_particlespawner_ids.push_back(id);
+ break;
+ }
+ }
+
+ SendAddParticleSpawnerAll(amount, spawntime,
+ minpos, maxpos, minvel, maxvel, minacc, maxacc,
+ minexptime, maxexptime, minsize, maxsize,
+ collisiondetection, texture, id);
+
+ return id;
+}
+
+void Server::deleteParticleSpawner(const char *playername, u32 id)
+{
+ Player *player = m_env->getPlayer(playername);
+ if(!player)
+ return;
+
+ m_particlespawner_ids.erase(
+ std::remove(m_particlespawner_ids.begin(),
+ m_particlespawner_ids.end(), id),
+ m_particlespawner_ids.end());
+ SendDeleteParticleSpawner(player->peer_id, id);
+}
+
+void Server::deleteParticleSpawnerAll(u32 id)
+{
+ m_particlespawner_ids.erase(
+ std::remove(m_particlespawner_ids.begin(),
+ m_particlespawner_ids.end(), id),
+ m_particlespawner_ids.end());
+ SendDeleteParticleSpawnerAll(id);
+}
+
void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
{
m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
@@ -4579,11 +4816,11 @@ const ModSpec* Server::getModSpec(const std::string &modname)
}
return NULL;
}
-void Server::getModNames(core::list<std::string> &modlist)
+void Server::getModNames(std::list<std::string> &modlist)
{
for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
{
- modlist.push_back((*i).name);
+ modlist.push_back(i->name);
}
}
std::string Server::getBuiltinLuaPath()
@@ -4733,15 +4970,15 @@ void Server::handlePeerChange(PeerChange &c)
*/
// Error check
- core::map<u16, RemoteClient*>::Node *n;
+ std::map<u16, RemoteClient*>::iterator n;
n = m_clients.find(c.peer_id);
// The client shouldn't already exist
- assert(n == NULL);
+ assert(n == m_clients.end());
// Create client
RemoteClient *client = new RemoteClient();
client->peer_id = c.peer_id;
- m_clients.insert(client->peer_id, client);
+ m_clients[client->peer_id] = client;
} // PEER_ADDED
else if(c.type == PEER_REMOVED)
@@ -4751,22 +4988,22 @@ void Server::handlePeerChange(PeerChange &c)
*/
// Error check
- core::map<u16, RemoteClient*>::Node *n;
+ std::map<u16, RemoteClient*>::iterator n;
n = m_clients.find(c.peer_id);
// The client should exist
- assert(n != NULL);
+ assert(n != m_clients.end());
/*
Mark objects to be not known by the client
*/
- RemoteClient *client = n->getValue();
+ RemoteClient *client = n->second;
// Handle objects
- for(core::map<u16, bool>::Iterator
- i = client->m_known_objects.getIterator();
- i.atEnd()==false; i++)
+ for(std::set<u16>::iterator
+ i = client->m_known_objects.begin();
+ i != client->m_known_objects.end(); ++i)
{
// Get object
- u16 id = i.getNode()->getKey();
+ u16 id = *i;
ServerActiveObject* obj = m_env->getActiveObject(id);
if(obj && obj->m_known_by_count > 0)
@@ -4824,12 +5061,12 @@ void Server::handlePeerChange(PeerChange &c)
if(player != NULL)
{
std::ostringstream os(std::ios_base::binary);
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<u16, RemoteClient*>::iterator
+ i = m_clients.begin();
+ i != m_clients.end(); ++i)
{
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
+ RemoteClient *client = i->second;
+ assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
// Get player
@@ -4849,7 +5086,7 @@ void Server::handlePeerChange(PeerChange &c)
// Delete client
delete m_clients[c.peer_id];
- m_clients.remove(c.peer_id);
+ m_clients.erase(c.peer_id);
// Send player info to all remaining clients
//SendPlayerInfos();
diff --git a/src/server.h b/src/server.h
index d7700791c..04e693fc8 100644
--- a/src/server.h
+++ b/src/server.h
@@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
#include "rollback_interface.h" // Needed for rollbackRevertActions()
#include <list> // Needed for rollbackRevertActions()
+#include <algorithm>
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@@ -166,7 +167,7 @@ struct PrioritySortedBlockTransfer
pos = a_pos;
peer_id = a_peer_id;
}
- bool operator < (PrioritySortedBlockTransfer &other)
+ bool operator < (const PrioritySortedBlockTransfer &other) const
{
return priority < other.priority;
}
@@ -271,14 +272,14 @@ public:
dtime is used for resetting send radius at slow interval
*/
void GetNextBlocks(Server *server, float dtime,
- core::array<PrioritySortedBlockTransfer> &dest);
+ std::vector<PrioritySortedBlockTransfer> &dest);
void GotBlock(v3s16 p);
void SentBlock(v3s16 p);
void SetBlockNotSent(v3s16 p);
- void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks);
+ void SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks);
s32 SendingCount()
{
@@ -314,7 +315,7 @@ public:
List of active objects that the client knows of.
Value is dummy.
*/
- core::map<u16, bool> m_known_objects;
+ std::set<u16> m_known_objects;
private:
/*
@@ -326,7 +327,7 @@ private:
Key is position, value is dummy.
No MapBlock* is stored here because the blocks can get deleted.
*/
- core::map<v3s16, bool> m_blocks_sent;
+ std::set<v3s16> m_blocks_sent;
s16 m_nearest_unsent_d;
v3s16 m_last_center;
float m_nearest_unsent_reset_timer;
@@ -339,7 +340,7 @@ private:
Block is removed when GOTBLOCKS is received.
Value is time from sending. (not used at the moment)
*/
- core::map<v3s16, float> m_blocks_sending;
+ std::map<v3s16, float> m_blocks_sending;
/*
Count of excess GotBlocks().
@@ -381,7 +382,7 @@ public:
void Receive();
void ProcessData(u8 *data, u32 datasize, u16 peer_id);
- core::list<PlayerInfo> getPlayerInfo();
+ std::list<PlayerInfo> getPlayerInfo();
// Environment must be locked when called
void setTimeOfDay(u32 time)
@@ -455,6 +456,35 @@ public:
// Envlock and conlock should be locked when calling this
void notifyPlayer(const char *name, const std::wstring msg);
void notifyPlayers(const std::wstring msg);
+ void spawnParticle(const char *playername,
+ v3f pos, v3f velocity, v3f acceleration,
+ float expirationtime, float size,
+ bool collisiondetection, std::string texture);
+
+ void spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
+ float expirationtime, float size,
+ bool collisiondetection, std::string texture);
+
+ u32 addParticleSpawner(const char *playername,
+ u16 amount, float spawntime,
+ v3f minpos, v3f maxpos,
+ v3f minvel, v3f maxvel,
+ v3f minacc, v3f maxacc,
+ float minexptime, float maxexptime,
+ float minsize, float maxsize,
+ bool collisiondetection, std::string texture);
+
+ u32 addParticleSpawnerAll(u16 amount, float spawntime,
+ v3f minpos, v3f maxpos,
+ v3f minvel, v3f maxvel,
+ v3f minacc, v3f maxacc,
+ float minexptime, float maxexptime,
+ float minsize, float maxsize,
+ bool collisiondetection, std::string texture);
+
+ void deleteParticleSpawner(const char *playername, u32 id);
+ void deleteParticleSpawnerAll(u32 id);
+
void queueBlockEmerge(v3s16 blockpos, bool allow_generate);
@@ -494,7 +524,7 @@ public:
IWritableCraftDefManager* getWritableCraftDefManager();
const ModSpec* getModSpec(const std::string &modname);
- void getModNames(core::list<std::string> &modlist);
+ void getModNames(std::list<std::string> &modlist);
std::string getBuiltinLuaPath();
std::string getWorldPath(){ return m_path_world; }
@@ -526,7 +556,7 @@ private:
static void SendDeathscreen(con::Connection &con, u16 peer_id,
bool set_camera_point_target, v3f camera_point_target);
static void SendItemDef(con::Connection &con, u16 peer_id,
- IItemDefManager *itemdef);
+ IItemDefManager *itemdef, u16 protocol_version);
static void SendNodeDef(con::Connection &con, u16 peer_id,
INodeDefManager *nodedef, u16 protocol_version);
@@ -553,9 +583,9 @@ private:
*/
// Envlock and conlock should be locked when calling these
void sendRemoveNode(v3s16 p, u16 ignore_id=0,
- core::list<u16> *far_players=NULL, float far_d_nodes=100);
+ std::list<u16> *far_players=NULL, float far_d_nodes=100);
void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0,
- core::list<u16> *far_players=NULL, float far_d_nodes=100);
+ std::list<u16> *far_players=NULL, float far_d_nodes=100);
void setBlockNotSent(v3s16 p);
// Environment and Connection must be locked when called
@@ -567,12 +597,47 @@ private:
void fillMediaCache();
void sendMediaAnnouncement(u16 peer_id);
void sendRequestedMedia(u16 peer_id,
- const core::list<MediaRequest> &tosend);
+ const std::list<MediaRequest> &tosend);
void sendDetachedInventory(const std::string &name, u16 peer_id);
void sendDetachedInventoryToAll(const std::string &name);
void sendDetachedInventories(u16 peer_id);
+ // Adds a ParticleSpawner on peer with peer_id
+ void SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime,
+ v3f minpos, v3f maxpos,
+ v3f minvel, v3f maxvel,
+ v3f minacc, v3f maxacc,
+ float minexptime, float maxexptime,
+ float minsize, float maxsize,
+ bool collisiondetection, std::string texture, u32 id);
+
+ // Adds a ParticleSpawner on all peers
+ void SendAddParticleSpawnerAll(u16 amount, float spawntime,
+ v3f minpos, v3f maxpos,
+ v3f minvel, v3f maxvel,
+ v3f minacc, v3f maxacc,
+ float minexptime, float maxexptime,
+ float minsize, float maxsize,
+ bool collisiondetection, std::string texture, u32 id);
+
+ // Deletes ParticleSpawner on a single client
+ void SendDeleteParticleSpawner(u16 peer_id, u32 id);
+
+ // Deletes ParticleSpawner on all clients
+ void SendDeleteParticleSpawnerAll(u32 id);
+
+ // Spawns particle on single client
+ void SendSpawnParticle(u16 peer_id,
+ v3f pos, v3f velocity, v3f acceleration,
+ float expirationtime, float size,
+ bool collisiondetection, std::string texture);
+
+ // Spawns particle on all clients
+ void SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
+ float expirationtime, float size,
+ bool collisiondetection, std::string texture);
+
/*
Something random
*/
@@ -655,7 +720,7 @@ private:
con::Connection m_con;
JMutex m_con_mutex;
// Connected clients (behind the con mutex)
- core::map<u16, RemoteClient*> m_clients;
+ std::map<u16, RemoteClient*> m_clients;
u16 m_clients_number; //for announcing masterserver
// Bann checking
@@ -735,7 +800,7 @@ private:
*/
// Mod parent directory paths
- core::list<std::string> m_modspaths;
+ std::list<std::string> m_modspaths;
bool m_shutdown_requested;
@@ -789,6 +854,11 @@ private:
*/
// key = name
std::map<std::string, Inventory*> m_detached_inventories;
+
+ /*
+ Particles
+ */
+ std::vector<u32> m_particlespawner_ids;
};
/*
diff --git a/src/serverlist.cpp b/src/serverlist.cpp
index d37b5d637..93f9d2435 100644
--- a/src/serverlist.cpp
+++ b/src/serverlist.cpp
@@ -232,7 +232,7 @@ static size_t ServerAnnounceCallback(void *contents, size_t size, size_t nmemb,
//((std::string*)userp)->append((char*)contents, size * nmemb);
//return size * nmemb;
}
-void sendAnnounce(std::string action, u16 clients) {
+void sendAnnounce(std::string action, u16 clients, double uptime, std::string gameid) {
Json::Value server;
if (action.size())
server["action"] = action;
@@ -250,6 +250,9 @@ void sendAnnounce(std::string action, u16 clients) {
server["pvp"] = g_settings->getBool("enable_pvp");
server["clients"] = clients;
server["clients_max"] = g_settings->get("max_users");
+ if (uptime >=1) server["uptime"] = (int)uptime;
+ if (gameid!="") server["gameid"] = gameid;
+
}
if(server["action"] == "start")
actionstream << "announcing to " << g_settings->get("serverlist_url") << std::endl;
@@ -259,6 +262,7 @@ void sendAnnounce(std::string action, u16 clients) {
if (curl)
{
CURLcode res;
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_URL, (g_settings->get("serverlist_url")+std::string("/announce?json=")+curl_easy_escape(curl, writer.write( server ).c_str(), 0)).c_str());
//curl_easy_setopt(curl, CURLOPT_USERAGENT, "minetest");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ServerList::ServerAnnounceCallback);
diff --git a/src/serverlist.h b/src/serverlist.h
index e81e64c5b..d01415c50 100644
--- a/src/serverlist.h
+++ b/src/serverlist.h
@@ -39,7 +39,7 @@ namespace ServerList
std::vector<ServerListSpec> deSerializeJson(std::string liststring);
std::string serializeJson(std::vector<ServerListSpec>);
#if USE_CURL
- void sendAnnounce(std::string action = "", u16 clients = 0);
+ void sendAnnounce(std::string action = "", u16 clients = 0, double uptime = 0, std::string gameid = "");
#endif
} //ServerList namespace
diff --git a/src/serverobject.cpp b/src/serverobject.cpp
index beb17d31f..95735de17 100644
--- a/src/serverobject.cpp
+++ b/src/serverobject.cpp
@@ -43,9 +43,9 @@ ServerActiveObject* ServerActiveObject::create(u8 type,
const std::string &data)
{
// Find factory function
- core::map<u16, Factory>::Node *n;
+ std::map<u16, Factory>::iterator n;
n = m_types.find(type);
- if(n == NULL)
+ if(n == m_types.end())
{
// If factory is not found, just return.
dstream<<"WARNING: ServerActiveObject: No factory for type="
@@ -53,18 +53,18 @@ ServerActiveObject* ServerActiveObject::create(u8 type,
return NULL;
}
- Factory f = n->getValue();
+ Factory f = n->second;
ServerActiveObject *object = (*f)(env, pos, data);
return object;
}
void ServerActiveObject::registerType(u16 type, Factory f)
{
- core::map<u16, Factory>::Node *n;
+ std::map<u16, Factory>::iterator n;
n = m_types.find(type);
- if(n)
+ if(n != m_types.end())
return;
- m_types.insert(type, f);
+ m_types[type] = f;
}
float ServerActiveObject::getMinimumSavedMovement()
diff --git a/src/serverobject.h b/src/serverobject.h
index 6525270f6..7a5b47bd1 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -235,7 +235,7 @@ protected:
private:
// Used for creating objects based on type
- static core::map<u16, Factory> m_types;
+ static std::map<u16, Factory> m_types;
};
#endif
diff --git a/src/settings.h b/src/settings.h
index 7ac308cc0..1b7e3cb09 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -33,6 +33,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "util/string.h"
#include "porting.h"
+#include <list>
+#include <map>
+#include <set>
enum ValueType
{
@@ -63,12 +66,12 @@ public:
{
JMutexAutoLock lock(m_mutex);
- for(core::map<std::string, std::string>::Iterator
- i = m_settings.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<std::string, std::string>::iterator
+ i = m_settings.begin();
+ i != m_settings.end(); ++i)
{
- std::string name = i.getNode()->getKey();
- std::string value = i.getNode()->getValue();
+ std::string name = i->first;
+ std::string value = i->second;
os<<name<<" = "<<value<<"\n";
}
}
@@ -76,12 +79,11 @@ public:
// return all keys used
std::vector<std::string> getNames(){
std::vector<std::string> names;
- for(core::map<std::string, std::string>::Iterator
- i = m_settings.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<std::string, std::string>::iterator
+ i = m_settings.begin();
+ i != m_settings.end(); ++i)
{
- std::string name = i.getNode()->getKey();
- names.push_back(name);
+ names.push_back(i->first);
}
return names;
}
@@ -89,7 +91,7 @@ public:
// remove a setting
bool remove(const std::string& name)
{
- return m_settings.remove(name);
+ return m_settings.erase(name);
}
@@ -188,8 +190,8 @@ public:
Returns false on EOF
*/
bool getUpdatedConfigObject(std::istream &is,
- core::list<std::string> &dst,
- core::map<std::string, bool> &updated,
+ std::list<std::string> &dst,
+ std::set<std::string> &updated,
bool &value_changed)
{
JMutexAutoLock lock(m_mutex);
@@ -228,7 +230,7 @@ public:
std::string value = sf.next("\n");
value = trim(value);
- if(m_settings.find(name))
+ if(m_settings.find(name) != m_settings.end())
{
std::string newvalue = m_settings[name];
@@ -242,7 +244,7 @@ public:
dst.push_back(name + " = " + newvalue + line_end);
- updated[name] = true;
+ updated.insert(name);
}
else //file contains a setting which is not in m_settings
value_changed=true;
@@ -260,8 +262,8 @@ public:
infostream<<"Updating configuration file: \""
<<filename<<"\""<<std::endl;
- core::list<std::string> objects;
- core::map<std::string, bool> updated;
+ std::list<std::string> objects;
+ std::set<std::string> updated;
bool something_actually_changed = false;
// Read and modify stuff
@@ -286,11 +288,11 @@ public:
// If something not yet determined to have been changed, check if
// any new stuff was added
if(!something_actually_changed){
- for(core::map<std::string, std::string>::Iterator
- i = m_settings.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<std::string, std::string>::iterator
+ i = m_settings.begin();
+ i != m_settings.end(); ++i)
{
- if(updated.find(i.getNode()->getKey()))
+ if(updated.find(i->first) != updated.end())
continue;
something_actually_changed = true;
break;
@@ -318,9 +320,9 @@ public:
/*
Write updated stuff
*/
- for(core::list<std::string>::Iterator
+ for(std::list<std::string>::iterator
i = objects.begin();
- i != objects.end(); i++)
+ i != objects.end(); ++i)
{
os<<(*i);
}
@@ -328,14 +330,14 @@ public:
/*
Write stuff that was not already in the file
*/
- for(core::map<std::string, std::string>::Iterator
- i = m_settings.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<std::string, std::string>::iterator
+ i = m_settings.begin();
+ i != m_settings.end(); ++i)
{
- if(updated.find(i.getNode()->getKey()))
+ if(updated.find(i->first) != updated.end())
continue;
- std::string name = i.getNode()->getKey();
- std::string value = i.getNode()->getValue();
+ std::string name = i->first;
+ std::string value = i->second;
infostream<<"Adding \""<<name<<"\" = \""<<value<<"\""
<<std::endl;
os<<name<<" = "<<value<<"\n";
@@ -351,7 +353,7 @@ public:
returns true on success
*/
bool parseCommandLine(int argc, char *argv[],
- core::map<std::string, ValueSpec> &allowed_options)
+ std::map<std::string, ValueSpec> &allowed_options)
{
int nonopt_index = 0;
int i=1;
@@ -379,16 +381,16 @@ public:
std::string name = argname.substr(2);
- core::map<std::string, ValueSpec>::Node *n;
+ std::map<std::string, ValueSpec>::iterator n;
n = allowed_options.find(name);
- if(n == NULL)
+ if(n == allowed_options.end())
{
errorstream<<"Unknown command-line parameter \""
<<argname<<"\""<<std::endl;
return false;
}
- ValueType type = n->getValue().type;
+ ValueType type = n->second.type;
std::string value = "";
@@ -444,25 +446,25 @@ public:
{
JMutexAutoLock lock(m_mutex);
- return (m_settings.find(name) || m_defaults.find(name));
+ return (m_settings.find(name) != m_settings.end() || m_defaults.find(name) != m_defaults.end());
}
std::string get(std::string name)
{
JMutexAutoLock lock(m_mutex);
- core::map<std::string, std::string>::Node *n;
+ std::map<std::string, std::string>::iterator n;
n = m_settings.find(name);
- if(n == NULL)
+ if(n == m_settings.end())
{
n = m_defaults.find(name);
- if(n == NULL)
+ if(n == m_defaults.end())
{
- throw SettingNotFoundException("Setting not found");
+ throw SettingNotFoundException(("Setting [" + name + "] not found ").c_str());
}
}
- return n->getValue();
+ return n->second;
}
bool getBool(std::string name)
@@ -919,19 +921,8 @@ fail:
if(&other == this)
return;
- for(core::map<std::string, std::string>::Iterator
- i = other.m_settings.getIterator();
- i.atEnd() == false; i++)
- {
- m_settings[i.getNode()->getKey()] = i.getNode()->getValue();
- }
-
- for(core::map<std::string, std::string>::Iterator
- i = other.m_defaults.getIterator();
- i.atEnd() == false; i++)
- {
- m_defaults[i.getNode()->getKey()] = i.getNode()->getValue();
- }
+ m_settings.insert(other.m_settings.begin(), other.m_settings.end());
+ m_defaults.insert(other.m_defaults.begin(), other.m_defaults.end());
return;
}
@@ -944,21 +935,7 @@ fail:
if(&other == this)
return *this;
- for(core::map<std::string, std::string>::Iterator
- i = other.m_settings.getIterator();
- i.atEnd() == false; i++)
- {
- m_settings.insert(i.getNode()->getKey(),
- i.getNode()->getValue());
- }
-
- for(core::map<std::string, std::string>::Iterator
- i = other.m_defaults.getIterator();
- i.atEnd() == false; i++)
- {
- m_defaults.insert(i.getNode()->getKey(),
- i.getNode()->getValue());
- }
+ update(other);
return *this;
@@ -979,8 +956,8 @@ fail:
}
private:
- core::map<std::string, std::string> m_settings;
- core::map<std::string, std::string> m_defaults;
+ std::map<std::string, std::string> m_settings;
+ std::map<std::string, std::string> m_defaults;
// All methods that access m_settings/m_defaults directly should lock this.
JMutex m_mutex;
};
diff --git a/src/shader.cpp b/src/shader.cpp
index 7e3d16e8b..a224c82bb 100644
--- a/src/shader.cpp
+++ b/src/shader.cpp
@@ -125,10 +125,10 @@ public:
const std::string &filename)
{
std::string combined = name_of_shader + DIR_DELIM + filename;
- core::map<std::string, std::string>::Node *n;
+ std::map<std::string, std::string>::iterator n;
n = m_programs.find(combined);
- if(n)
- return n->getValue();
+ if(n != m_programs.end())
+ return n->second;
return "";
}
// Primarily fetches from cache, secondarily tries to read from filesystem
@@ -136,10 +136,10 @@ public:
const std::string &filename)
{
std::string combined = name_of_shader + DIR_DELIM + filename;
- core::map<std::string, std::string>::Node *n;
+ std::map<std::string, std::string>::iterator n;
n = m_programs.find(combined);
- if(n)
- return n->getValue();
+ if(n != m_programs.end())
+ return n->second;
std::string path = getShaderPath(name_of_shader, filename);
if(path == ""){
infostream<<"SourceShaderCache::getOrLoad(): No path found for \""
@@ -156,7 +156,7 @@ public:
return "";
}
private:
- core::map<std::string, std::string> m_programs;
+ std::map<std::string, std::string> m_programs;
std::string readFile(const std::string &path)
{
std::ifstream is(path.c_str(), std::ios::binary);
@@ -332,9 +332,9 @@ private:
// A shader id is index in this array.
// The first position contains a dummy shader.
- core::array<ShaderInfo> m_shaderinfo_cache;
+ std::vector<ShaderInfo> m_shaderinfo_cache;
// Maps a shader name to an index in the former.
- core::map<std::string, u32> m_name_to_id;
+ std::map<std::string, u32> m_name_to_id;
// The two former containers are behind this mutex
JMutex m_shaderinfo_cache_mutex;
@@ -343,7 +343,7 @@ private:
// Global constant setters
// TODO: Delete these in the destructor
- core::array<IShaderConstantSetter*> m_global_setters;
+ std::vector<IShaderConstantSetter*> m_global_setters;
};
IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
@@ -399,10 +399,10 @@ u32 ShaderSource::getShaderId(const std::string &name)
See if shader already exists
*/
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
- if(n != NULL)
- return n->getValue();
+ if(n != m_name_to_id.end())
+ return n->second;
}
/*
@@ -471,12 +471,12 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
{
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
- if(n != NULL){
+ if(n != m_name_to_id.end()){
/*infostream<<"getShaderIdDirect(): \""<<name
<<"\" found in cache"<<std::endl;*/
- return n->getValue();
+ return n->second;
}
}
@@ -494,7 +494,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
u32 id = m_shaderinfo_cache.size();
m_shaderinfo_cache.push_back(info);
- m_name_to_id.insert(name, id);
+ m_name_to_id[name] = id;
/*infostream<<"getShaderIdDirect(): "
<<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
@@ -531,7 +531,7 @@ void ShaderSource::processQueue()
/*
Fetch shaders
*/
- if(m_get_shader_queue.size() > 0){
+ if(!m_get_shader_queue.empty()){
GetRequest<std::string, u32, u8, u8>
request = m_get_shader_queue.pop();
diff --git a/src/staticobject.cpp b/src/staticobject.cpp
index 48fadaf06..973257fcf 100644
--- a/src/staticobject.cpp
+++ b/src/staticobject.cpp
@@ -58,18 +58,18 @@ void StaticObjectList::serialize(std::ostream &os)
u16 count = m_stored.size() + m_active.size();
writeU16((u8*)buf, count);
os.write(buf, 2);
- for(core::list<StaticObject>::Iterator
+ for(std::list<StaticObject>::iterator
i = m_stored.begin();
- i != m_stored.end(); i++)
+ i != m_stored.end(); ++i)
{
StaticObject &s_obj = *i;
s_obj.serialize(os);
}
- for(core::map<u16, StaticObject>::Iterator
- i = m_active.getIterator();
- i.atEnd()==false; i++)
+ for(std::map<u16, StaticObject>::iterator
+ i = m_active.begin();
+ i != m_active.end(); ++i)
{
- StaticObject s_obj = i.getNode()->getValue();
+ StaticObject s_obj = i->second;
s_obj.serialize(os);
}
}
diff --git a/src/staticobject.h b/src/staticobject.h
index c8427fe47..640747e96 100644
--- a/src/staticobject.h
+++ b/src/staticobject.h
@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h"
#include <string>
#include <sstream>
+#include <list>
+#include <map>
#include "debug.h"
struct StaticObject
@@ -62,27 +64,27 @@ public:
}
else
{
- if(m_active.find(id) != NULL)
+ if(m_active.find(id) != m_active.end())
{
dstream<<"ERROR: StaticObjectList::insert(): "
<<"id already exists"<<std::endl;
assert(0);
return;
}
- m_active.insert(id, obj);
+ m_active[id] = obj;
}
}
void remove(u16 id)
{
assert(id != 0);
- if(m_active.find(id) == NULL)
+ if(m_active.find(id) == m_active.end())
{
dstream<<"WARNING: StaticObjectList::remove(): id="<<id
<<" not found"<<std::endl;
return;
}
- m_active.remove(id);
+ m_active.erase(id);
}
void serialize(std::ostream &os);
@@ -93,8 +95,8 @@ public:
from m_stored and inserted to m_active.
The caller directly manipulates these containers.
*/
- core::list<StaticObject> m_stored;
- core::map<u16, StaticObject> m_active;
+ std::list<StaticObject> m_stored;
+ std::map<u16, StaticObject> m_active;
private:
};
diff --git a/src/strfnd.h b/src/strfnd.h
index d28aa73b2..4a72edf3c 100644
--- a/src/strfnd.h
+++ b/src/strfnd.h
@@ -65,6 +65,25 @@ public:
//std::cout<<"palautus=\""<<palautus<<"\""<<std::endl;
return palautus;
}
+
+ // Returns substr of tek up to the next occurence of plop that isn't escaped with '\'
+ std::string next_esc(std::string plop) {
+ size_t n, realp;
+
+ if (p >= tek.size())
+ return "";
+
+ realp = p;
+ do {
+ n = tek.find(plop, p);
+ if (n == std::string::npos || plop == "")
+ n = tek.length();
+ p = n + plop.length();
+ } while (n > 0 && tek[n - 1] == '\\');
+
+ return tek.substr(realp, n - realp);
+ }
+
void skip_over(std::string chars){
while(p < tek.size()){
bool is = false;
@@ -128,6 +147,24 @@ public:
//std::cout<<"palautus=\""<<palautus<<"\""<<std::endl;
return palautus;
}
+
+ std::wstring next_esc(std::wstring plop) {
+ size_t n, realp;
+
+ if (p >= tek.size())
+ return L"";
+
+ realp = p;
+ do {
+ n = tek.find(plop, p);
+ if (n == std::wstring::npos || plop == L"")
+ n = tek.length();
+ p = n + plop.length();
+ } while (n > 0 && tek[n - 1] == '\\');
+
+ return tek.substr(realp, n - realp);
+ }
+
bool atend(){
if(p>=tek.size()) return true;
return false;
diff --git a/src/subgame.cpp b/src/subgame.cpp
index 3c8bf53c5..19ad4e636 100644
--- a/src/subgame.cpp
+++ b/src/subgame.cpp
@@ -24,12 +24,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "util/string.h"
-std::string getGameName(const std::string &game_path)
+bool getGameMinetestConfig(const std::string &game_path, Settings &conf)
+{
+ std::string conf_path = game_path + DIR_DELIM + "minetest.conf";
+ return conf.readConfigFile(conf_path.c_str());
+}
+
+bool getGameConfig(const std::string &game_path, Settings &conf)
{
std::string conf_path = game_path + DIR_DELIM + "game.conf";
+ return conf.readConfigFile(conf_path.c_str());
+}
+
+std::string getGameName(const std::string &game_path)
+{
Settings conf;
- bool succeeded = conf.readConfigFile(conf_path.c_str());
- if(!succeeded)
+ if(!getGameConfig(game_path, conf))
return "";
if(!conf.exists("name"))
return "";
@@ -117,6 +127,11 @@ std::set<std::string> getAvailableGameIds()
for(u32 j=0; j<dirlist.size(); j++){
if(!dirlist[j].dir)
continue;
+ // If configuration file is not found or broken, ignore game
+ Settings conf;
+ if(!getGameConfig(*i + DIR_DELIM + dirlist[j].name, conf))
+ continue;
+ // Add it to result
const char *ends[] = {"_game", NULL};
std::string shorter = removeStringEnd(dirlist[j].name, ends);
if(shorter != "")
diff --git a/src/subgame.h b/src/subgame.h
index 8561c1a52..b120b7542 100644
--- a/src/subgame.h
+++ b/src/subgame.h
@@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <set>
#include <vector>
+class Settings;
+
#define WORLDNAME_BLACKLISTED_CHARS "/\\"
struct SubgameSpec
@@ -52,6 +54,11 @@ struct SubgameSpec
}
};
+// minetest.conf
+bool getGameMinetestConfig(const std::string &game_path, Settings &conf);
+// game.conf
+bool getGameConfig(const std::string &game_path, Settings &conf);
+
std::string getGameName(const std::string &game_path);
SubgameSpec findSubgame(const std::string &id);
diff --git a/src/test.cpp b/src/test.cpp
index d86868118..d18bd8b93 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -42,6 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/serialize.h"
#include "noise.h" // PseudoRandom used for random data for compression
#include "clientserver.h" // LATEST_PROTOCOL_VERSION
+#include <algorithm>
/*
Asserts that the exception occurs
@@ -508,26 +509,26 @@ struct TestVoxelManipulator: public TestBase
// An area that is 1 bigger in x+ and z-
VoxelArea d(v3s16(-2,-2,-3), v3s16(3,2,2));
- core::list<VoxelArea> aa;
+ std::list<VoxelArea> aa;
d.diff(c, aa);
// Correct results
- core::array<VoxelArea> results;
+ std::vector<VoxelArea> results;
results.push_back(VoxelArea(v3s16(-2,-2,-3),v3s16(3,2,-3)));
results.push_back(VoxelArea(v3s16(3,-2,-2),v3s16(3,2,2)));
UASSERT(aa.size() == results.size());
infostream<<"Result of diff:"<<std::endl;
- for(core::list<VoxelArea>::Iterator
- i = aa.begin(); i != aa.end(); i++)
+ for(std::list<VoxelArea>::const_iterator
+ i = aa.begin(); i != aa.end(); ++i)
{
i->print(infostream);
infostream<<std::endl;
- s32 j = results.linear_search(*i);
- UASSERT(j != -1);
- results.erase(j, 1);
+ std::vector<VoxelArea>::iterator j = std::find(results.begin(), results.end(), *i);
+ UASSERT(j != results.end());
+ results.erase(j);
}
@@ -582,7 +583,7 @@ struct TestVoxelAlgorithms: public TestBase
}
VoxelArea a(v3s16(0,0,0), v3s16(2,2,2));
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, true, light_sources, ndef);
@@ -593,7 +594,7 @@ struct TestVoxelAlgorithms: public TestBase
}
v.setNodeNoRef(v3s16(0,0,0), MapNode(CONTENT_STONE));
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, true, light_sources, ndef);
@@ -602,7 +603,7 @@ struct TestVoxelAlgorithms: public TestBase
== LIGHT_SUN);
}
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, false, light_sources, ndef);
@@ -612,7 +613,7 @@ struct TestVoxelAlgorithms: public TestBase
}
v.setNodeNoRef(v3s16(1,3,2), MapNode(CONTENT_STONE));
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, true, light_sources, ndef);
@@ -621,7 +622,7 @@ struct TestVoxelAlgorithms: public TestBase
== 0);
}
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, false, light_sources, ndef);
@@ -635,14 +636,14 @@ struct TestVoxelAlgorithms: public TestBase
v.setNodeNoRef(v3s16(1,-1,2), n);
}
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, true, light_sources, ndef);
UASSERT(res.bottom_sunlight_valid == true);
}
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, false, light_sources, ndef);
@@ -654,14 +655,14 @@ struct TestVoxelAlgorithms: public TestBase
v.setNodeNoRef(v3s16(1,-1,2), n);
}
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, true, light_sources, ndef);
UASSERT(res.bottom_sunlight_valid == false);
}
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, false, light_sources, ndef);
@@ -669,7 +670,7 @@ struct TestVoxelAlgorithms: public TestBase
}
v.setNodeNoRef(v3s16(1,3,2), MapNode(CONTENT_IGNORE));
{
- core::map<v3s16, bool> light_sources;
+ std::set<v3s16> light_sources;
voxalgo::setLight(v, a, 0, ndef);
voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
v, a, true, light_sources, ndef);
@@ -697,16 +698,16 @@ struct TestVoxelAlgorithms: public TestBase
v.setNode(v3s16(1,1,2), n);
}
{
- core::map<v3s16, bool> light_sources;
- core::map<v3s16, u8> unlight_from;
+ std::set<v3s16> light_sources;
+ std::map<v3s16, u8> unlight_from;
voxalgo::clearLightAndCollectSources(v, a, LIGHTBANK_DAY,
ndef, light_sources, unlight_from);
//v.print(dstream, ndef, VOXELPRINT_LIGHT_DAY);
UASSERT(v.getNode(v3s16(0,1,1)).getLight(LIGHTBANK_DAY, ndef)
== 0);
- UASSERT(light_sources.find(v3s16(1,1,1)) != NULL);
+ UASSERT(light_sources.find(v3s16(1,1,1)) != light_sources.end());
UASSERT(light_sources.size() == 1);
- UASSERT(unlight_from.find(v3s16(1,1,2)) != NULL);
+ UASSERT(unlight_from.find(v3s16(1,1,2)) != unlight_from.end());
UASSERT(unlight_from.size() == 1);
}
}
diff --git a/src/tile.cpp b/src/tile.cpp
index 7286293d8..aea9665f5 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -206,10 +206,10 @@ public:
{
assert(img);
// Remove old image
- core::map<std::string, video::IImage*>::Node *n;
+ std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name);
- if(n){
- video::IImage *oldimg = n->getValue();
+ if(n != m_images.end()){
+ video::IImage *oldimg = n->second;
if(oldimg)
oldimg->drop();
}
@@ -229,20 +229,20 @@ public:
}
video::IImage* get(const std::string &name)
{
- core::map<std::string, video::IImage*>::Node *n;
+ std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name);
- if(n)
- return n->getValue();
+ if(n != m_images.end())
+ return n->second;
return NULL;
}
// Primarily fetches from cache, secondarily tries to read from filesystem
video::IImage* getOrLoad(const std::string &name, IrrlichtDevice *device)
{
- core::map<std::string, video::IImage*>::Node *n;
+ std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name);
- if(n){
- n->getValue()->grab(); // Grab for caller
- return n->getValue();
+ if(n != m_images.end()){
+ n->second->grab(); // Grab for caller
+ return n->second;
}
video::IVideoDriver* driver = device->getVideoDriver();
std::string path = getTexturePath(name.c_str());
@@ -263,7 +263,7 @@ public:
return img;
}
private:
- core::map<std::string, video::IImage*> m_images;
+ std::map<std::string, video::IImage*> m_images;
};
/*
@@ -417,9 +417,9 @@ private:
// A texture id is index in this array.
// The first position contains a NULL texture.
- core::array<SourceAtlasPointer> m_atlaspointer_cache;
+ std::vector<SourceAtlasPointer> m_atlaspointer_cache;
// Maps a texture name to an index in the former.
- core::map<std::string, u32> m_name_to_id;
+ std::map<std::string, u32> m_name_to_id;
// The two former containers are behind this mutex
JMutex m_atlaspointer_cache_mutex;
@@ -465,11 +465,11 @@ u32 TextureSource::getTextureId(const std::string &name)
See if texture already exists
*/
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
- if(n != NULL)
+ if(n != m_name_to_id.end())
{
- return n->getValue();
+ return n->second;
}
}
@@ -579,13 +579,13 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
{
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
- if(n != NULL)
+ if(n != m_name_to_id.end())
{
/*infostream<<"getTextureIdDirect(): \""<<name
<<"\" found in cache"<<std::endl;*/
- return n->getValue();
+ return n->second;
}
}
@@ -724,7 +724,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
baseimg_dim = baseimg->getDimension();
SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim);
m_atlaspointer_cache.push_back(nap);
- m_name_to_id.insert(name, id);
+ m_name_to_id[name] = id;
/*infostream<<"getTextureIdDirect(): "
<<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
@@ -769,7 +769,7 @@ void TextureSource::processQueue()
/*
Fetch textures
*/
- if(m_get_texture_queue.size() > 0)
+ if(!m_get_texture_queue.empty())
{
GetRequest<std::string, u32, u8, u8>
request = m_get_texture_queue.pop();
@@ -872,7 +872,7 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
main content features
*/
- core::map<std::string, bool> sourcelist;
+ std::set<std::string> sourcelist;
for(u16 j=0; j<MAX_CONTENT+1; j++)
{
@@ -882,16 +882,16 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
for(u32 i=0; i<6; i++)
{
std::string name = f.tiledef[i].name;
- sourcelist[name] = true;
+ sourcelist.insert(name);
}
}
infostream<<"Creating texture atlas out of textures: ";
- for(core::map<std::string, bool>::Iterator
- i = sourcelist.getIterator();
- i.atEnd() == false; i++)
+ for(std::set<std::string>::iterator
+ i = sourcelist.begin();
+ i != sourcelist.end(); ++i)
{
- std::string name = i.getNode()->getKey();
+ std::string name = *i;
infostream<<"\""<<name<<"\" ";
}
infostream<<std::endl;
@@ -910,11 +910,11 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
pos_in_atlas.X = column_padding;
pos_in_atlas.Y = padding;
- for(core::map<std::string, bool>::Iterator
- i = sourcelist.getIterator();
- i.atEnd() == false; i++)
+ for(std::set<std::string>::iterator
+ i = sourcelist.begin();
+ i != sourcelist.end(); ++i)
{
- std::string name = i.getNode()->getKey();
+ std::string name = *i;
// Generate image by name
video::IImage *img2 = generate_image_from_scratch(name, m_device,
@@ -1026,11 +1026,11 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
bool reuse_old_id = false;
u32 id = m_atlaspointer_cache.size();
// Check old id without fetching a texture
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
// If it exists, we will replace the old definition
- if(n){
- id = n->getValue();
+ if(n != m_name_to_id.end()){
+ id = n->second;
reuse_old_id = true;
/*infostream<<"TextureSource::buildMainAtlas(): "
<<"Replacing old AtlasPointer"<<std::endl;*/
@@ -1066,12 +1066,12 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
/*
Second pass: set texture pointer in generated AtlasPointers
*/
- for(core::map<std::string, bool>::Iterator
- i = sourcelist.getIterator();
- i.atEnd() == false; i++)
+ for(std::set<std::string>::iterator
+ i = sourcelist.begin();
+ i != sourcelist.end(); ++i)
{
- std::string name = i.getNode()->getKey();
- if(m_name_to_id.find(name) == NULL)
+ std::string name = *i;
+ if(m_name_to_id.find(name) == m_name_to_id.end())
continue;
u32 id = m_name_to_id[name];
//infostream<<"id of name "<<name<<" is "<<id<<std::endl;
diff --git a/src/tile.h b/src/tile.h
index 07e5bcb56..c5c7f9303 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -205,7 +205,8 @@ struct TileSpec
texture == other.texture &&
alpha == other.alpha &&
material_type == other.material_type &&
- material_flags == other.material_flags
+ material_flags == other.material_flags &&
+ rotation == other.rotation
);
}
@@ -264,6 +265,7 @@ struct TileSpec
// Animation parameters
u8 animation_frame_count;
u16 animation_frame_length_ms;
+ u8 rotation;
};
#endif
diff --git a/src/tool.cpp b/src/tool.cpp
index 04f19749c..4d809e2c4 100644
--- a/src/tool.cpp
+++ b/src/tool.cpp
@@ -24,9 +24,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/serialize.h"
#include "util/numeric.h"
-void ToolCapabilities::serialize(std::ostream &os) const
+void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const
{
- writeU8(os, 1); // version
+ if(protocol_version <= 17)
+ writeU8(os, 1); // version
+ else
+ writeU8(os, 2); // version
writeF1000(os, full_punch_interval);
writeS16(os, max_drop_level);
writeU32(os, groupcaps.size());
@@ -44,12 +47,20 @@ void ToolCapabilities::serialize(std::ostream &os) const
writeF1000(os, i->second);
}
}
+ if(protocol_version > 17){
+ writeU32(os, damageGroups.size());
+ for(std::map<std::string, s16>::const_iterator
+ i = damageGroups.begin(); i != damageGroups.end(); i++){
+ os<<serializeString(i->first);
+ writeS16(os, i->second);
+ }
+ }
}
void ToolCapabilities::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version != 1) throw SerializationError(
+ if(version != 1 && version != 2) throw SerializationError(
"unsupported ToolCapabilities version");
full_punch_interval = readF1000(is);
max_drop_level = readS16(is);
@@ -68,6 +79,15 @@ void ToolCapabilities::deSerialize(std::istream &is)
}
groupcaps[name] = cap;
}
+ if(version == 2)
+ {
+ u32 damage_groups_size = readU32(is);
+ for(u32 i=0; i<damage_groups_size; i++){
+ std::string name = deSerializeString(is);
+ s16 rating = readS16(is);
+ damageGroups[name] = rating;
+ }
+ }
}
DigParams getDigParams(const ItemGroupList &groups,
@@ -136,28 +156,26 @@ DigParams getDigParams(const ItemGroupList &groups,
return getDigParams(groups, tp, 1000000);
}
-HitParams getHitParams(const ItemGroupList &groups,
+HitParams getHitParams(const ItemGroupList &armor_groups,
const ToolCapabilities *tp, float time_from_last_punch)
{
- DigParams digprop = getDigParams(groups, tp,
- time_from_last_punch);
-
- if(time_from_last_punch > tp->full_punch_interval)
- time_from_last_punch = tp->full_punch_interval;
- // Damage in hp is equivalent to nodes dug in time_from_last_punch
- s16 hp = 0;
- if(digprop.diggable)
- hp = time_from_last_punch / digprop.time;
- // Wear is the same as for digging a single node
- s16 wear = (float)digprop.wear;
-
- return HitParams(hp, wear, digprop.main_group);
+ s16 damage = 0;
+ float full_punch_interval = tp->full_punch_interval;
+
+ for(std::map<std::string, s16>::const_iterator
+ i = tp->damageGroups.begin(); i != tp->damageGroups.end(); i++){
+ s16 armor = itemgroup_get(armor_groups, i->first);
+ damage += i->second * rangelim(time_from_last_punch * full_punch_interval, 0.0, 1.0)
+ * armor / 100.0;
+ }
+
+ return HitParams(damage, 0);
}
-HitParams getHitParams(const ItemGroupList &groups,
+HitParams getHitParams(const ItemGroupList &armor_groups,
const ToolCapabilities *tp)
{
- return getHitParams(groups, tp, 1000000);
+ return getHitParams(armor_groups, tp, 1000000);
}
PunchDamageResult getPunchDamage(
@@ -187,7 +205,6 @@ PunchDamageResult getPunchDamage(
result.did_punch = true;
result.wear = hitparams.wear;
result.damage = hitparams.hp;
- result.main_group = hitparams.main_group;
}
return result;
diff --git a/src/tool.h b/src/tool.h
index e812a9e36..509561a16 100644
--- a/src/tool.h
+++ b/src/tool.h
@@ -52,6 +52,7 @@ struct ToolGroupCap
// CLANG SUCKS DONKEY BALLS
typedef std::map<std::string, struct ToolGroupCap> ToolGCMap;
+typedef std::map<std::string, s16> DamageGroup;
struct ToolCapabilities
{
@@ -59,19 +60,22 @@ struct ToolCapabilities
int max_drop_level;
// CLANG SUCKS DONKEY BALLS
ToolGCMap groupcaps;
+ DamageGroup damageGroups;
ToolCapabilities(
float full_punch_interval_=1.4,
int max_drop_level_=1,
// CLANG SUCKS DONKEY BALLS
- ToolGCMap groupcaps_=ToolGCMap()
+ ToolGCMap groupcaps_=ToolGCMap(),
+ DamageGroup damageGroups_=DamageGroup()
):
full_punch_interval(full_punch_interval_),
max_drop_level(max_drop_level_),
- groupcaps(groupcaps_)
+ groupcaps(groupcaps_),
+ damageGroups(damageGroups_)
{}
- void serialize(std::ostream &os) const;
+ void serialize(std::ostream &os, u16 version) const;
void deSerialize(std::istream &is);
};
@@ -103,19 +107,17 @@ struct HitParams
{
s16 hp;
s16 wear;
- std::string main_group;
- HitParams(s16 hp_=0, s16 wear_=0, std::string main_group_=""):
+ HitParams(s16 hp_=0, s16 wear_=0):
hp(hp_),
- wear(wear_),
- main_group(main_group_)
+ wear(wear_)
{}
};
-HitParams getHitParams(const ItemGroupList &groups,
+HitParams getHitParams(const ItemGroupList &armor_groups,
const ToolCapabilities *tp, float time_from_last_punch);
-HitParams getHitParams(const ItemGroupList &groups,
+HitParams getHitParams(const ItemGroupList &armor_groups,
const ToolCapabilities *tp);
struct PunchDamageResult
@@ -123,7 +125,6 @@ struct PunchDamageResult
bool did_punch;
int damage;
int wear;
- std::string main_group;
PunchDamageResult():
did_punch(false),
diff --git a/src/treegen.cpp b/src/treegen.cpp
index 7b6152329..808cf916a 100644
--- a/src/treegen.cpp
+++ b/src/treegen.cpp
@@ -28,15 +28,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
namespace treegen
{
+
void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
- bool is_apple_tree, INodeDefManager *ndef,int seed)
+ bool is_apple_tree, INodeDefManager *ndef, int seed)
{
MapNode treenode(ndef->getId("mapgen_tree"));
MapNode leavesnode(ndef->getId("mapgen_leaves"));
MapNode applenode(ndef->getId("mapgen_apple"));
- PseudoRandom ps(seed);
- s16 trunk_h = ps.range(4, 5);
+ PseudoRandom pr(seed);
+ s16 trunk_h = pr.range(4, 5);
v3s16 p1 = p0;
for(s16 ii=0; ii<trunk_h; ii++)
{
@@ -72,9 +73,9 @@ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
s16 d = 1;
v3s16 p(
- ps.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
- ps.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
- ps.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
+ pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
+ pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
+ pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
);
for(s16 z=0; z<=d; z++)
@@ -100,7 +101,7 @@ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
continue;
u32 i = leaves_a.index(x,y,z);
if(leaves_d[i] == 1) {
- bool is_apple = ps.range(0,99) < 10;
+ bool is_apple = pr.range(0,99) < 10;
if(is_apple_tree && is_apple) {
vmanip.m_data[vi] = applenode;
} else {
@@ -111,10 +112,10 @@ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
}
// L-System tree LUA spawner
-void spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition)
+void spawn_ltree(ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition)
{
ServerMap *map = &env->getServerMap();
- core::map<v3s16, MapBlock*> modified_blocks;
+ std::map<v3s16, MapBlock*> modified_blocks;
ManualMapVoxelManipulator vmanip(map);
v3s16 tree_blockp = getNodeBlockPos(p0);
vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,3,1));
@@ -122,23 +123,17 @@ void spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeD
vmanip.blitBackAll(&modified_blocks);
// update lighting
- core::map<v3s16, MapBlock*> lighting_modified_blocks;
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
- {
- lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
- }
+ std::map<v3s16, MapBlock*> lighting_modified_blocks;
+ lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
map->updateLighting(lighting_modified_blocks, modified_blocks);
// Send a MEET_OTHER event
MapEditEvent event;
event.type = MEET_OTHER;
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
- event.modified_blocks.insert(p, true);
+ event.modified_blocks.insert(i->first);
}
map->dispatchEvent(&event);
}
@@ -512,33 +507,48 @@ v3f transposeMatrix(irr::core::matrix4 M, v3f v)
return translated;
}
-#if 0
-static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
- INodeDefManager *ndef)
+void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
+ INodeDefManager *ndef, int seed)
{
- MapNode treenode(ndef->getId("mapgen_jungletree"));
- MapNode leavesnode(ndef->getId("mapgen_leaves"));
+ content_t c_tree = ndef->getId("mapgen_jungletree");
+ content_t c_leaves = ndef->getId("mapgen_jungleleaves");
+ if (c_tree == CONTENT_IGNORE)
+ c_tree = ndef->getId("mapgen_tree");
+ if (c_leaves == CONTENT_IGNORE)
+ c_leaves = ndef->getId("mapgen_leaves");
+
+ MapNode treenode(c_tree);
+ MapNode leavesnode(c_leaves);
+ PseudoRandom pr(seed);
for(s16 x=-1; x<=1; x++)
for(s16 z=-1; z<=1; z++)
{
- if(myrand_range(0, 2) == 0)
+ if(pr.range(0, 2) == 0)
continue;
v3s16 p1 = p0 + v3s16(x,0,z);
v3s16 p2 = p0 + v3s16(x,-1,z);
- if(vmanip.m_area.contains(p2)
- && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
- vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
- else if(vmanip.m_area.contains(p1))
- vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+ u32 vi1 = vmanip.m_area.index(p1);
+ u32 vi2 = vmanip.m_area.index(p2);
+
+ if (vmanip.m_area.contains(p2) &&
+ vmanip.m_data[vi2].getContent() == CONTENT_AIR)
+ vmanip.m_data[vi2] = treenode;
+ else if (vmanip.m_area.contains(p1) &&
+ vmanip.m_data[vi1].getContent() == CONTENT_AIR)
+ vmanip.m_data[vi1] = treenode;
}
+ vmanip.m_data[vmanip.m_area.index(p0)] = treenode;
- s16 trunk_h = myrand_range(8, 12);
+ s16 trunk_h = pr.range(8, 12);
v3s16 p1 = p0;
- for(s16 ii=0; ii<trunk_h; ii++)
+ for (s16 ii=0; ii<trunk_h; ii++)
{
- if(vmanip.m_area.contains(p1))
- vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+ if (vmanip.m_area.contains(p1)) {
+ u32 vi = vmanip.m_area.index(p1);
+ if (vmanip.m_data[vi].getContent() == CONTENT_AIR)
+ vmanip.m_data[vi] = treenode;
+ }
p1.Y++;
}
@@ -568,9 +578,9 @@ static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
s16 d = 1;
v3s16 p(
- myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
- myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
- myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
+ pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
+ pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
+ pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
);
for(s16 z=0; z<=d; z++)
@@ -591,14 +601,13 @@ static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
if(vmanip.m_area.contains(p) == false)
continue;
u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() != CONTENT_AIR
- && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+ if (vmanip.m_data[vi].getContent() != CONTENT_AIR &&
+ vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
continue;
u32 i = leaves_a.index(x,y,z);
if(leaves_d[i] == 1)
vmanip.m_data[vi] = leavesnode;
}
}
-#endif
}; // namespace treegen
diff --git a/src/treegen.h b/src/treegen.h
index ca4d3e23d..16c85cf0a 100644
--- a/src/treegen.h
+++ b/src/treegen.h
@@ -27,33 +27,36 @@ class ManualMapVoxelManipulator;
class INodeDefManager;
-namespace treegen
-{
+namespace treegen {
-struct TreeDef
-{
-std::string initial_axiom;
-std::string rules_a;
-std::string rules_b;
-std::string rules_c;
-std::string rules_d;
-MapNode trunknode;
-MapNode leavesnode;
-MapNode leaves2node;
-int leaves2_chance;
-int angle;
-int iterations;
-int iterations_random_level;
-std::string trunk_type;
-bool thin_branches;
-MapNode fruitnode;
-int fruit_chance;
-int seed;
-};
+ struct TreeDef {
+ std::string initial_axiom;
+ std::string rules_a;
+ std::string rules_b;
+ std::string rules_c;
+ std::string rules_d;
+
+ MapNode trunknode;
+ MapNode leavesnode;
+ MapNode leaves2node;
+
+ int leaves2_chance;
+ int angle;
+ int iterations;
+ int iterations_random_level;
+ std::string trunk_type;
+ bool thin_branches;
+ MapNode fruitnode;
+ int fruit_chance;
+ int seed;
+ };
// Add default tree
void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
- bool is_apple_tree, INodeDefManager *ndef,int seed);
+ bool is_apple_tree, INodeDefManager *ndef, int seed);
+ // Add jungle tree
+ void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
+ INodeDefManager *ndef, int seed);
// Add L-Systems tree (used by engine)
void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef,
@@ -73,7 +76,7 @@ int seed;
PseudoRandom ps, TreeDef &tree_definition);
void tree_fruit_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
TreeDef &tree_definition);
- irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle,v3f axis);
+ irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis);
v3f transposeMatrix(irr::core::matrix4 M ,v3f v);
diff --git a/src/util/container.h b/src/util/container.h
index 775372649..9bb388f0e 100644
--- a/src/util/container.h
+++ b/src/util/container.h
@@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <jmutex.h>
#include <jmutexautolock.h>
#include "../porting.h" // For sleep_ms
+#include <list>
+#include <vector>
/*
Queue with unique values with fast checking of value existence
@@ -43,11 +45,11 @@ public:
bool push_back(Value value)
{
// Check if already exists
- if(m_map.find(value) != NULL)
+ if(m_map.find(value) != m_map.end())
return false;
// Add
- m_map.insert(value, 0);
+ m_map[value] = 0;
m_list.push_back(value);
return true;
@@ -55,22 +57,21 @@ public:
Value pop_front()
{
- typename core::list<Value>::Iterator i = m_list.begin();
+ typename std::list<Value>::iterator i = m_list.begin();
Value value = *i;
- m_map.remove(value);
+ m_map.erase(value);
m_list.erase(i);
return value;
}
u32 size()
{
- assert(m_list.size() == m_map.size());
- return m_list.size();
+ return m_map.size();
}
private:
- core::map<Value, u8> m_map;
- core::list<Value> m_list;
+ std::map<Value, u8> m_map;
+ std::list<Value> m_list;
};
#if 1
@@ -95,31 +96,31 @@ public:
{
JMutexAutoLock lock(m_mutex);
- typename core::map<Key, Value>::Node *n;
+ typename std::map<Key, Value>::iterator n;
n = m_values.find(name);
- if(n == NULL)
+ if(n == m_values.end())
return false;
if(result != NULL)
- *result = n->getValue();
+ *result = n->second;
return true;
}
- core::list<Value> getValues()
+ std::list<Value> getValues()
{
- core::list<Value> result;
- for(typename core::map<Key, Value>::Iterator
- i = m_values.getIterator();
- i.atEnd() == false; i++){
- result.push_back(i.getNode()->getValue());
+ std::list<Value> result;
+ for(typename std::map<Key, Value>::iterator
+ i = m_values.begin();
+ i != m_values.end(); ++i){
+ result.push_back(i->second);
}
return result;
}
private:
- core::map<Key, Value> m_values;
+ std::map<Key, Value> m_values;
JMutex m_mutex;
};
#endif
@@ -163,10 +164,10 @@ public:
u32 getId(const T &value)
{
JMutexAutoLock lock(m_mutex);
- typename core::map<T, u32>::Node *n;
+ typename std::map<T, u32>::iterator n;
n = m_value_to_id.find(value);
- if(n != NULL)
- return n->getValue();
+ if(n != m_value_to_id.end())
+ return n->second;
m_id_to_value.push_back(value);
u32 new_id = m_id_to_value.size();
m_value_to_id.insert(value, new_id);
@@ -176,8 +177,8 @@ public:
private:
JMutex m_mutex;
// Values are stored here at id-1 position (id 1 = [0])
- core::array<T> m_id_to_value;
- core::map<T, u32> m_value_to_id;
+ std::vector<T> m_id_to_value;
+ std::map<T, u32> m_value_to_id;
};
/*
@@ -187,39 +188,52 @@ template<typename T>
class Queue
{
public:
+ Queue():
+ m_list_size(0)
+ {}
+
void push_back(T t)
{
m_list.push_back(t);
+ ++m_list_size;
}
T pop_front()
{
- if(m_list.size() == 0)
+ if(m_list.empty())
throw ItemNotFoundException("Queue: queue is empty");
- typename core::list<T>::Iterator begin = m_list.begin();
+ typename std::list<T>::iterator begin = m_list.begin();
T t = *begin;
m_list.erase(begin);
+ --m_list_size;
return t;
}
T pop_back()
{
- if(m_list.size() == 0)
+ if(m_list.empty())
throw ItemNotFoundException("Queue: queue is empty");
- typename core::list<T>::Iterator last = m_list.getLast();
+ typename std::list<T>::iterator last = m_list.back();
T t = *last;
m_list.erase(last);
+ --m_list_size;
return t;
}
u32 size()
{
- return m_list.size();
+ return m_list_size;
+ }
+
+ bool empty()
+ {
+ return m_list.empty();
}
protected:
- core::list<T> m_list;
+ std::list<T> m_list;
+ u32 m_list_size;
};
/*
@@ -234,10 +248,10 @@ public:
{
m_mutex.Init();
}
- u32 size()
+ bool empty()
{
JMutexAutoLock lock(m_mutex);
- return m_list.size();
+ return m_list.empty();
}
void push_back(T t)
{
@@ -253,9 +267,9 @@ public:
{
JMutexAutoLock lock(m_mutex);
- if(m_list.size() > 0)
+ if(!m_list.empty())
{
- typename core::list<T>::Iterator begin = m_list.begin();
+ typename std::list<T>::iterator begin = m_list.begin();
T t = *begin;
m_list.erase(begin);
return t;
@@ -279,9 +293,9 @@ public:
{
JMutexAutoLock lock(m_mutex);
- if(m_list.size() > 0)
+ if(!m_list.empty())
{
- typename core::list<T>::Iterator last = m_list.getLast();
+ typename std::list<T>::iterator last = m_list.back();
T t = *last;
m_list.erase(last);
return t;
@@ -302,14 +316,14 @@ public:
return m_mutex;
}
- core::list<T> & getList()
+ std::list<T> & getList()
{
return m_list;
}
protected:
JMutex m_mutex;
- core::list<T> m_list;
+ std::list<T> m_list;
};
#endif
diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp
index a79454628..ed83df7d7 100644
--- a/src/util/numeric.cpp
+++ b/src/util/numeric.cpp
@@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream>
// Calculate the borders of a "d-radius" cube
-void getFacePositions(core::list<v3s16> &list, u16 d)
+void getFacePositions(std::list<v3s16> &list, u16 d)
{
if(d == 0)
{
diff --git a/src/util/numeric.h b/src/util/numeric.h
index 450a98e40..e66af2376 100644
--- a/src/util/numeric.h
+++ b/src/util/numeric.h
@@ -25,9 +25,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "../irr_v3d.h"
#include "../irr_aabb3d.h"
#include <irrList.h>
+#include <list>
// Calculate the borders of a "d-radius" cube
-void getFacePositions(core::list<v3s16> &list, u16 d);
+void getFacePositions(std::list<v3s16> &list, u16 d);
class IndentationRaiser
{
diff --git a/src/util/string.h b/src/util/string.h
index 2f0264bd4..6c48adeb3 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -286,6 +286,22 @@ inline std::string wrap_rows(const std::string &from, u32 rowlen)
return to;
}
+/*
+ Removes all \\ from a string that had been escaped (FormSpec strings)
+*/
+inline std::string unescape_string(std::string &s)
+{
+ std::string res;
+
+ for (size_t i = 0; i <= s.length(); i++) {
+ if (s[i] == '\\')
+ i++;
+ res += s[i];
+ }
+
+ return res;
+}
+
std::string translatePassword(std::string playername, std::wstring password);
size_t curl_write_data(char *ptr, size_t size, size_t nmemb, void *userdata);
u32 readFlagString(std::string str, FlagDesc *flagdesc);
diff --git a/src/util/thread.h b/src/util/thread.h
index 949bb4204..6b2cf5b6c 100644
--- a/src/util/thread.h
+++ b/src/util/thread.h
@@ -120,7 +120,7 @@ class GetResult
public:
Key key;
T item;
- core::list<CallerInfo<Caller, CallerData> > callers;
+ std::list<CallerInfo<Caller, CallerData> > callers;
};
template<typename Key, typename T, typename Caller, typename CallerData>
@@ -152,16 +152,16 @@ public:
Key key;
ResultQueue<Key, T, Caller, CallerData> *dest;
- core::list<CallerInfo<Caller, CallerData> > callers;
+ std::list<CallerInfo<Caller, CallerData> > callers;
};
template<typename Key, typename T, typename Caller, typename CallerData>
class RequestQueue
{
public:
- u32 size()
+ bool empty()
{
- return m_queue.size();
+ return m_queue.empty();
}
void add(Key key, Caller caller, CallerData callerdata,
@@ -172,17 +172,17 @@ public:
/*
If the caller is already on the list, only update CallerData
*/
- for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
+ for(typename std::list< GetRequest<Key, T, Caller, CallerData> >::iterator
i = m_queue.getList().begin();
- i != m_queue.getList().end(); i++)
+ i != m_queue.getList().end(); ++i)
{
GetRequest<Key, T, Caller, CallerData> &request = *i;
if(request.key == key)
{
- for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
+ for(typename std::list< CallerInfo<Caller, CallerData> >::iterator
i = request.callers.begin();
- i != request.callers.end(); i++)
+ i != request.callers.end(); ++i)
{
CallerInfo<Caller, CallerData> &ca = *i;
if(ca.caller == caller)
diff --git a/src/util/timetaker.cpp b/src/util/timetaker.cpp
index 910fea822..720a9e1a9 100644
--- a/src/util/timetaker.cpp
+++ b/src/util/timetaker.cpp
@@ -23,19 +23,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "../log.h"
#include <ostream>
-TimeTaker::TimeTaker(const char *name, u32 *result)
+TimeTaker::TimeTaker(const char *name, u32 *result, TimePrecision prec)
{
m_name = name;
m_result = result;
m_running = true;
- m_time1 = getTimeMs();
+ m_precision = prec;
+ m_time1 = getTime(prec);
}
u32 TimeTaker::stop(bool quiet)
{
if(m_running)
{
- u32 time2 = getTimeMs();
+ u32 time2 = getTime(m_precision);
u32 dtime = time2 - m_time1;
if(m_result != NULL)
{
@@ -52,9 +53,9 @@ u32 TimeTaker::stop(bool quiet)
return 0;
}
-u32 TimeTaker::getTime()
+u32 TimeTaker::getTimerTime()
{
- u32 time2 = getTimeMs();
+ u32 time2 = getTime(m_precision);
u32 dtime = time2 - m_time1;
return dtime;
}
diff --git a/src/util/timetaker.h b/src/util/timetaker.h
index 0b9d9ca04..5512c205f 100644
--- a/src/util/timetaker.h
+++ b/src/util/timetaker.h
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define UTIL_TIMETAKER_HEADER
#include "../irrlichttypes.h"
+#include "../gettime.h"
/*
TimeTaker
@@ -29,7 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class TimeTaker
{
public:
- TimeTaker(const char *name, u32 *result=NULL);
+ TimeTaker(const char *name, u32 *result=NULL,
+ TimePrecision=PRECISION_MILLI);
~TimeTaker()
{
@@ -38,12 +40,13 @@ public:
u32 stop(bool quiet=false);
- u32 getTime();
+ u32 getTimerTime();
private:
const char *m_name;
u32 m_time1;
bool m_running;
+ TimePrecision m_precision;
u32 *m_result;
};
diff --git a/src/voxel.cpp b/src/voxel.cpp
index c55f3f539..f859a1f03 100644
--- a/src/voxel.cpp
+++ b/src/voxel.cpp
@@ -302,7 +302,7 @@ void VoxelManipulator::clearFlag(u8 flags)
}
void VoxelManipulator::unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
- core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr)
+ std::set<v3s16> & light_sources, INodeDefManager *nodemgr)
{
v3s16 dirs[6] = {
v3s16(0,0,1), // back
@@ -360,7 +360,7 @@ void VoxelManipulator::unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
}
}
else{
- light_sources.insert(n2pos, true);
+ light_sources.insert(n2pos);
}
}
}
@@ -384,24 +384,16 @@ void VoxelManipulator::unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
values of from_nodes are lighting values.
*/
void VoxelManipulator::unspreadLight(enum LightBank bank,
- core::map<v3s16, u8> & from_nodes,
- core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr)
+ std::map<v3s16, u8> & from_nodes,
+ std::set<v3s16> & light_sources, INodeDefManager *nodemgr)
{
if(from_nodes.size() == 0)
return;
- core::map<v3s16, u8>::Iterator j;
- j = from_nodes.getIterator();
-
- for(; j.atEnd() == false; j++)
+ for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
+ j != from_nodes.end(); ++j)
{
- v3s16 pos = j.getNode()->getKey();
-
- //MapNode &n = m_data[m_area.index(pos)];
-
- u8 oldlight = j.getNode()->getValue();
-
- unspreadLight(bank, pos, oldlight, light_sources, nodemgr);
+ unspreadLight(bank, j->first, j->second, light_sources, nodemgr);
}
}
#endif
@@ -609,7 +601,7 @@ void VoxelManipulator::spreadLight(enum LightBank bank,
goes on recursively.
*/
void VoxelManipulator::spreadLight(enum LightBank bank,
- core::map<v3s16, bool> & from_nodes, INodeDefManager *nodemgr)
+ std::set<v3s16> & from_nodes, INodeDefManager *nodemgr)
{
const v3s16 dirs[6] = {
v3s16(0,0,1), // back
@@ -623,13 +615,12 @@ void VoxelManipulator::spreadLight(enum LightBank bank,
if(from_nodes.size() == 0)
return;
- core::map<v3s16, bool> lighted_nodes;
- core::map<v3s16, bool>::Iterator j;
- j = from_nodes.getIterator();
+ std::set<v3s16> lighted_nodes;
- for(; j.atEnd() == false; j++)
+ for(std::set<v3s16>::iterator j = from_nodes.begin();
+ j != from_nodes.end(); ++j)
{
- v3s16 pos = j.getNode()->getKey();
+ v3s16 pos = *j;
emerge(VoxelArea(pos - v3s16(1,1,1), pos + v3s16(1,1,1)));
@@ -666,7 +657,7 @@ void VoxelManipulator::spreadLight(enum LightBank bank,
*/
if(light2 > undiminish_light(oldlight))
{
- lighted_nodes.insert(n2pos, true);
+ lighted_nodes.insert(n2pos);
}
/*
If the neighbor is dimmer than how much light this node
@@ -677,7 +668,7 @@ void VoxelManipulator::spreadLight(enum LightBank bank,
if(nodemgr->get(n2).light_propagates)
{
n2.setLight(bank, newlight, nodemgr);
- lighted_nodes.insert(n2pos, true);
+ lighted_nodes.insert(n2pos);
}
}
}
diff --git a/src/voxel.h b/src/voxel.h
index b48943624..bed35b57e 100644
--- a/src/voxel.h
+++ b/src/voxel.h
@@ -26,6 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream>
#include "debug.h"
#include "mapnode.h"
+#include <set>
+#include <list>
class INodeDefManager;
@@ -186,7 +188,7 @@ public:
a: area inside *this
*/
- void diff(const VoxelArea &a, core::list<VoxelArea> &result)
+ void diff(const VoxelArea &a, std::list<VoxelArea> &result)
{
/*
This can result in a maximum of 6 areas
@@ -519,14 +521,14 @@ public:
// TODO: Move to voxelalgorithms.h
void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
- core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr);
+ std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
void unspreadLight(enum LightBank bank,
- core::map<v3s16, u8> & from_nodes,
- core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr);
+ std::map<v3s16, u8> & from_nodes,
+ std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr);
void spreadLight(enum LightBank bank,
- core::map<v3s16, bool> & from_nodes, INodeDefManager *nodemgr);
+ std::set<v3s16> & from_nodes, INodeDefManager *nodemgr);
/*
Virtual functions
diff --git a/src/voxelalgorithms.cpp b/src/voxelalgorithms.cpp
index bd8f816b8..14638a827 100644
--- a/src/voxelalgorithms.cpp
+++ b/src/voxelalgorithms.cpp
@@ -39,8 +39,8 @@ void setLight(VoxelManipulator &v, VoxelArea a, u8 light,
void clearLightAndCollectSources(VoxelManipulator &v, VoxelArea a,
enum LightBank bank, INodeDefManager *ndef,
- core::map<v3s16, bool> & light_sources,
- core::map<v3s16, u8> & unlight_from)
+ std::set<v3s16> & light_sources,
+ std::map<v3s16, u8> & unlight_from)
{
// The full area we shall touch
VoxelArea required_a = a;
@@ -60,7 +60,7 @@ void clearLightAndCollectSources(VoxelManipulator &v, VoxelArea a,
// If node sources light, add to list
u8 source = ndef->get(n).light_source;
if(source != 0)
- light_sources[p] = true;
+ light_sources.insert(p);
// Collect borders for unlighting
if((x==a.MinEdge.X || x == a.MaxEdge.X
@@ -68,14 +68,14 @@ void clearLightAndCollectSources(VoxelManipulator &v, VoxelArea a,
|| z==a.MinEdge.Z || z == a.MaxEdge.Z)
&& oldlight != 0)
{
- unlight_from.insert(p, oldlight);
+ unlight_from[p] = oldlight;
}
}
}
SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a,
bool inexistent_top_provides_sunlight,
- core::map<v3s16, bool> & light_sources,
+ std::set<v3s16> & light_sources,
INodeDefManager *ndef)
{
// Return values
@@ -127,7 +127,7 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a,
n.setLight(LIGHTBANK_DAY, incoming_light, ndef);
if(diminish_light(incoming_light) != 0)
- light_sources.insert(p, true);
+ light_sources.insert(p);
}
// Check validity of sunlight at top of block below if it
diff --git a/src/voxelalgorithms.h b/src/voxelalgorithms.h
index 2a5fc394e..2eba6a176 100644
--- a/src/voxelalgorithms.h
+++ b/src/voxelalgorithms.h
@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "voxel.h"
#include "mapnode.h"
+#include <set>
+#include <map>
namespace voxalgo
{
@@ -33,8 +35,8 @@ void setLight(VoxelManipulator &v, VoxelArea a, u8 light,
void clearLightAndCollectSources(VoxelManipulator &v, VoxelArea a,
enum LightBank bank, INodeDefManager *ndef,
- core::map<v3s16, bool> & light_sources,
- core::map<v3s16, u8> & unlight_from);
+ std::set<v3s16> & light_sources,
+ std::map<v3s16, u8> & unlight_from);
struct SunlightPropagateResult
{
@@ -47,7 +49,7 @@ struct SunlightPropagateResult
SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a,
bool inexistent_top_provides_sunlight,
- core::map<v3s16, bool> & light_sources,
+ std::set<v3s16> & light_sources,
INodeDefManager *ndef);
} // namespace voxalgo
diff --git a/textures/base/pack/logo.png b/textures/base/pack/logo.png
new file mode 100644
index 000000000..f341e8892
--- /dev/null
+++ b/textures/base/pack/logo.png
Binary files differ
diff --git a/textures/base/pack/menufooter.png b/textures/base/pack/menufooter.png
new file mode 100644
index 000000000..fd431846e
--- /dev/null
+++ b/textures/base/pack/menufooter.png
Binary files differ
diff --git a/textures/base/pack/menuheader.png b/textures/base/pack/menuheader.png
new file mode 100644
index 000000000..66fd6def5
--- /dev/null
+++ b/textures/base/pack/menuheader.png
Binary files differ
diff --git a/textures/base/pack/menulogo.png b/textures/base/pack/menulogo.png
deleted file mode 100644
index 76595c48d..000000000
--- a/textures/base/pack/menulogo.png
+++ /dev/null
Binary files differ
diff --git a/util/buildbot/buildwin32.sh b/util/buildbot/buildwin32.sh
index fc42db8a7..0c0d7cf21 100755
--- a/util/buildbot/buildwin32.sh
+++ b/util/buildbot/buildwin32.sh
@@ -53,6 +53,9 @@ cd $builddir
wget http://github.com/minetest/minetest/zipball/master \
-c -O $packagedir/minetest.zip --tries=3 || (echo "Please download http://github.com/minetest/minetest/zipball/master manually and save it as $packagedir/minetest.zip"; read -s)
[ -e $packagedir/minetest.zip ] || (echo "minetest.zip not found"; exit 1)
+wget http://github.com/minetest/common/zipball/master \
+ -c -O $packagedir/common.zip --tries=3 || (echo "Please download http://github.com/minetest/common/zipball/master manually and save it as $packagedir/common.zip"; read -s)
+[ -e $packagedir/common.zip ] || (echo "common.zip not found"; exit 1)
wget http://github.com/minetest/minetest_game/zipball/master \
-c -O $packagedir/minetest_game.zip --tries=3 || (echo "Please download http://github.com/minetest/minetest_game/zipball/master manually and save it as $packagedir/minetest_game.zip"; read -s)
[ -e $packagedir/minetest_game.zip ] || (echo "minetest_game.zip not found"; exit 1)
@@ -66,6 +69,7 @@ wget http://github.com/minetest/minetest_game/zipball/master \
minetestdirname=`unzip -l $packagedir/minetest.zip | head -n 7 | tail -n 1 | sed -e 's/^[^m]*//' -e 's/\/.*$//'`
minetestdir=$builddir/$minetestdirname || exit 1
git_hash=`echo $minetestdirname | sed -e 's/minetest-minetest-//'`
+commondirname=`unzip -l $packagedir/common.zip | head -n 7 | tail -n 1 | sed -e 's/^[^m]*//' -e 's/\/.*$//'`
minetest_gamedirname=`unzip -l $packagedir/minetest_game.zip | head -n 7 | tail -n 1 | sed -e 's/^[^m]*//' -e 's/\/.*$//'`
# Extract stuff
@@ -86,6 +90,13 @@ unzip -o $packagedir/minetest.zip || exit 1
rm -rf $builddir/minetest
ln -s $minetestdir $builddir/minetest
+# Extract common
+cd $minetestdir/games || exit 1
+rm -rf common || exit 1
+unzip -o $packagedir/common.zip || exit 1
+commondir=$minetestdir/games/$commondirname || exit 1
+mv $commondir $minetestdir/games/common || exit 1
+
# Extract minetest_game
cd $minetestdir/games || exit 1
rm -rf minetest_game || exit 1
diff --git a/util/master/list.js b/util/master/list.js
index dcc30e091..990bb6ded 100644
--- a/util/master/list.js
+++ b/util/master/list.js
@@ -2,11 +2,12 @@ function e(s) {
if (typeof s === "undefined") s = '';
return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); //mc"
}
-function human_time(t) {
+
+function human_time(t, abs) {
var n = 's';
if (!t || t < 0) t = 0;
var f = 0;
- var s = parseInt((new Date().getTime() / 1000 - (t || 0)));
+ var s = parseInt(abs ? (t || 0) : (new Date().getTime() / 1000 - (t || 0)));
if (!s || s <= 0) s = 0;
if (s == 0) return 'now';
if (s >= 60) {
@@ -35,38 +36,36 @@ function human_time(t) {
}
return ((f ? parseFloat(s).toFixed(1) : parseInt(s)) + n);
}
+
function success(r) {
if (!r || !r.list) return;
- var h = '<table><tr><th>ip:port</th><th>clients, max</th><th>version</th><th>name</th><th>desc</th><th>flags</th><th>updated/started</th><th>ping</th></tr>';
+ var h = '<table class="mts_table"><tr class="mts_head"><th>ip[:port]</th><th>clients/max</th><th>version gameid</th><th>name</th><th>desc</th><th>flags</th><th>uptime</th><th>ping</th></tr>';
for (var i = 0; i < r.list.length; ++i) {
var s = r.list[i];
if (!s) continue;
- h += '<tr>';
- h += '<td>' + e(s.address) + ':' + e(s.port) + '</td>';
- h += '<td>' + e(s.clients) + (s.clients_max ? '/' + e(s.clients_max) : '') + (s.clients_top ? ', ' + s.clients_top : '') + '</td>';
- h += '<td>' + e(s.version) + '</td>';
- h += '<td>';
+ h += '<tr class="mts_row">';
+ h += '<td class="mts_address">' + e(s.address) + (s.port != 30000 ? (':' + e(s.port)) : '') + '</td>';
+ h += '<td class="mts_clients">' + e(s.clients) + (s.clients_max ? '/' + e(s.clients_max) : '') + (s.clients_top ? ', ' + s.clients_top : '') + '</td>';
+ h += '<td class="mts_version">' + e(s.version) + ' ' + e(s.gameid) + '</td>';
+ h += '<td class="mts_url">';
if (s.url) h += '<a href="' + e(s.url) + '">';
h += e(s.name || s.url);
if (s.url) h += '</a>';
h += '</td>';
- h += '<td>' + e(s.description) + '</td>';
- h += '<td>' + e(s.password ? 'Pwd ' : '') + (s.creative ? 'Cre ' : '') + (s.damage ? 'Dmg ' : '') + (s.pvp ? 'Pvp ' : '') + (s.dedicated ? 'Ded ' : '') + '</td>';
- if (!s.time || s.time < 0) s.time = 0;
+ h += '<td class="mts_description">' + e(s.description) + '</td>';
+ h += '<td class="mts_flags">' + e(s.password ? 'Pwd ' : '') + (s.creative ? 'Cre ' : '') + (s.damage ? 'Dmg ' : '') + (s.pvp ? 'Pvp ' : '') + (s.dedicated ? 'Ded ' : '') + '</td>';
if (!s.start || s.start < 0) s.start = 0;
- h += '<td>' + human_time(s.time) + (s.start ? '/' + human_time(s.start) : '') + '</td>';
- h += '<td>' + (s.ping ? parseFloat(s.ping).toFixed(3)*1000 : '') + '</td>';
+ h += '<td class="mts_time">' + (s.uptime ? human_time(s.uptime, 1) : s.start ? human_time(s.start) : '') + '</td>';
+ h += '<td class="mts_ping">' + (s.ping ? parseFloat(s.ping).toFixed(3) * 1000 : '') + '</td>';
h += '</tr>';
}
h += '</table>'
jQuery('#table').html(h);
}
+var master_root;
+
function get() {
- jQuery.ajax({
- url: 'list',
- dataType: 'json',
- success: success
- });
+ jQuery.getJSON((master_root || '') + 'list', success);
setTimeout(get, 60000);
}
-get(); \ No newline at end of file
+get();
diff --git a/util/master/master.cgi b/util/master/master.cgi
index b918876bd..0e456ed0c 100755
--- a/util/master/master.cgi
+++ b/util/master/master.cgi
@@ -18,6 +18,7 @@ nginx:
location / {
index index.html;
+ add_header Access-Control-Allow-Origin *;
}
location /announce {
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
@@ -35,6 +36,10 @@ apache .htaccess:
Allow from all
</FilesMatch>
Deny from all
+ <ifModule mod_headers.c>
+ Header set Access-Control-Allow-Origin: *
+ </ifModule>
+
=cut