Merge remote branch 'origin/master'

This commit is contained in:
Weblate 2013-03-30 19:49:52 +01:00
commit a0566270d9
162 changed files with 15898 additions and 12783 deletions

9
.gitignore vendored

@ -4,13 +4,16 @@
*bak* *bak*
tags tags
*.vim *.vim
*.orig
*.rej
## Non-static Minetest directories ## Non-static Minetest directories
/bin/ /bin/
/games/* /games/*
!/games/minimal/ !/games/minimal/
/cache/ /cache/
/textures/ /textures/*
!/textures/base/
/sounds/ /sounds/
/mods/* /mods/*
!/mods/minetest/ !/mods/minetest/
@ -41,7 +44,9 @@ src/cguittfont/libcguittfont.a
src/cguittfont/cmake_install.cmake src/cguittfont/cmake_install.cmake
src/cguittfont/Makefile src/cguittfont/Makefile
src/json/CMakeFiles/ src/json/CMakeFiles/
src/json/libjson.a src/json/libjsoncpp.a
src/sqlite/CMakeFiles/*
src/sqlite/libsqlite3.a
CMakeCache.txt CMakeCache.txt
CPackConfig.cmake CPackConfig.cmake
CPackSourceConfig.cmake CPackSourceConfig.cmake

@ -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 # Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
set(VERSION_MAJOR 0) set(VERSION_MAJOR 0)
set(VERSION_MINOR 4) set(VERSION_MINOR 4)
set(VERSION_PATCH 4-d1) set(VERSION_PATCH 5)
if(VERSION_EXTRA) if(VERSION_EXTRA)
set(VERSION_PATCH ${VERSION_PATCH}-${VERSION_EXTRA}) set(VERSION_PATCH ${VERSION_PATCH}-${VERSION_EXTRA})
endif() endif()
@ -133,6 +133,11 @@ endif()
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/builtin" DESTINATION "${SHAREDIR}") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/builtin" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client" DESTINATION "${SHAREDIR}") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minimal" DESTINATION "${SHAREDIR}/games") 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") set(MINETEST_GAME_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game")
if(EXISTS ${MINETEST_GAME_SOURCE} AND IS_DIRECTORY ${MINETEST_GAME_SOURCE}) if(EXISTS ${MINETEST_GAME_SOURCE} AND IS_DIRECTORY ${MINETEST_GAME_SOURCE})
install(FILES ${MINETEST_GAME_SOURCE}/game.conf DESTINATION "${SHAREDIR}/games/minetest_game/") install(FILES ${MINETEST_GAME_SOURCE}/game.conf DESTINATION "${SHAREDIR}/games/minetest_game/")

@ -9,9 +9,10 @@ and contributors (see source file comments and the version control log)
In case you downloaded the source code: In case you downloaded the source code:
--------------------------------------- ---------------------------------------
If you downloaded the Minetest Engine source code in which this file is 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/ https://github.com/minetest/minetest_game/
See the README.txt in it. See the README.txt in them.
Further documentation Further documentation
---------------------- ----------------------
@ -80,17 +81,24 @@ Compiling on GNU/Linux:
----------------------- -----------------------
Install dependencies. Here's an example for Debian/Ubuntu: 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): 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 $ wget https://github.com/minetest/minetest/tarball/master -O master.tar.gz
$ tar xf master.tar.gz $ tar xf master.tar.gz
$ cd minetest-minetest-286edd4 (or similar) $ 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) Download minetest_game (otherwise only the "Minimal development test" game is available)
$ cd games/ $ cd games/
$ wget https://github.com/minetest/minetest_game/tarball/master -O master.tar.gz $ wget https://github.com/minetest/minetest_game/tarball/master -O minetest_game.tar.gz
$ tar xf master.tar.gz $ tar xf minetest_game.tar.gz
$ mv minetest-minetest_game-* minetest_game $ mv minetest-minetest_game-* minetest_game
$ cd .. $ 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 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> - 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 - 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: Compiling on Windows:
--------------------- ---------------------
- This section is outdated. In addition to what is described here: - 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 - If you wish to have sound support, you need libogg, libvorbis and libopenal
- You need: - You need:

@ -57,6 +57,10 @@ minetest.register_entity("__builtin:falling_node", {
-- Note: walkable is in the node definition, not in item groups -- Note: walkable is in the node definition, not in item groups
if minetest.registered_nodes[bcn.name] and if minetest.registered_nodes[bcn.name] and
minetest.registered_nodes[bcn.name].walkable then 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} local np = {x=bcp.x, y=bcp.y+1, z=bcp.z}
-- Check what's here -- Check what's here
local n2 = minetest.env:get_node(np) local n2 = minetest.env:get_node(np)
@ -80,6 +84,7 @@ minetest.register_entity("__builtin:falling_node", {
-- Create node and remove entity -- Create node and remove entity
minetest.env:add_node(np, {name=self.nodename}) minetest.env:add_node(np, {name=self.nodename})
self.object:remove() self.object:remove()
nodeupdate(np)
else else
-- Do nothing -- Do nothing
end end
@ -144,7 +149,8 @@ function nodeupdate_single(p)
n_bottom = minetest.env:get_node(p_bottom) n_bottom = minetest.env:get_node(p_bottom)
-- Note: walkable is in the node definition, not in item groups -- Note: walkable is in the node definition, not in item groups
if minetest.registered_nodes[n_bottom.name] and 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) minetest.env:remove_node(p)
spawn_falling_node(p, n.name) spawn_falling_node(p, n.name)
nodeupdate(p) nodeupdate(p)

@ -129,11 +129,18 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
end end
local under = pointed_thing.under 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() local olddef_under = ItemStack({name=oldnode_under.name}):get_definition()
olddef_under = olddef_under or minetest.nodedef_default 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() local olddef_above = ItemStack({name=oldnode_above.name}):get_definition()
olddef_above = olddef_above or minetest.nodedef_default olddef_above = olddef_above or minetest.nodedef_default

@ -111,6 +111,7 @@ minetest.register_entity("__builtin:item", {
if self.itemstring ~= '' then if self.itemstring ~= '' then
local left = hitter:get_inventory():add_item("main", self.itemstring) local left = hitter:get_inventory():add_item("main", self.itemstring)
if not left:is_empty() then if not left:is_empty() then
self.itemstring = left:to_string()
return return
end end
end end

@ -14,14 +14,14 @@ minetest.register_globalstep(function(dtime)
for index, timer in ipairs(minetest.timers) do for index, timer in ipairs(minetest.timers) do
timer.time = timer.time - dtime timer.time = timer.time - dtime
if timer.time <= 0 then if timer.time <= 0 then
timer.func(timer.param) timer.func(unpack(timer.args or {}))
table.remove(minetest.timers,index) table.remove(minetest.timers,index)
end end
end end
end) end)
function minetest.after(time, func, param) function minetest.after(time, func, ...)
table.insert(minetest.timers_to_add, {time=time, func=func, param=param}) table.insert(minetest.timers_to_add, {time=time, func=func, args={...}})
end end
function minetest.check_player_privs(name, privs) function minetest.check_player_privs(name, privs)
@ -99,3 +99,10 @@ function minetest.setting_get_pos(name)
return minetest.string_to_pos(value) return minetest.string_to_pos(value)
end end
function minetest.formspec_escape(str)
str = string.gsub(str, "\\", "\\\\")
str = string.gsub(str, "%[", "\\[")
str = string.gsub(str, "%]", "\\]")
return str
end

@ -8,9 +8,7 @@ varying vec3 vPosition;
void main(void) void main(void)
{ {
vec4 pos = gl_Vertex; gl_Position = mWorldViewProj * gl_Vertex;
pos.y -= 2.0;
gl_Position = mWorldViewProj * pos;
vPosition = (mWorldViewProj * gl_Vertex).xyz; vPosition = (mWorldViewProj * gl_Vertex).xyz;

@ -2,17 +2,17 @@
#FIND_PATH(JSON_INCLUDE_DIR json.h) #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) #IF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
# SET( JSON_FOUND TRUE ) # SET( JSON_FOUND TRUE )
#ENDIF(JSON_LIBRARY AND JSON_INCLUDE_DIR) #ENDIF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
#IF(JSON_FOUND) #IF(JSON_FOUND)
# MESSAGE(STATUS "Found system json header file in ${JSON_INCLUDE_DIR}") # MESSAGE(STATUS "Found system jsoncpp header file in ${JSON_INCLUDE_DIR}")
# MESSAGE(STATUS "Found system json library ${JSON_LIBRARY}") # MESSAGE(STATUS "Found system jsoncpp library ${JSON_LIBRARY}")
#ELSE(JSON_FOUND) #ELSE(JSON_FOUND)
SET(JSON_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/json) SET(JSON_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/json)
SET(JSON_LIBRARY json) SET(JSON_LIBRARY jsoncpp)
MESSAGE(STATUS "Using project json library") MESSAGE(STATUS "Using project jsoncpp library")
#ENDIF(JSON_FOUND) #ENDIF(JSON_FOUND)

@ -0,0 +1,130 @@
#-------------------------------------------------------------------
# This file is stolen from part of the CMake build system for OGRE (Object-oriented Graphics Rendering Engine) http://www.ogre3d.org/
#
# The contents of this file are placed in the public domain. Feel
# free to make use of it in any way you like.
#-------------------------------------------------------------------
# - Try to find OpenGLES and EGL
# Once done this will define
#
# OPENGLES2_FOUND - system has OpenGLES
# OPENGLES2_INCLUDE_DIR - the GL include directory
# OPENGLES2_LIBRARIES - Link these to use OpenGLES
#
# EGL_FOUND - system has EGL
# EGL_INCLUDE_DIR - the EGL include directory
# EGL_LIBRARIES - Link these to use EGL
# win32, apple, android NOT TESED
# linux tested and works
IF (WIN32)
IF (CYGWIN)
FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h )
FIND_LIBRARY(OPENGLES2_gl_LIBRARY libGLESv2 )
ELSE (CYGWIN)
IF(BORLAND)
SET (OPENGLES2_gl_LIBRARY import32 CACHE STRING "OpenGL ES 2.x library for win32")
ELSE(BORLAND)
# todo
# SET (OPENGLES_gl_LIBRARY ${SOURCE_DIR}/Dependencies/lib/release/libGLESv2.lib CACHE STRING "OpenGL ES 2.x library for win32"
ENDIF(BORLAND)
ENDIF (CYGWIN)
ELSE (WIN32)
IF (APPLE)
create_search_paths(/Developer/Platforms)
findpkg_framework(OpenGLES2)
set(OPENGLES2_gl_LIBRARY "-framework OpenGLES")
ELSE(APPLE)
FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h
/usr/openwin/share/include
/opt/graphics/OpenGL/include /usr/X11R6/include
/usr/include
)
FIND_LIBRARY(OPENGLES2_gl_LIBRARY
NAMES GLESv2
PATHS /opt/graphics/OpenGL/lib
/usr/openwin/lib
/usr/shlib /usr/X11R6/lib
/usr/lib
)
IF (NOT BUILD_ANDROID)
FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h
/usr/openwin/share/include
/opt/graphics/OpenGL/include /usr/X11R6/include
/usr/include
)
FIND_LIBRARY(EGL_egl_LIBRARY
NAMES EGL
PATHS /opt/graphics/OpenGL/lib
/usr/openwin/lib
/usr/shlib /usr/X11R6/lib
/usr/lib
)
# On Unix OpenGL most certainly always requires X11.
# Feel free to tighten up these conditions if you don't
# think this is always true.
# It's not true on OSX.
IF (OPENGLES2_gl_LIBRARY)
IF(NOT X11_FOUND)
INCLUDE(FindX11)
ENDIF(NOT X11_FOUND)
IF (X11_FOUND)
IF (NOT APPLE)
SET (OPENGLES2_LIBRARIES ${X11_LIBRARIES})
ENDIF (NOT APPLE)
ENDIF (X11_FOUND)
ENDIF (OPENGLES2_gl_LIBRARY)
ENDIF ()
ENDIF(APPLE)
ENDIF (WIN32)
#SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
IF (BUILD_ANDROID)
IF(OPENGLES2_gl_LIBRARY)
SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
SET( EGL_LIBRARIES)
SET( OPENGLES2_FOUND "YES" )
ENDIF(OPENGLES2_gl_LIBRARY)
ELSE ()
SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
IF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY)
SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
SET( EGL_LIBRARIES ${EGL_egl_LIBRARY} ${EGL_LIBRARIES})
SET( OPENGLES2_FOUND "YES" )
ENDIF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY)
ENDIF ()
MARK_AS_ADVANCED(
OPENGLES2_INCLUDE_DIR
OPENGLES2_gl_LIBRARY
EGL_INCLUDE_DIR
EGL_egl_LIBRARY
)
IF(OPENGLES2_FOUND)
MESSAGE(STATUS "Found system opengles2 library ${OPENGLES2_LIBRARIES}")
ELSE ()
SET(OPENGLES2_LIBRARIES "")
ENDIF ()

@ -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/ 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 Mods are loaded during server startup from the mod load paths by running
the init.lua scripts in a shared environment. 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 Mod load path
------------- -------------
Generic: Generic:
@ -170,18 +203,18 @@ from the available ones of the following files:
Examples of sound parameter tables: Examples of sound parameter tables:
-- Play locationless on all clients -- Play locationless on all clients
{ {
gain = 1.0, -- default gain = 1.0, -- default
} }
-- Play locationless to a player -- Play locationless to a player
{ {
to_player = name, to_player = name,
gain = 1.0, -- default gain = 1.0, -- default
} }
-- Play in a location -- Play in a location
{ {
pos = {x=1,y=2,z=3}, pos = {x=1,y=2,z=3},
gain = 1.0, -- default gain = 1.0, -- default
max_hear_distance = 32, -- default max_hear_distance = 32, -- default
} }
-- Play connected to an object, looped -- 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: Example: minetest.get_item_group(name, group) has been implemented as:
function minetest.get_item_group(name, group) function minetest.get_item_group(name, group)
if not minetest.registered_items[name] or not if not minetest.registered_items[name] or not
minetest.registered_items[name].groups[group] then minetest.registered_items[name].groups[group] then
return 0 return 0
end end
return minetest.registered_items[name].groups[group] return minetest.registered_items[name].groups[group]
end end
Nodes Nodes
@ -277,6 +310,10 @@ param2 is reserved for the engine when any of these are used:
paramtype2 == "facedir" paramtype2 == "facedir"
^ The rotation of the node is stored in param2. Furnaces and chests are ^ 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(). 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". 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: A box of a regular node would look like:
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, {-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 Representations of simple things
-------------------------------- --------------------------------
Position/vector: Position/vector:
@ -412,9 +471,11 @@ a node is destroyable and how long it takes to destroy by a tool.
Groups of entities Groups of entities
------------------- -------------------
For entities, groups are, as of now, used only for calculating damage. 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.get_armor_groups() -> a group-rating table (eg. {fleshy=100})
object.set_armor_groups({level=2, fleshy=2, cracky=2}) object.set_armor_groups({fleshy=30, cracky=80})
Groups of tools 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 An another example: Make red wool from white wool and red dye
{ {
type = 'shapeless', type = 'shapeless',
output = 'wool:red', output = 'wool:red',
recipe = {'wool:white', 'group:dye,basecolor_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. - 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 - 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 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 - 0 is something that is directly accessible at the start of gameplay
- There is no upper limit - There is no upper limit
- dig_immediate: (player can always pick up node without tool wear) - dig_immediate: (player can always pick up node without tool wear)
@ -463,7 +524,6 @@ Special groups
Known damage and digging time defining groups Known damage and digging time defining groups
---------------------------------------------- ----------------------------------------------
Valid ratings for these are 0, 1, 2 and 3, unless otherwise stated.
- crumbly: dirt, sand - crumbly: dirt, sand
- cracky: tough but crackable stuff like stone. - cracky: tough but crackable stuff like stone.
- snappy: something that can be cut using fine tools; eg. leaves, small - 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) * Uses (until the tool breaks)
* Maximum level (usually 0, 1, 2 or 3) * Maximum level (usually 0, 1, 2 or 3)
* Digging times * Digging times
* Damage groups
**Full punch interval**: **Full punch interval**:
When used as a weapon, the tool will do full damage if this time is spent 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 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. for this group, and unable to dig the rating 1, which is the toughest.
Unless there is a matching group that enables digging otherwise. 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 Example definition of the capabilities of a tool
------------------------------------------------- -------------------------------------------------
tool_capabilities = { tool_capabilities = {
full_punch_interval=1.5, full_punch_interval=1.5,
max_drop_level=1, max_drop_level=1,
groupcaps={ groupcaps={
crumbly={maxlevel=2, uses=20, times={[1]=1.60, [2]=1.20, [3]=0.80}} 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: This makes the tool be able to dig nodes that fullfill both of these:
@ -588,10 +651,12 @@ Notes:
Entity damage mechanism Entity damage mechanism
------------------------ ------------------------
Damage calculation: Damage calculation:
- Take the time spent after the last hit damage = 0
- Limit time to full_punch_interval foreach group in cap.damage_groups:
- Take the damage groups and imagine a bunch of nodes that have them damage += cap.damage_groups[group] * limit(actual_interval / cap.full_punch_interval, 0.0, 1.0)
- Damage in HP is the amount of nodes destroyed in this time. * (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 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 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 is the default value of the field
^ default may contain variable references such as '${text}' which ^ default may contain variable references such as '${text}' which
will fill the value from the metadata value 'text' 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>] field[<name>;<label>;<default>]
^ as above but without position/size units ^ 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)" minetest.pos_to_string({x=X,y=Y,z=Z}) -> "(X,Y,Z)"
^ Convert position to a printable string ^ Convert position to a printable string
minetest.string_to_pos(string) -> position 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 minetest namespace reference
----------------------------- -----------------------------
@ -804,6 +872,7 @@ minetest.register_tool(name, item definition)
minetest.register_craftitem(name, item definition) minetest.register_craftitem(name, item definition)
minetest.register_alias(name, convert_to) minetest.register_alias(name, convert_to)
minetest.register_craft(recipe) minetest.register_craft(recipe)
minetest.register_ore(ore definition)
Global callback registration functions: (Call these only at load time) Global callback registration functions: (Call these only at load time)
minetest.register_globalstep(func(dtime)) minetest.register_globalstep(func(dtime))
@ -919,12 +988,17 @@ minetest.get_craft_result(input) -> output, decremented_input
^ output.time = number, if unsuccessful: 0 ^ output.time = number, if unsuccessful: 0
^ decremented_input = like input ^ decremented_input = like input
minetest.get_craft_recipe(output) -> 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' ^ output is a node or item type such as 'default:torch'
^ input.method = 'normal' or 'cooking' or 'fuel' ^ input.method = 'normal' or 'cooking' or 'fuel'
^ input.width = for example 3 ^ input.width = for example 3
^ input.items = for example { stack 1, stack 2, stack 3, stack 4, ^ input.items = for example { stack 1, stack 2, stack 3, stack 4,
stack 5, stack 6, stack 7, stack 8, stack 9 } stack 5, stack 6, stack 7, stack 8, stack 9 }
^ input.items = nil if no recipe found ^ 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) minetest.handle_node_drops(pos, drops, digger)
^ drops: list of itemstrings ^ drops: list of itemstrings
^ Handles drops from nodes after digging: Default action is to put them into ^ 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) minetest.sound_stop(handle)
Timing: Timing:
minetest.after(time, func, param) minetest.after(time, func, ...)
^ Call function after time seconds ^ 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: Server:
minetest.request_shutdown() -> request for server shutdown 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.ban_player(name) -> ban a player
minetest.unban_player_or_ip(name) -> unban player or IP address 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: Random:
minetest.get_connected_players() -> list of ObjectRefs minetest.get_connected_players() -> list of ObjectRefs
minetest.hash_node_position({x=,y=,z=}) -> 48-bit integer 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_wielded_item(item): replaces the wielded item, returns true if successful
- set_armor_groups({group1=rating, group2=rating, ...}) - set_armor_groups({group1=rating, group2=rating, ...})
- set_animation({x=1,y=1}, frame_speed=15, frame_blend=0) - 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_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) - set_properties(object property table)
LuaEntitySAO-only: (no-op for other objects) LuaEntitySAO-only: (no-op for other objects)
- setvelocity({x=num, y=num, z=num}) - setvelocity({x=num, y=num, z=num})
@ -1220,14 +1331,16 @@ Player-only: (no-op for other objects)
- get_look_dir(): get camera direction as a unit vector - get_look_dir(): get camera direction as a unit vector
- get_look_pitch(): pitch in radians - get_look_pitch(): pitch in radians
- get_look_yaw(): yaw in radians (wraps around pretty randomly as of now) - 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) - set_inventory_formspec(formspec)
^ Redefine player's inventory form ^ Redefine player's inventory form
^ Should usually be called in on_joinplayer ^ Should usually be called in on_joinplayer
- get_inventory_formspec() -> formspec string - get_inventory_formspec() -> formspec string
- get_player_control(): returns table with player pressed keys - 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 - 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 InvRef: Reference to an inventory
methods: methods:
@ -1313,8 +1426,8 @@ Registered entities
^ puncher: ObjectRef (can be nil) ^ puncher: ObjectRef (can be nil)
^ time_from_last_punch: Meant for disallowing spamming of clicks (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) ^ tool_capabilities: capability table of used tool (can be nil)
^ dir: unit vector of direction of punch. Always defined. Points from ^ dir: unit vector of direction of punch. Always defined. Points from
the puncher to the punched. the puncher to the punched.
- on_rightclick(self, clicker) - on_rightclick(self, clicker)
- get_staticdata(self) - get_staticdata(self)
^ Should return a string that will be passed to on_activate when ^ 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, max_drop_level=0,
groupcaps={ groupcaps={
-- For example: -- 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}, snappy={times={[2]=0.80, [3]=0.40}, maxwear=0.05, maxlevel=1},
choppy={times={[3]=0.90}, maxwear=0.05, maxlevel=0} choppy={times={[3]=0.90}, maxwear=0.05, maxlevel=0}
} },
damage_groups = {groupname=damage},
} }
node_placement_prediction = nil, node_placement_prediction = nil,
^ If nil and item is node, prediction is made automatically ^ 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 ^ Otherwise should be name of node which the client immediately places
on ground when the player places the item. Server will always update on ground when the player places the item. Server will always update
actual result to client in a short moment. actual result to client in a short moment.
sound = {
place = <SimpleSoundSpec>,
}
on_place = func(itemstack, placer, pointed_thing), on_place = func(itemstack, placer, pointed_thing),
^ Shall place item and return the leftover itemstack ^ Shall place item and return the leftover itemstack
@ -1435,10 +1551,10 @@ Node definition (register_node)
drawtype = "normal", -- See "Node drawtypes" drawtype = "normal", -- See "Node drawtypes"
visual_scale = 1.0, visual_scale = 1.0,
tiles = {tile definition 1, def2, def3, def4, def5, def6}, 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 ^ List can be shortened to needed length
special_tiles = {tile definition 1, Tile definition 2}, 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 ^ List can be shortened to needed length
alpha = 255, alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0}, -- If player is inside node 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>, footstep = <SimpleSoundSpec>,
dig = <SimpleSoundSpec>, -- "__group" = group-based sound (default) dig = <SimpleSoundSpec>, -- "__group" = group-based sound (default)
dug = <SimpleSoundSpec>, dug = <SimpleSoundSpec>,
place = <SimpleSoundSpec>,
}, },
on_construct = func(pos), on_construct = func(pos),
@ -1517,32 +1634,32 @@ Node definition (register_node)
^ Called when an UI form (eg. sign text input) returns data ^ Called when an UI form (eg. sign text input) returns data
^ default: nil ^ default: nil
allow_metadata_inventory_move = func(pos, from_list, from_index, allow_metadata_inventory_move = func(pos, from_list, from_index,
to_list, to_index, count, player), to_list, to_index, count, player),
^ Called when a player wants to move items inside the inventory ^ 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_metadata_inventory_put = func(pos, listname, index, stack, player), allow_metadata_inventory_put = func(pos, listname, index, stack, player),
^ Called when a player wants to put something into the inventory ^ Called when a player wants to put something into the inventory
^ Return value: number of items allowed to put ^ Return value: number of items allowed to put
^ Return value: -1: Allow and don't modify item count in inventory ^ Return value: -1: Allow and don't modify item count in inventory
allow_metadata_inventory_take = func(pos, listname, index, stack, player), allow_metadata_inventory_take = func(pos, listname, index, stack, player),
^ Called when a player wants to take something out of the inventory ^ Called when a player wants to take something out of the inventory
^ Return value: number of items allowed to take ^ Return value: number of items allowed to take
^ Return value: -1: Allow and don't modify item count in inventory ^ Return value: -1: Allow and don't modify item count in inventory
on_metadata_inventory_move = func(pos, from_list, from_index, on_metadata_inventory_move = func(pos, from_list, from_index,
to_list, to_index, count, player), to_list, to_index, count, player),
on_metadata_inventory_put = func(pos, listname, index, stack, player), on_metadata_inventory_put = func(pos, listname, index, stack, player),
on_metadata_inventory_take = 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. ^ Called after the actual action has happened, according to what was allowed.
^ No return value ^ No return value
on_blast = func(pos, intensity), on_blast = func(pos, intensity),
^ intensity: 1.0 = mid range of regular TNT ^ intensity: 1.0 = mid range of regular TNT
^ If defined, called when an explosion touches the node, instead of ^ If defined, called when an explosion touches the node, instead of
removing the node removing the node
} }
Recipe for register_craft: (shaped) Recipe for register_craft: (shaped)
@ -1591,6 +1708,28 @@ Recipe for register_craft (furnace fuel)
burntime = 1, 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) Chatcommand definition (register_chatcommand)
{ {
params = "<name> <privilege>", -- short parameter description params = "<name> <privilege>", -- short parameter description
@ -1601,24 +1740,24 @@ Chatcommand definition (register_chatcommand)
Detached inventory callbacks 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 ^ 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), allow_put = func(inv, listname, index, stack, player),
^ Called when a player wants to put something into the inventory ^ Called when a player wants to put something into the inventory
^ Return value: number of items allowed to put ^ Return value: number of items allowed to put
^ Return value: -1: Allow and don't modify item count in inventory ^ Return value: -1: Allow and don't modify item count in inventory
allow_take = func(inv, listname, index, stack, player), allow_take = func(inv, listname, index, stack, player),
^ Called when a player wants to take something out of the inventory ^ Called when a player wants to take something out of the inventory
^ Return value: number of items allowed to take ^ Return value: number of items allowed to take
^ Return value: -1: Allow and don't modify item count in inventory ^ 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_move = func(inv, from_list, from_index, to_list, to_index, count, player),
on_put = func(inv, listname, index, stack, player), on_put = func(inv, listname, index, stack, player),
on_take = 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. ^ Called after the actual action has happened, according to what was allowed.
^ No return value ^ No return value
} }

@ -70,3 +70,39 @@ function check_if_minetestserver_up($host, $port)
return false; 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])

@ -659,6 +659,8 @@ function default.node_sound_dirt_defaults(table)
{name="", gain=0.5} {name="", gain=0.5}
--table.dug = table.dug or --table.dug = table.dug or
-- {name="default_dirt_break", gain=0.5} -- {name="default_dirt_break", gain=0.5}
table.place = table.place or
{name="default_grass_footstep", gain=0.5}
default.node_sound_defaults(table) default.node_sound_defaults(table)
return table return table
end end

@ -27,52 +27,74 @@ minetest.register_alias("mapgen_mese", "default:mese")
-- Ore generation -- Ore generation
-- --
local function generate_ore(name, wherein, minp, maxp, seed, chunks_per_volume, ore_per_chunk, height_min, height_max, param2) minetest.register_ore({
if maxp.y < height_min or minp.y > height_max then ore_type = "scatter",
return ore = "default:stone_with_coal",
end wherein = "default:stone",
local y_min = math.max(minp.y, height_min) clust_scarcity = 8*8*8,
local y_max = math.min(maxp.y, height_max) clust_num_ores = 5,
local volume = (maxp.x-minp.x+1)*(y_max-y_min+1)*(maxp.z-minp.z+1) clust_size = 3,
local pr = PseudoRandom(seed) height_min = -31000,
local num_chunks = math.floor(chunks_per_volume * volume) height_max = 64,
local chunk_size = 3 })
if ore_per_chunk <= 4 then
chunk_size = 2 minetest.register_ore({
end ore_type = "scatter",
local inverse_chance = math.floor(chunk_size*chunk_size*chunk_size / ore_per_chunk) ore = "default:stone_with_iron",
--print("generate_ore num_chunks: "..dump(num_chunks)) wherein = "default:stone",
for i=1,num_chunks do clust_scarcity = 16*16*16,
local y0 = pr:next(y_min, y_max-chunk_size+1) clust_num_ores = 5,
if y0 >= height_min and y0 <= height_max then clust_size = 3,
local x0 = pr:next(minp.x, maxp.x-chunk_size+1) height_min = -5,
local z0 = pr:next(minp.z, maxp.z-chunk_size+1) height_max = 7,
local p0 = {x=x0, y=y0, z=z0} })
for x1=0,chunk_size-1 do
for y1=0,chunk_size-1 do minetest.register_ore({
for z1=0,chunk_size-1 do ore_type = "scatter",
if pr:next(1,inverse_chance) == 1 then ore = "default:stone_with_iron",
local x2 = x0+x1 wherein = "default:stone",
local y2 = y0+y1 clust_scarcity = 12*12*12,
local z2 = z0+z1 clust_num_ores = 5,
local p2 = {x=x2, y=y2, z=z2} clust_size = 3,
if minetest.env:get_node(p2).name == wherein then height_min = -16,
minetest.env:set_node(p2, {name=name, param2=param2}) height_max = -5,
end })
end
end minetest.register_ore({
end ore_type = "scatter",
end ore = "default:stone_with_iron",
end wherein = "default:stone",
end clust_scarcity = 9*9*9,
--print("generate_ore done") clust_num_ores = 5,
end 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) 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 -- Generate clay
if maxp.y >= 2 and minp.y <= 0 then if maxp.y >= 2 and minp.y <= 0 then
-- Assume X and Z lengths are equal -- Assume X and Z lengths are equal
@ -110,11 +132,5 @@ minetest.register_on_generated(function(minp, maxp, seed)
end end
end 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) end)

@ -80,6 +80,7 @@
# when set to higher number than 0 # when set to higher number than 0
#fsaa = 0 #fsaa = 0
#vsync = false #vsync = false
#fov = 72
# Address to connect to (#blank = start local server) # Address to connect to (#blank = start local server)
#address = #address =
# Enable random user input, for testing # Enable random user input, for testing
@ -95,9 +96,11 @@
# Update liquids every .. recommend for finite: 0.2 # Update liquids every .. recommend for finite: 0.2
#liquid_update = 1.0 #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 # 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 #liquid_relax = 2
# optimization: faster cave flood (and not true constant) # Optimization: faster cave flood (and not true constant)
#liquid_fast_flood = 1 #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 # Enable nice leaves; disable for speed
#new_style_leaves = true #new_style_leaves = true
# Enable smooth lighting with simple ambient occlusion; # Enable smooth lighting with simple ambient occlusion;
@ -125,6 +128,10 @@
#farmesh_distance = 40 #farmesh_distance = 40
# Enable/disable clouds # Enable/disable clouds
#enable_clouds = true #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 # Path for screenshots
#screenshot_path = . #screenshot_path = .
# Amount of view bobbing (0 = no view bobbing, 1.0 = normal, 2.0 = double) # Amount of view bobbing (0 = no view bobbing, 1.0 = normal, 2.0 = double)
@ -304,29 +311,45 @@
# Mapgen stuff # 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 #mg_name = v6
# Water level of map. # Water level of map.
#water_level = 1 #water_level = 1
# Size of chunks to be generated. # Size of chunks to be generated.
#chunksize = 5 #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 #mg_flags = trees, caves, v6_biome_blend
# How large deserts and beaches are # How large deserts and beaches are
#mgv6_freq_desert = 0.45 #mgv6_freq_desert = 0.45
#mgv6_freq_beach = 0.15 #mgv6_freq_beach = 0.15
# Perlin noise attributes for different map generation parameters # Perlin noise attributes for different map generation parameters
# Offset, scale, spread factor, seed offset, number of octaves, persistence # 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_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_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_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_mud = 4, 2, (200, 200, 200), 91013, 3, 0.55
#mgv6_np_beach = 0, 1, (250, 250, 250), 59420, 3, 0.50 #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_biome = 0, 1, (250, 250, 250), 9130, 3, 0.50
#mgv6_np_cave = 6, 6, (250, 250, 250), 34329, 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_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_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_heat = 25, 50, (500, 500, 500), 35293, 1, 0
#mgv7_np_humidity = 50, 31.25, (750, 750, 750), 12094, 2, 0.6 #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

@ -161,7 +161,7 @@ else()
endif(APPLE) endif(APPLE)
endif(BUILD_CLIENT) endif(BUILD_CLIENT)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
set(PLATFORM_LIBS -lpthread ${CMAKE_DL_LIBS}) set(PLATFORM_LIBS -lpthread -lrt ${CMAKE_DL_LIBS})
#set(CLIENT_PLATFORM_LIBS -lXxf86vm) #set(CLIENT_PLATFORM_LIBS -lXxf86vm)
# This way Xxf86vm is found on OpenBSD too # This way Xxf86vm is found on OpenBSD too
find_library(XXF86VM_LIBRARY Xxf86vm) find_library(XXF86VM_LIBRARY Xxf86vm)
@ -172,6 +172,7 @@ endif()
find_package(Jthread REQUIRED) find_package(Jthread REQUIRED)
find_package(Sqlite3 REQUIRED) find_package(Sqlite3 REQUIRED)
find_package(Json REQUIRED) find_package(Json REQUIRED)
find_package(OpenGLES2)
if(USE_FREETYPE) if(USE_FREETYPE)
find_package(Freetype REQUIRED) find_package(Freetype REQUIRED)
@ -205,6 +206,20 @@ set(common_SRCS
itemdef.cpp itemdef.cpp
nodedef.cpp nodedef.cpp
object_properties.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 scriptapi.cpp
script.cpp script.cpp
log.cpp log.cpp
@ -212,7 +227,10 @@ set(common_SRCS
emerge.cpp emerge.cpp
mapgen.cpp mapgen.cpp
mapgen_v6.cpp mapgen_v6.cpp
mapgen_indev.cpp
mapgen_singlenode.cpp
treegen.cpp treegen.cpp
dungeongen.cpp
content_nodemeta.cpp content_nodemeta.cpp
content_mapnode.cpp content_mapnode.cpp
collision.cpp collision.cpp
@ -371,6 +389,7 @@ if(BUILD_CLIENT)
${SQLITE3_LIBRARY} ${SQLITE3_LIBRARY}
${LUA_LIBRARY} ${LUA_LIBRARY}
${JSON_LIBRARY} ${JSON_LIBRARY}
${OPENGLES2_LIBRARIES}
${PLATFORM_LIBS} ${PLATFORM_LIBS}
${CLIENT_PLATFORM_LIBS} ${CLIENT_PLATFORM_LIBS}
) )

@ -61,7 +61,7 @@ public:
} }
virtual u8 getType() const = 0; virtual u8 getType() const = 0;
virtual bool getCollisionBox(aabb3f *toset) = 0;
protected: protected:
u16 m_id; // 0 is invalid, "no id" u16 m_id; // 0 is invalid, "no id"
}; };

@ -117,8 +117,8 @@ void ChatBuffer::deleteOldest(u32 count)
--count; --count;
} }
m_unformatted.erase(0, del_unformatted); m_unformatted.erase(m_unformatted.begin(), m_unformatted.begin() + del_unformatted);
m_formatted.erase(0, del_formatted); m_formatted.erase(m_formatted.begin(), m_formatted.begin() + del_formatted);
} }
void ChatBuffer::deleteByAge(f32 maxAge) void ChatBuffer::deleteByAge(f32 maxAge)
@ -232,10 +232,10 @@ void ChatBuffer::scrollTop()
} }
u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols, u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
core::array<ChatFormattedLine>& destination) const std::vector<ChatFormattedLine>& destination) const
{ {
u32 num_added = 0; u32 num_added = 0;
core::array<ChatFormattedFragment> next_frags; std::vector<ChatFormattedFragment> next_frags;
ChatFormattedLine next_line; ChatFormattedLine next_line;
ChatFormattedFragment temp_frag; ChatFormattedFragment temp_frag;
u32 out_column = 0; u32 out_column = 0;
@ -292,7 +292,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
frag.column = out_column; frag.column = out_column;
next_line.fragments.push_back(frag); next_line.fragments.push_back(frag);
out_column += frag.text.size(); out_column += frag.text.size();
next_frags.erase(0, 1); next_frags.erase(next_frags.begin());
} }
else else
{ {
@ -414,7 +414,7 @@ std::wstring ChatPrompt::submit()
if (!line.empty()) if (!line.empty())
m_history.push_back(line); m_history.push_back(line);
if (m_history.size() > m_history_limit) if (m_history.size() > m_history_limit)
m_history.erase(0); m_history.erase(m_history.begin());
m_history_index = m_history.size(); m_history_index = m_history.size();
m_view = 0; m_view = 0;
m_cursor = 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: // Two cases:
// (a) m_nick_completion_start == m_nick_completion_end == 0 // (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); std::wstring prefix = m_line.substr(prefix_start, prefix_end - prefix_start);
// find all names that start with the selected prefix // find all names that start with the selected prefix
core::array<std::wstring> completions; std::vector<std::wstring> completions;
for (core::list<std::wstring>::ConstIterator for (std::list<std::wstring>::const_iterator
i = names.begin(); i = names.begin();
i != names.end(); i++) i != names.end(); ++i)
{ {
if (str_starts_with(*i, prefix, true)) if (str_starts_with(*i, prefix, true))
{ {

@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h" #include "irrlichttypes_bloated.h"
#include <string> #include <string>
#include <vector>
#include <list>
// Chat console related classes, only used by the client // Chat console related classes, only used by the client
@ -55,7 +57,7 @@ struct ChatFormattedFragment
struct ChatFormattedLine struct ChatFormattedLine
{ {
// Array of text fragments // Array of text fragments
core::array<ChatFormattedFragment> fragments; std::vector<ChatFormattedFragment> fragments;
// true if first line of one formatted ChatLine // true if first line of one formatted ChatLine
bool first; bool first;
}; };
@ -110,7 +112,7 @@ public:
// Appends the formatted lines to the destination array and // Appends the formatted lines to the destination array and
// returns the number of formatted lines. // returns the number of formatted lines.
u32 formatChatLine(const ChatLine& line, u32 cols, u32 formatChatLine(const ChatLine& line, u32 cols,
core::array<ChatFormattedLine>& destination) const; std::vector<ChatFormattedLine>& destination) const;
protected: protected:
s32 getTopScrollPos() const; s32 getTopScrollPos() const;
@ -120,7 +122,7 @@ private:
// Scrollback size // Scrollback size
u32 m_scrollback; u32 m_scrollback;
// Array of unformatted chat lines // Array of unformatted chat lines
core::array<ChatLine> m_unformatted; std::vector<ChatLine> m_unformatted;
// Number of character columns in console // Number of character columns in console
u32 m_cols; u32 m_cols;
@ -129,7 +131,7 @@ private:
// Scroll position (console's top line index into m_formatted) // Scroll position (console's top line index into m_formatted)
s32 m_scroll; s32 m_scroll;
// Array of formatted lines // Array of formatted lines
core::array<ChatFormattedLine> m_formatted; std::vector<ChatFormattedLine> m_formatted;
// Empty formatted line, for error returns // Empty formatted line, for error returns
ChatFormattedLine m_empty_formatted_line; ChatFormattedLine m_empty_formatted_line;
}; };
@ -158,7 +160,7 @@ public:
void historyNext(); void historyNext();
// Nick completion // 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 // Update console size and reformat the visible portion of the prompt
void reformat(u32 cols); void reformat(u32 cols);
@ -209,7 +211,7 @@ private:
// Currently edited line // Currently edited line
std::wstring m_line; std::wstring m_line;
// History buffer // History buffer
core::array<std::wstring> m_history; std::vector<std::wstring> m_history;
// History index (0 <= m_history_index <= m_history.size()) // History index (0 <= m_history_index <= m_history.size())
u32 m_history_index; u32 m_history_index;
// Maximum number of history entries // Maximum number of history entries

@ -232,8 +232,8 @@ void * MediaFetchThread::Thread()
#if USE_CURL #if USE_CURL
CURL *curl; CURL *curl;
CURLcode res; CURLcode res;
for (core::list<MediaRequest>::Iterator i = m_file_requests.begin(); for (std::list<MediaRequest>::iterator i = m_file_requests.begin();
i != m_file_requests.end(); i++) { i != m_file_requests.end(); ++i) {
curl = curl_easy_init(); curl = curl_easy_init();
assert(curl); assert(curl);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
@ -360,8 +360,8 @@ Client::~Client()
} }
} }
for (core::list<MediaFetchThread*>::Iterator i = m_media_fetch_threads.begin(); for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
i != m_media_fetch_threads.end(); i++) i != m_media_fetch_threads.end(); ++i)
delete *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)) if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
{ {
ScopeProfiler sp(g_profiler, "Client: map timer and unload"); 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, m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
g_settings->getFloat("client_unload_unused_data_timeout"), g_settings->getFloat("client_unload_unused_data_timeout"),
&deleted_blocks); &deleted_blocks);
@ -599,8 +599,8 @@ void Client::step(float dtime)
NOTE: This loop is intentionally iterated the way it is. NOTE: This loop is intentionally iterated the way it is.
*/ */
core::list<v3s16>::Iterator i = deleted_blocks.begin(); std::list<v3s16>::iterator i = deleted_blocks.begin();
core::list<v3s16> sendlist; std::list<v3s16> sendlist;
for(;;) for(;;)
{ {
if(sendlist.size() == 255 || i == deleted_blocks.end()) if(sendlist.size() == 255 || i == deleted_blocks.end())
@ -619,9 +619,9 @@ void Client::step(float dtime)
writeU16(&reply[0], TOSERVER_DELETEDBLOCKS); writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
reply[2] = sendlist.size(); reply[2] = sendlist.size();
u32 k = 0; u32 k = 0;
for(core::list<v3s16>::Iterator for(std::list<v3s16>::iterator
j = sendlist.begin(); j = sendlist.begin();
j != sendlist.end(); j++) j != sendlist.end(); ++j)
{ {
writeV3S16(&reply[2+1+6*k], *j); writeV3S16(&reply[2+1+6*k], *j);
k++; k++;
@ -635,7 +635,7 @@ void Client::step(float dtime)
} }
sendlist.push_back(*i); sendlist.push_back(*i);
i++; ++i;
} }
} }
@ -727,7 +727,7 @@ void Client::step(float dtime)
<<std::endl;*/ <<std::endl;*/
int num_processed_meshes = 0; 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++; num_processed_meshes++;
MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front(); 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) { if (m_media_receive_started) {
bool all_stopped = true; bool all_stopped = true;
for (core::list<MediaFetchThread*>::Iterator thread = m_media_fetch_threads.begin(); for (std::list<MediaFetchThread*>::iterator thread = m_media_fetch_threads.begin();
thread != m_media_fetch_threads.end(); thread++) { thread != m_media_fetch_threads.end(); ++thread) {
all_stopped &= !(*thread)->IsRunning(); 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(); std::pair <std::string, std::string> out = (*thread)->m_file_data.pop_front();
++m_media_received_count; ++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); 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 " errorstream<<"The server sent a file that has not "
<<"been announced."<<std::endl; <<"been announced."<<std::endl;
else else
@ -814,11 +814,11 @@ void Client::step(float dtime)
} }
} }
if (all_stopped) { if (all_stopped) {
core::list<MediaRequest> fetch_failed; std::list<MediaRequest> fetch_failed;
for (core::list<MediaFetchThread*>::Iterator thread = m_media_fetch_threads.begin(); for (std::list<MediaFetchThread*>::iterator thread = m_media_fetch_threads.begin();
thread != m_media_fetch_threads.end(); thread++) { thread != m_media_fetch_threads.end(); ++thread) {
for (core::list<MediaRequest>::Iterator request = (*thread)->m_failed.begin(); for (std::list<MediaRequest>::iterator request = (*thread)->m_failed.begin();
request != (*thread)->m_failed.end(); request++) request != (*thread)->m_failed.end(); ++request)
fetch_failed.push_back(*request); fetch_failed.push_back(*request);
(*thread)->m_failed.clear(); (*thread)->m_failed.clear();
} }
@ -1015,14 +1015,14 @@ void Client::deletingPeer(con::Peer *peer, bool timeout)
string name 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); std::ostringstream os(std::ios_base::binary);
writeU16(os, TOSERVER_REQUEST_MEDIA); writeU16(os, TOSERVER_REQUEST_MEDIA);
writeU16(os, file_requests.size()); writeU16(os, file_requests.size());
for(core::list<MediaRequest>::ConstIterator i = file_requests.begin(); for(std::list<MediaRequest>::const_iterator i = file_requests.begin();
i != file_requests.end(); i++) { i != file_requests.end(); ++i) {
os<<serializeString(i->name); 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: " infostream<<"Client: Received media announcement: packet size: "
<<datasize<<std::endl; <<datasize<<std::endl;
core::list<MediaRequest> file_requests; std::list<MediaRequest> file_requests;
for(int i=0; i<num_files; i++) 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::string sha1_hex = hex_encode(sha1_raw);
std::ostringstream tmp_os(std::ios_base::binary); std::ostringstream tmp_os(std::ios_base::binary);
bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os); 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, try to load it from there
if(found_in_cache) if(found_in_cache)
@ -1677,16 +1677,16 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
request_media(file_requests); request_media(file_requests);
} else { } else {
#if USE_CURL #if USE_CURL
core::list<MediaFetchThread*>::Iterator cur = m_media_fetch_threads.begin(); std::list<MediaFetchThread*>::iterator cur = m_media_fetch_threads.begin();
for(core::list<MediaRequest>::Iterator i = file_requests.begin(); for(std::list<MediaRequest>::iterator i = file_requests.begin();
i != file_requests.end(); i++) { i != file_requests.end(); ++i) {
(*cur)->m_file_requests.push_back(*i); (*cur)->m_file_requests.push_back(*i);
cur++; cur++;
if (cur == m_media_fetch_threads.end()) if (cur == m_media_fetch_threads.end())
cur = m_media_fetch_threads.begin(); cur = m_media_fetch_threads.begin();
} }
for (core::list<MediaFetchThread*>::Iterator i = m_media_fetch_threads.begin(); for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
i != m_media_fetch_threads.end(); i++) { i != m_media_fetch_threads.end(); ++i) {
(*i)->m_remote_url = remote_media; (*i)->m_remote_url = remote_media;
(*i)->Start(); (*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); 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 " errorstream<<"The server sent a file that has not "
<<"been announced."<<std::endl; <<"been announced."<<std::endl;
else else
@ -1936,6 +1936,89 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
event.show_formspec.formname = new std::string(formname); event.show_formspec.formname = new std::string(formname);
m_client_event_queue.push_back(event); 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 else
{ {
infostream<<"Client: Ignoring unknown command " infostream<<"Client: Ignoring unknown command "
@ -2231,7 +2314,7 @@ void Client::sendPlayerItem(u16 item)
void Client::removeNode(v3s16 p) void Client::removeNode(v3s16 p)
{ {
core::map<v3s16, MapBlock*> modified_blocks; std::map<v3s16, MapBlock*> modified_blocks;
try try
{ {
@ -2245,12 +2328,11 @@ void Client::removeNode(v3s16 p)
// add urgent task to update the modified node // add urgent task to update the modified node
addUpdateMeshTaskForNode(p, false, true); addUpdateMeshTaskForNode(p, false, true);
for(core::map<v3s16, MapBlock * >::Iterator for(std::map<v3s16, MapBlock * >::iterator
i = modified_blocks.getIterator(); i = modified_blocks.begin();
i.atEnd() == false; i++) i != modified_blocks.end(); ++i)
{ {
v3s16 p = i.getNode()->getKey(); addUpdateMeshTaskWithEdge(i->first);
addUpdateMeshTaskWithEdge(p);
} }
} }
@ -2258,7 +2340,7 @@ void Client::addNode(v3s16 p, MapNode n)
{ {
TimeTaker timer1("Client::addNode()"); TimeTaker timer1("Client::addNode()");
core::map<v3s16, MapBlock*> modified_blocks; std::map<v3s16, MapBlock*> modified_blocks;
try try
{ {
@ -2268,12 +2350,11 @@ void Client::addNode(v3s16 p, MapNode n)
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
{} {}
for(core::map<v3s16, MapBlock * >::Iterator for(std::map<v3s16, MapBlock * >::iterator
i = modified_blocks.getIterator(); i = modified_blocks.begin();
i.atEnd() == false; i++) i != modified_blocks.end(); ++i)
{ {
v3s16 p = i.getNode()->getKey(); addUpdateMeshTaskWithEdge(i->first);
addUpdateMeshTaskWithEdge(p);
} }
} }
@ -2373,7 +2454,7 @@ ClientActiveObject * Client::getSelectedActiveObject(
core::line3d<f32> shootline_on_map 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); m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
@ -2381,7 +2462,7 @@ ClientActiveObject * Client::getSelectedActiveObject(
// Sort them. // Sort them.
// After this, the closest object is the first in the array. // 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++) for(u32 i=0; i<objects.size(); i++)
{ {
@ -2420,13 +2501,13 @@ void Client::printDebugInfo(std::ostream &os)
<<std::endl;*/ <<std::endl;*/
} }
core::list<std::wstring> Client::getConnectedPlayerNames() std::list<std::wstring> Client::getConnectedPlayerNames()
{ {
core::list<Player*> players = m_env.getPlayers(true); std::list<Player*> players = m_env.getPlayers(true);
core::list<std::wstring> playerNames; std::list<std::wstring> playerNames;
for(core::list<Player*>::Iterator for(std::list<Player*>::iterator
i = players.begin(); i = players.begin();
i != players.end(); i++) i != players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
playerNames.push_back(narrow_to_wide(player->getName())); playerNames.push_back(narrow_to_wide(player->getName()));

@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h" #include "server.h"
#include "particles.h" #include "particles.h"
#include "util/pointedthing.h" #include "util/pointedthing.h"
#include <algorithm>
struct MeshMakeData; struct MeshMakeData;
class MapBlockMesh; class MapBlockMesh;
@ -142,9 +143,9 @@ public:
void * Thread(); void * Thread();
core::list<MediaRequest> m_file_requests; std::list<MediaRequest> m_file_requests;
MutexedQueue<std::pair<std::string, std::string> > m_file_data; 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; std::string m_remote_url;
IGameDef *m_gamedef; IGameDef *m_gamedef;
}; };
@ -156,7 +157,10 @@ enum ClientEventType
CE_PLAYER_FORCE_MOVE, CE_PLAYER_FORCE_MOVE,
CE_DEATHSCREEN, CE_DEATHSCREEN,
CE_TEXTURES_UPDATED, CE_TEXTURES_UPDATED,
CE_SHOW_FORMSPEC CE_SHOW_FORMSPEC,
CE_SPAWN_PARTICLE,
CE_ADD_PARTICLESPAWNER,
CE_DELETE_PARTICLESPAWNER
}; };
struct ClientEvent struct ClientEvent
@ -184,6 +188,35 @@ struct ClientEvent
} show_formspec; } show_formspec;
struct{ struct{
} textures_updated; } 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 // Prints a line or two of info
void printDebugInfo(std::ostream &os); void printDebugInfo(std::ostream &os);
core::list<std::wstring> getConnectedPlayerNames(); std::list<std::wstring> getConnectedPlayerNames();
float getAnimationTime(); float getAnimationTime();
@ -347,7 +380,7 @@ private:
// Insert a media file appropriately into the appropriate manager // Insert a media file appropriately into the appropriate manager
bool loadMedia(const std::string &data, const std::string &filename); 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 // Virtual methods from con::PeerHandler
void peerAdded(con::Peer *peer); void peerAdded(con::Peer *peer);
@ -377,7 +410,7 @@ private:
MtEventManager *m_event; MtEventManager *m_event;
MeshUpdateThread m_mesh_update_thread; MeshUpdateThread m_mesh_update_thread;
core::list<MediaFetchThread*> m_media_fetch_threads; std::list<MediaFetchThread*> m_media_fetch_threads;
ClientEnvironment m_env; ClientEnvironment m_env;
con::Connection m_con; con::Connection m_con;
IrrlichtDevice *m_device; IrrlichtDevice *m_device;
@ -387,7 +420,7 @@ private:
bool m_inventory_updated; bool m_inventory_updated;
Inventory *m_inventory_from_server; Inventory *m_inventory_from_server;
float m_inventory_from_server_age; float m_inventory_from_server_age;
core::map<v3s16, bool> m_active_blocks; std::set<v3s16> m_active_blocks;
PacketCounter m_packetcounter; PacketCounter m_packetcounter;
// Block mesh animation parameters // Block mesh animation parameters
float m_animation_time; float m_animation_time;
@ -405,7 +438,7 @@ private:
Queue<ClientEvent> m_client_event_queue; Queue<ClientEvent> m_client_event_queue;
FileCache m_media_cache; FileCache m_media_cache;
// Mapping from media file name to SHA1 checksum // 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; bool m_media_receive_started;
u32 m_media_count; u32 m_media_count;
u32 m_media_received_count; u32 m_media_received_count;

@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "profiler.h" #include "profiler.h"
#include "settings.h" #include "settings.h"
#include "util/mathconstants.h" #include "util/mathconstants.h"
#include <algorithm>
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" #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 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
m_sectors.insert(p2d, sector); m_sectors[p2d] = sector;
} }
return sector; return sector;
@ -164,11 +165,11 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
INodeDefManager *nodemgr = m_gamedef->ndef(); INodeDefManager *nodemgr = m_gamedef->ndef();
for(core::map<v3s16, MapBlock*>::Iterator for(std::map<v3s16, MapBlock*>::iterator
i = m_drawlist.getIterator(); i = m_drawlist.begin();
i.atEnd() == false; i++) i != m_drawlist.end(); ++i)
{ {
MapBlock *block = i.getNode()->getValue(); MapBlock *block = i->second;
block->refDrop(); block->refDrop();
} }
m_drawlist.clear(); m_drawlist.clear();
@ -215,11 +216,11 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
// Blocks from which stuff was actually drawn // Blocks from which stuff was actually drawn
//u32 blocks_without_stuff = 0; //u32 blocks_without_stuff = 0;
for(core::map<v2s16, MapSector*>::Iterator for(std::map<v2s16, MapSector*>::iterator
si = m_sectors.getIterator(); si = m_sectors.begin();
si.atEnd() == false; si++) si != m_sectors.end(); ++si)
{ {
MapSector *sector = si.getNode()->getValue(); MapSector *sector = si->second;
v2s16 sp = sector->getPos(); v2s16 sp = sector->getPos();
if(m_control.range_all == false) if(m_control.range_all == false)
@ -231,7 +232,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
continue; continue;
} }
core::list< MapBlock * > sectorblocks; std::list< MapBlock * > sectorblocks;
sector->getBlocks(sectorblocks); sector->getBlocks(sectorblocks);
/* /*
@ -240,7 +241,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
u32 sector_blocks_drawn = 0; u32 sector_blocks_drawn = 0;
core::list< MapBlock * >::Iterator i; std::list< MapBlock * >::iterator i;
for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++) for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
{ {
MapBlock *block = *i; MapBlock *block = *i;
@ -350,7 +351,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
} // foreach sectorblocks } // foreach sectorblocks
if(sector_blocks_drawn != 0) 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; m_control.blocks_would_have_drawn = blocks_would_have_drawn;
@ -368,12 +369,12 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
struct MeshBufList struct MeshBufList
{ {
video::SMaterial m; video::SMaterial m;
core::list<scene::IMeshBuffer*> bufs; std::list<scene::IMeshBuffer*> bufs;
}; };
struct MeshBufListList struct MeshBufListList
{ {
core::list<MeshBufList> lists; std::list<MeshBufList> lists;
void clear() void clear()
{ {
@ -382,8 +383,8 @@ struct MeshBufListList
void add(scene::IMeshBuffer *buf) void add(scene::IMeshBuffer *buf)
{ {
for(core::list<MeshBufList>::Iterator i = lists.begin(); for(std::list<MeshBufList>::iterator i = lists.begin();
i != lists.end(); i++){ i != lists.end(); ++i){
MeshBufList &l = *i; MeshBufList &l = *i;
if(l.m == buf->getMaterial()){ if(l.m == buf->getMaterial()){
l.bufs.push_back(buf); l.bufs.push_back(buf);
@ -487,11 +488,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
MeshBufListList drawbufs; MeshBufListList drawbufs;
for(core::map<v3s16, MapBlock*>::Iterator for(std::map<v3s16, MapBlock*>::iterator
i = m_drawlist.getIterator(); i = m_drawlist.begin();
i.atEnd() == false; i++) 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 the mesh of the block happened to get deleted, ignore it
if(block->mesh == NULL) 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; int timecheck_counter = 0;
for(core::list<MeshBufList>::Iterator i = lists.begin(); for(std::list<MeshBufList>::iterator i = lists.begin();
i != lists.end(); i++) i != lists.end(); ++i)
{ {
{ {
timecheck_counter++; timecheck_counter++;
@ -595,8 +596,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
driver->setMaterial(list.m); driver->setMaterial(list.m);
for(core::list<scene::IMeshBuffer*>::Iterator j = list.bufs.begin(); for(std::list<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
j != list.bufs.end(); j++) j != list.bufs.end(); ++j)
{ {
scene::IMeshBuffer *buf = *j; scene::IMeshBuffer *buf = *j;
driver->drawMeshBuffer(buf); driver->drawMeshBuffer(buf);
@ -769,7 +770,7 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
float sunlight_min_d = max_d*0.8; float sunlight_min_d = max_d*0.8;
if(sunlight_min_d > 35*BS) if(sunlight_min_d > 35*BS)
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++){ for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
v3f z_dir = z_directions[i]; v3f z_dir = z_directions[i];
z_dir.normalize(); z_dir.normalize();
@ -798,7 +799,7 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
} }
int brightness_sum = 0; int brightness_sum = 0;
int brightness_count = 0; int brightness_count = 0;
values.sort(); std::sort(values.begin(), values.end());
u32 num_values_to_use = values.size(); u32 num_values_to_use = values.size();
if(num_values_to_use >= 10) if(num_values_to_use >= 10)
num_values_to_use -= num_values_to_use/2; num_values_to_use -= num_values_to_use/2;

@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes_extrabloated.h"
#include "map.h" #include "map.h"
#include <set>
#include <map>
struct MapDrawControl struct MapDrawControl
{ {
@ -128,7 +130,7 @@ public:
// Check if sector was drawn on last render() // Check if sector was drawn on last render()
bool sectorWasDrawn(v2s16 p) 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: private:
@ -143,9 +145,9 @@ private:
f32 m_camera_fov; f32 m_camera_fov;
JMutex m_camera_mutex; 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 #endif

@ -43,9 +43,9 @@ ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
ClientEnvironment *env) ClientEnvironment *env)
{ {
// Find factory function // Find factory function
core::map<u16, Factory>::Node *n; std::map<u16, Factory>::iterator n;
n = m_types.find(type); n = m_types.find(type);
if(n == NULL) if(n == m_types.end())
{ {
// If factory is not found, just return. // If factory is not found, just return.
dstream<<"WARNING: ClientActiveObject: No factory for type=" dstream<<"WARNING: ClientActiveObject: No factory for type="
@ -53,18 +53,18 @@ ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
return NULL; return NULL;
} }
Factory f = n->getValue(); Factory f = n->second;
ClientActiveObject *object = (*f)(gamedef, env); ClientActiveObject *object = (*f)(gamedef, env);
return object; return object;
} }
void ClientActiveObject::registerType(u16 type, Factory f) void ClientActiveObject::registerType(u16 type, Factory f)
{ {
core::map<u16, Factory>::Node *n; std::map<u16, Factory>::iterator n;
n = m_types.find(type); n = m_types.find(type);
if(n) if(n != m_types.end())
return; return;
m_types.insert(type, f); m_types[type] = f;
} }

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes_extrabloated.h"
#include "activeobject.h" #include "activeobject.h"
#include <map>
/* /*
@ -96,7 +97,7 @@ protected:
ClientEnvironment *m_env; ClientEnvironment *m_env;
private: private:
// Used for creating objects based on type // Used for creating objects based on type
static core::map<u16, Factory> m_types; static std::map<u16, Factory> m_types;
}; };
struct DistanceSortedActiveObject struct DistanceSortedActiveObject
@ -110,7 +111,7 @@ struct DistanceSortedActiveObject
d = a_d; d = a_d;
} }
bool operator < (DistanceSortedActiveObject &other) bool operator < (const DistanceSortedActiveObject &other) const
{ {
return d < other.d; return d < other.d;
} }

@ -79,9 +79,18 @@ SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
Serialization format changes Serialization format changes
PROTOCOL_VERSION 16: PROTOCOL_VERSION 16:
TOCLIENT_SHOW_FORMSPEC 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 // Server's supported network protocol range
#define SERVER_PROTOCOL_VERSION_MIN 13 #define SERVER_PROTOCOL_VERSION_MIN 13
@ -356,6 +365,7 @@ enum ToClientCommand
u8[len] name u8[len] name
[2] serialized inventory [2] serialized inventory
*/ */
TOCLIENT_SHOW_FORMSPEC = 0x44, TOCLIENT_SHOW_FORMSPEC = 0x44,
/* /*
[0] u16 command [0] u16 command
@ -381,6 +391,46 @@ enum ToClientCommand
f1000 movement_liquid_sink f1000 movement_liquid_sink
f1000 movement_gravity 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 enum ToServerCommand

@ -29,7 +29,8 @@ Clouds::Clouds(
scene::ISceneNode* parent, scene::ISceneNode* parent,
scene::ISceneManager* mgr, scene::ISceneManager* mgr,
s32 id, s32 id,
u32 seed u32 seed,
s16 cloudheight
): ):
scene::ISceneNode(parent, mgr, id), scene::ISceneNode(parent, mgr, id),
m_seed(seed), m_seed(seed),
@ -45,7 +46,8 @@ Clouds::Clouds(
//m_material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; //m_material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; 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, m_box = core::aabbox3d<f32>(-BS*1000000,m_cloud_y-BS,-BS*1000000,
BS*1000000,m_cloud_y+BS,BS*1000000); BS*1000000,m_cloud_y+BS,BS*1000000);

@ -30,7 +30,8 @@ public:
scene::ISceneNode* parent, scene::ISceneNode* parent,
scene::ISceneManager* mgr, scene::ISceneManager* mgr,
s32 id, s32 id,
u32 seed u32 seed,
s16 cloudheight=0
); );
~Clouds(); ~Clouds();

@ -23,7 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h" #include "nodedef.h"
#include "gamedef.h" #include "gamedef.h"
#include "log.h" #include "log.h"
#include "environment.h"
#include "serverobject.h"
#include <vector> #include <vector>
#include <set>
#include "util/timetaker.h" #include "util/timetaker.h"
#include "main.h" // g_profiler #include "main.h" // g_profiler
#include "profiler.h" #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 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime, f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f) v3f &pos_f, v3f &speed_f, v3f &accel_f)
{ {
Map *map = &env->getMap();
//TimeTaker tt("collisionMoveSimple"); //TimeTaker tt("collisionMoveSimple");
ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG); ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG);
@ -215,6 +219,7 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
std::vector<aabb3f> cboxes; std::vector<aabb3f> cboxes;
std::vector<bool> is_unloaded; std::vector<bool> is_unloaded;
std::vector<bool> is_step_up; std::vector<bool> is_step_up;
std::vector<bool> is_object;
std::vector<int> bouncy_values; std::vector<int> bouncy_values;
std::vector<v3s16> node_positions; std::vector<v3s16> node_positions;
{ {
@ -256,6 +261,7 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
is_step_up.push_back(false); is_step_up.push_back(false);
bouncy_values.push_back(n_bouncy_value); bouncy_values.push_back(n_bouncy_value);
node_positions.push_back(p); node_positions.push_back(p);
is_object.push_back(false);
} }
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
@ -267,14 +273,72 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
is_step_up.push_back(false); is_step_up.push_back(false);
bouncy_values.push_back(0); bouncy_values.push_back(0);
node_positions.push_back(p); node_positions.push_back(p);
is_object.push_back(false);
} }
} }
} // tt2 } // 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_unloaded.size());
assert(cboxes.size() == is_step_up.size()); assert(cboxes.size() == is_step_up.size());
assert(cboxes.size() == bouncy_values.size()); assert(cboxes.size() == bouncy_values.size());
assert(cboxes.size() == node_positions.size()); assert(cboxes.size() == node_positions.size());
assert(cboxes.size() == is_object.size());
/* /*
Collision detection Collision detection
@ -386,7 +450,11 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
is_collision = false; is_collision = false;
CollisionInfo info; 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.node_p = node_positions[nearest_boxindex];
info.bouncy = bouncy; info.bouncy = bouncy;
info.old_speed = speed_f; info.old_speed = speed_f;

@ -25,10 +25,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map; class Map;
class IGameDef; class IGameDef;
class Environment;
enum CollisionType enum CollisionType
{ {
COLLISION_NODE COLLISION_NODE,
COLLISION_OBJECT,
}; };
struct CollisionInfo struct CollisionInfo
@ -65,7 +67,7 @@ struct collisionMoveResult
}; };
// Moves using a single iteration; speed should not exceed pos_max_d/dtime // 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 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime, f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f); v3f &pos_f, v3f &speed_f, v3f &accel_f);

@ -76,19 +76,20 @@ SharedBuffer<u8> makeOriginalPacket(
return b; return b;
} }
core::list<SharedBuffer<u8> > makeSplitPacket( std::list<SharedBuffer<u8> > makeSplitPacket(
SharedBuffer<u8> data, SharedBuffer<u8> data,
u32 chunksize_max, u32 chunksize_max,
u16 seqnum) u16 seqnum)
{ {
// Chunk packets, containing the TYPE_SPLIT header // Chunk packets, containing the TYPE_SPLIT header
core::list<SharedBuffer<u8> > chunks; std::list<SharedBuffer<u8> > chunks;
u32 chunk_header_size = 7; u32 chunk_header_size = 7;
u32 maximum_data_size = chunksize_max - chunk_header_size; u32 maximum_data_size = chunksize_max - chunk_header_size;
u32 start = 0; u32 start = 0;
u32 end = 0; u32 end = 0;
u32 chunk_num = 0; u32 chunk_num = 0;
u16 chunk_count = 0;
do{ do{
end = start + maximum_data_size - 1; end = start + maximum_data_size - 1;
if(end > data.getSize() - 1) if(end > data.getSize() - 1)
@ -106,16 +107,15 @@ core::list<SharedBuffer<u8> > makeSplitPacket(
memcpy(&chunk[chunk_header_size], &data[start], payload_size); memcpy(&chunk[chunk_header_size], &data[start], payload_size);
chunks.push_back(chunk); chunks.push_back(chunk);
chunk_count++;
start = end + 1; start = end + 1;
chunk_num++; chunk_num++;
} }
while(end != data.getSize() - 1); while(end != data.getSize() - 1);
u16 chunk_count = chunks.getSize(); for(std::list<SharedBuffer<u8> >::iterator i = chunks.begin();
i != chunks.end(); ++i)
core::list<SharedBuffer<u8> >::Iterator i = chunks.begin();
for(; i != chunks.end(); i++)
{ {
// Write chunk_count // Write chunk_count
writeU16(&((*i)[3]), chunk_count); writeU16(&((*i)[3]), chunk_count);
@ -124,13 +124,13 @@ core::list<SharedBuffer<u8> > makeSplitPacket(
return chunks; return chunks;
} }
core::list<SharedBuffer<u8> > makeAutoSplitPacket( std::list<SharedBuffer<u8> > makeAutoSplitPacket(
SharedBuffer<u8> data, SharedBuffer<u8> data,
u32 chunksize_max, u32 chunksize_max,
u16 &split_seqnum) u16 &split_seqnum)
{ {
u32 original_header_size = 1; u32 original_header_size = 1;
core::list<SharedBuffer<u8> > list; std::list<SharedBuffer<u8> > list;
if(data.getSize() + original_header_size > chunksize_max) if(data.getSize() + original_header_size > chunksize_max)
{ {
list = makeSplitPacket(data, chunksize_max, split_seqnum); list = makeSplitPacket(data, chunksize_max, split_seqnum);
@ -170,11 +170,13 @@ SharedBuffer<u8> makeReliablePacket(
ReliablePacketBuffer ReliablePacketBuffer
*/ */
ReliablePacketBuffer::ReliablePacketBuffer(): m_list_size(0) {}
void ReliablePacketBuffer::print() void ReliablePacketBuffer::print()
{ {
core::list<BufferedPacket>::Iterator i; for(std::list<BufferedPacket>::iterator i = m_list.begin();
i = m_list.begin(); i != m_list.end();
for(; i != m_list.end(); i++) ++i)
{ {
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1])); u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
dout_con<<s<<" "; dout_con<<s<<" ";
@ -186,13 +188,12 @@ bool ReliablePacketBuffer::empty()
} }
u32 ReliablePacketBuffer::size() u32 ReliablePacketBuffer::size()
{ {
return m_list.getSize(); return m_list_size;
} }
RPBSearchResult ReliablePacketBuffer::findPacket(u16 seqnum) RPBSearchResult ReliablePacketBuffer::findPacket(u16 seqnum)
{ {
core::list<BufferedPacket>::Iterator i; std::list<BufferedPacket>::iterator i = m_list.begin();
i = m_list.begin(); for(; i != m_list.end(); ++i)
for(; i != m_list.end(); i++)
{ {
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1])); u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
/*dout_con<<"findPacket(): finding seqnum="<<seqnum /*dout_con<<"findPacket(): finding seqnum="<<seqnum
@ -218,8 +219,8 @@ BufferedPacket ReliablePacketBuffer::popFirst()
if(empty()) if(empty())
throw NotFoundException("Buffer is empty"); throw NotFoundException("Buffer is empty");
BufferedPacket p = *m_list.begin(); BufferedPacket p = *m_list.begin();
core::list<BufferedPacket>::Iterator i = m_list.begin(); m_list.erase(m_list.begin());
m_list.erase(i); --m_list_size;
return p; return p;
} }
BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum) BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
@ -231,6 +232,7 @@ BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
} }
BufferedPacket p = *r; BufferedPacket p = *r;
m_list.erase(r); m_list.erase(r);
--m_list_size;
return p; return p;
} }
void ReliablePacketBuffer::insert(BufferedPacket &p) void ReliablePacketBuffer::insert(BufferedPacket &p)
@ -240,6 +242,7 @@ void ReliablePacketBuffer::insert(BufferedPacket &p)
assert(type == TYPE_RELIABLE); assert(type == TYPE_RELIABLE);
u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE+1]); u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE+1]);
++m_list_size;
// Find the right place for the packet and insert it there // Find the right place for the packet and insert it there
// If list is empty, just add it // If list is empty, just add it
@ -250,12 +253,12 @@ void ReliablePacketBuffer::insert(BufferedPacket &p)
return; return;
} }
// Otherwise find the right place // Otherwise find the right place
core::list<BufferedPacket>::Iterator i; std::list<BufferedPacket>::iterator i = m_list.begin();
i = m_list.begin();
// Find the first packet in the list which has a higher seqnum // 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])); u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
if(s == seqnum){ if(s == seqnum){
--m_list_size;
throw AlreadyExistsException("Same seqnum in list"); throw AlreadyExistsException("Same seqnum in list");
} }
if(seqnum_higher(s, seqnum)){ if(seqnum_higher(s, seqnum)){
@ -271,14 +274,14 @@ void ReliablePacketBuffer::insert(BufferedPacket &p)
return; return;
} }
// Insert before i // Insert before i
m_list.insert_before(i, p); m_list.insert(i, p);
} }
void ReliablePacketBuffer::incrementTimeouts(float dtime) void ReliablePacketBuffer::incrementTimeouts(float dtime)
{ {
core::list<BufferedPacket>::Iterator i; for(std::list<BufferedPacket>::iterator i = m_list.begin();
i = m_list.begin(); i != m_list.end(); ++i)
for(; i != m_list.end(); i++){ {
i->time += dtime; i->time += dtime;
i->totaltime += dtime; i->totaltime += dtime;
} }
@ -286,9 +289,9 @@ void ReliablePacketBuffer::incrementTimeouts(float dtime)
void ReliablePacketBuffer::resetTimedOuts(float timeout) void ReliablePacketBuffer::resetTimedOuts(float timeout)
{ {
core::list<BufferedPacket>::Iterator i; for(std::list<BufferedPacket>::iterator i = m_list.begin();
i = m_list.begin(); i != m_list.end(); ++i)
for(; i != m_list.end(); i++){ {
if(i->time >= timeout) if(i->time >= timeout)
i->time = 0.0; i->time = 0.0;
} }
@ -296,21 +299,20 @@ void ReliablePacketBuffer::resetTimedOuts(float timeout)
bool ReliablePacketBuffer::anyTotaltimeReached(float timeout) bool ReliablePacketBuffer::anyTotaltimeReached(float timeout)
{ {
core::list<BufferedPacket>::Iterator i; for(std::list<BufferedPacket>::iterator i = m_list.begin();
i = m_list.begin(); i != m_list.end(); ++i)
for(; i != m_list.end(); i++){ {
if(i->totaltime >= timeout) if(i->totaltime >= timeout)
return true; return true;
} }
return false; return false;
} }
core::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout) std::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout)
{ {
core::list<BufferedPacket> timed_outs; std::list<BufferedPacket> timed_outs;
core::list<BufferedPacket>::Iterator i; for(std::list<BufferedPacket>::iterator i = m_list.begin();
i = m_list.begin(); i != m_list.end(); ++i)
for(; i != m_list.end(); i++)
{ {
if(i->time >= timeout) if(i->time >= timeout)
timed_outs.push_back(*i); timed_outs.push_back(*i);
@ -324,11 +326,10 @@ core::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout)
IncomingSplitBuffer::~IncomingSplitBuffer() IncomingSplitBuffer::~IncomingSplitBuffer()
{ {
core::map<u16, IncomingSplitPacket*>::Iterator i; for(std::map<u16, IncomingSplitPacket*>::iterator i = m_buf.begin();
i = m_buf.getIterator(); i != m_buf.end(); ++i)
for(; i.atEnd() == false; 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]); u16 chunk_num = readU16(&p.data[BASE_HEADER_SIZE+5]);
// Add if doesn't exist // Add if doesn't exist
if(m_buf.find(seqnum) == NULL) if(m_buf.find(seqnum) == m_buf.end())
{ {
IncomingSplitPacket *sp = new IncomingSplitPacket(); IncomingSplitPacket *sp = new IncomingSplitPacket();
sp->chunk_count = chunk_count; sp->chunk_count = chunk_count;
@ -369,7 +370,7 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
// If chunk already exists, ignore it. // If chunk already exists, ignore it.
// Sometimes two identical packets may arrive when there is network // Sometimes two identical packets may arrive when there is network
// lag and the server re-sends stuff. // 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>(); return SharedBuffer<u8>();
// Cut chunk data out of packet // Cut chunk data out of packet
@ -386,11 +387,10 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
// Calculate total size // Calculate total size
u32 totalsize = 0; u32 totalsize = 0;
core::map<u16, SharedBuffer<u8> >::Iterator i; for(std::map<u16, SharedBuffer<u8> >::iterator i = sp->chunks.begin();
i = sp->chunks.getIterator(); i != sp->chunks.end(); ++i)
for(; i.atEnd() == false; i++)
{ {
totalsize += i.getNode()->getValue().getSize(); totalsize += i->second.getSize();
} }
SharedBuffer<u8> fulldata(totalsize); SharedBuffer<u8> fulldata(totalsize);
@ -407,34 +407,32 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
} }
// Remove sp from buffer // Remove sp from buffer
m_buf.remove(seqnum); m_buf.erase(seqnum);
delete sp; delete sp;
return fulldata; return fulldata;
} }
void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout) void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout)
{ {
core::list<u16> remove_queue; std::list<u16> remove_queue;
core::map<u16, IncomingSplitPacket*>::Iterator i; for(std::map<u16, IncomingSplitPacket*>::iterator i = m_buf.begin();
i = m_buf.getIterator(); i != m_buf.end(); ++i)
for(; i.atEnd() == false; i++)
{ {
IncomingSplitPacket *p = i.getNode()->getValue(); IncomingSplitPacket *p = i->second;
// Reliable ones are not removed by timeout // Reliable ones are not removed by timeout
if(p->reliable == true) if(p->reliable == true)
continue; continue;
p->time += dtime; p->time += dtime;
if(p->time >= timeout) if(p->time >= timeout)
remove_queue.push_back(i.getNode()->getKey()); remove_queue.push_back(i->first);
} }
core::list<u16>::Iterator j; for(std::list<u16>::iterator j = remove_queue.begin();
j = remove_queue.begin(); j != remove_queue.end(); ++j)
for(; j != remove_queue.end(); j++)
{ {
dout_con<<"NOTE: Removing timed out unreliable split packet" dout_con<<"NOTE: Removing timed out unreliable split packet"
<<std::endl; <<std::endl;
delete m_buf[*j]; delete m_buf[*j];
m_buf.remove(*j); m_buf.erase(*j);
} }
} }
@ -556,12 +554,11 @@ Connection::~Connection()
{ {
stop(); stop();
// Delete peers // Delete peers
for(core::map<u16, Peer*>::Iterator for(std::map<u16, Peer*>::iterator
j = m_peers.getIterator(); j = m_peers.begin();
j.atEnd() == false; j++) j != m_peers.end(); ++j)
{ {
Peer *peer = j.getNode()->getValue(); delete j->second;
delete peer;
} }
} }
@ -591,7 +588,7 @@ void * Connection::Thread()
runTimeouts(dtime); runTimeouts(dtime);
while(m_command_queue.size() != 0){ while(!m_command_queue.empty()){
ConnectionCommand c = m_command_queue.pop_front(); ConnectionCommand c = m_command_queue.pop_front();
processCommand(c); processCommand(c);
} }
@ -648,18 +645,18 @@ void Connection::processCommand(ConnectionCommand &c)
void Connection::send(float dtime) void Connection::send(float dtime)
{ {
for(core::map<u16, Peer*>::Iterator for(std::map<u16, Peer*>::iterator
j = m_peers.getIterator(); j = m_peers.begin();
j.atEnd() == false; j++) j != m_peers.end(); ++j)
{ {
Peer *peer = j.getNode()->getValue(); Peer *peer = j->second;
peer->m_sendtime_accu += dtime; peer->m_sendtime_accu += dtime;
peer->m_num_sent = 0; peer->m_num_sent = 0;
peer->m_max_num_sent = peer->m_sendtime_accu * peer->m_max_num_sent = peer->m_sendtime_accu *
peer->m_max_packets_per_second; peer->m_max_packets_per_second;
} }
Queue<OutgoingPacket> postponed_packets; Queue<OutgoingPacket> postponed_packets;
while(m_outgoing_queue.size() != 0){ while(!m_outgoing_queue.empty()){
OutgoingPacket packet = m_outgoing_queue.pop_front(); OutgoingPacket packet = m_outgoing_queue.pop_front();
Peer *peer = getPeerNoEx(packet.peer_id); Peer *peer = getPeerNoEx(packet.peer_id);
if(!peer) if(!peer)
@ -674,14 +671,14 @@ void Connection::send(float dtime)
postponed_packets.push_back(packet); postponed_packets.push_back(packet);
} }
} }
while(postponed_packets.size() != 0){ while(!postponed_packets.empty()){
m_outgoing_queue.push_back(postponed_packets.pop_front()); m_outgoing_queue.push_back(postponed_packets.pop_front());
} }
for(core::map<u16, Peer*>::Iterator for(std::map<u16, Peer*>::iterator
j = m_peers.getIterator(); j = m_peers.begin();
j.atEnd() == false; j++) 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_sendtime_accu -= (float)peer->m_num_sent /
peer->m_max_packets_per_second; peer->m_max_packets_per_second;
if(peer->m_sendtime_accu > 10. / 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. Allow only entries that have has_sent_with_id==false.
*/ */
core::map<u16, Peer*>::Iterator j; std::map<u16, Peer*>::iterator j;
j = m_peers.getIterator(); j = m_peers.begin();
for(; j.atEnd() == false; j++) for(; j != m_peers.end(); ++j)
{ {
Peer *peer = j.getNode()->getValue(); Peer *peer = j->second;
if(peer->has_sent_with_id) if(peer->has_sent_with_id)
continue; continue;
if(peer->address == sender) if(peer->address == sender)
@ -766,14 +763,14 @@ void Connection::receive()
If no peer was found with the same address and port, If no peer was found with the same address and port,
we shall assume it is a new peer and create an entry. 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 // Pass on to adding the peer
} }
// Else: A peer was found. // Else: A peer was found.
else else
{ {
Peer *peer = j.getNode()->getValue(); Peer *peer = j->second;
peer_id = peer->id; peer_id = peer->id;
PrintInfo(derr_con); PrintInfo(derr_con);
derr_con<<"WARNING: Assuming unknown peer to be " derr_con<<"WARNING: Assuming unknown peer to be "
@ -797,7 +794,7 @@ void Connection::receive()
for(;;) for(;;)
{ {
// Check if exists // Check if exists
if(m_peers.find(peer_id_new) == NULL) if(m_peers.find(peer_id_new) == m_peers.end())
break; break;
// Check for overflow // Check for overflow
if(peer_id_new == 65535){ if(peer_id_new == 65535){
@ -817,7 +814,7 @@ void Connection::receive()
// Create a peer // Create a peer
Peer *peer = new Peer(peer_id_new, sender); Peer *peer = new Peer(peer_id_new, sender);
m_peers.insert(peer->id, peer); m_peers[peer->id] = peer;
// Create peer addition event // Create peer addition event
ConnectionEvent e; ConnectionEvent e;
@ -837,9 +834,9 @@ void Connection::receive()
// Go on and process whatever it sent // 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 // Peer not found
// This means that the peer id of the sender is not PEER_ID_INEXISTENT // 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)"); throw InvalidIncomingDataException("Peer not found (possible timeout)");
} }
Peer *peer = node->getValue(); Peer *peer = node->second;
// Validate peer address // Validate peer address
if(peer->address != sender) if(peer->address != sender)
@ -902,12 +899,11 @@ void Connection::runTimeouts(float dtime)
float congestion_control_min_rate float congestion_control_min_rate
= g_settings->getFloat("congestion_control_min_rate"); = g_settings->getFloat("congestion_control_min_rate");
core::list<u16> timeouted_peers; std::list<u16> timeouted_peers;
core::map<u16, Peer*>::Iterator j; for(std::map<u16, Peer*>::iterator j = m_peers.begin();
j = m_peers.getIterator(); j != m_peers.end(); ++j)
for(; j.atEnd() == false; j++)
{ {
Peer *peer = j.getNode()->getValue(); Peer *peer = j->second;
// Update congestion control values // Update congestion control values
peer->congestion_control_aim_rtt = congestion_control_aim_rtt; peer->congestion_control_aim_rtt = congestion_control_aim_rtt;
@ -934,8 +930,7 @@ void Connection::runTimeouts(float dtime)
float resend_timeout = peer->resend_timeout; float resend_timeout = peer->resend_timeout;
for(u16 i=0; i<CHANNEL_COUNT; i++) for(u16 i=0; i<CHANNEL_COUNT; i++)
{ {
core::list<BufferedPacket> timed_outs; std::list<BufferedPacket> timed_outs;
core::list<BufferedPacket>::Iterator j;
Channel *channel = &peer->channels[i]; Channel *channel = &peer->channels[i];
@ -966,8 +961,8 @@ void Connection::runTimeouts(float dtime)
channel->outgoing_reliables.resetTimedOuts(resend_timeout); channel->outgoing_reliables.resetTimedOuts(resend_timeout);
j = timed_outs.begin(); for(std::list<BufferedPacket>::iterator j = timed_outs.begin();
for(; j != timed_outs.end(); j++) j != timed_outs.end(); ++j)
{ {
u16 peer_id = readPeerId(*(j->data)); u16 peer_id = readPeerId(*(j->data));
u8 channel = readChannel(*(j->data)); u8 channel = readChannel(*(j->data));
@ -1012,8 +1007,8 @@ nextpeer:
} }
// Remove timed out peers // Remove timed out peers
core::list<u16>::Iterator i = timeouted_peers.begin(); for(std::list<u16>::iterator i = timeouted_peers.begin();
for(; i != timeouted_peers.end(); i++) i != timeouted_peers.end(); ++i)
{ {
PrintInfo(derr_con); PrintInfo(derr_con);
derr_con<<"RunTimeouts(): Removing peer "<<(*i)<<std::endl; derr_con<<"RunTimeouts(): Removing peer "<<(*i)<<std::endl;
@ -1041,13 +1036,13 @@ void Connection::connect(Address address)
dout_con<<getDesc()<<" connecting to "<<address.serializeString() dout_con<<getDesc()<<" connecting to "<<address.serializeString()
<<":"<<address.getPort()<<std::endl; <<":"<<address.getPort()<<std::endl;
core::map<u16, Peer*>::Node *node = m_peers.find(PEER_ID_SERVER); std::map<u16, Peer*>::iterator node = m_peers.find(PEER_ID_SERVER);
if(node != NULL){ if(node != m_peers.end()){
throw ConnectionException("Already connected to a server"); throw ConnectionException("Already connected to a server");
} }
Peer *peer = new Peer(PEER_ID_SERVER, address); Peer *peer = new Peer(PEER_ID_SERVER, address);
m_peers.insert(peer->id, peer); m_peers[peer->id] = peer;
// Create event // Create event
ConnectionEvent e; ConnectionEvent e;
@ -1072,22 +1067,20 @@ void Connection::disconnect()
writeU8(&data[1], CONTROLTYPE_DISCO); writeU8(&data[1], CONTROLTYPE_DISCO);
// Send to all // Send to all
core::map<u16, Peer*>::Iterator j; for(std::map<u16, Peer*>::iterator j = m_peers.begin();
j = m_peers.getIterator(); j != m_peers.end(); ++j)
for(; j.atEnd() == false; j++)
{ {
Peer *peer = j.getNode()->getValue(); Peer *peer = j->second;
rawSendAsPacket(peer->id, 0, data, false); rawSendAsPacket(peer->id, 0, data, false);
} }
} }
void Connection::sendToAll(u8 channelnum, SharedBuffer<u8> data, bool reliable) void Connection::sendToAll(u8 channelnum, SharedBuffer<u8> data, bool reliable)
{ {
core::map<u16, Peer*>::Iterator j; for(std::map<u16, Peer*>::iterator j = m_peers.begin();
j = m_peers.getIterator(); j != m_peers.end(); ++j)
for(; j.atEnd() == false; j++)
{ {
Peer *peer = j.getNode()->getValue(); Peer *peer = j->second;
send(peer->id, channelnum, data, reliable); send(peer->id, channelnum, data, reliable);
} }
} }
@ -1108,13 +1101,12 @@ void Connection::send(u16 peer_id, u8 channelnum,
if(reliable) if(reliable)
chunksize_max -= RELIABLE_HEADER_SIZE; chunksize_max -= RELIABLE_HEADER_SIZE;
core::list<SharedBuffer<u8> > originals; std::list<SharedBuffer<u8> > originals;
originals = makeAutoSplitPacket(data, chunksize_max, originals = makeAutoSplitPacket(data, chunksize_max,
channel->next_outgoing_split_seqnum); channel->next_outgoing_split_seqnum);
core::list<SharedBuffer<u8> >::Iterator i; for(std::list<SharedBuffer<u8> >::iterator i = originals.begin();
i = originals.begin(); i != originals.end(); ++i)
for(; i != originals.end(); i++)
{ {
SharedBuffer<u8> original = *i; SharedBuffer<u8> original = *i;
@ -1187,40 +1179,39 @@ void Connection::rawSend(const BufferedPacket &packet)
Peer* Connection::getPeer(u16 peer_id) 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)"); throw PeerNotFoundException("GetPeer: Peer not found (possible timeout)");
} }
// Error checking // 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) 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; return NULL;
} }
// Error checking // 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; std::list<Peer*> list;
core::map<u16, Peer*>::Iterator j; for(std::map<u16, Peer*>::iterator j = m_peers.begin();
j = m_peers.getIterator(); j != m_peers.end(); ++j)
for(; j.atEnd() == false; j++)
{ {
Peer *peer = j.getNode()->getValue(); Peer *peer = j->second;
list.push_back(peer); list.push_back(peer);
} }
return list; return list;
@ -1228,11 +1219,10 @@ core::list<Peer*> Connection::getPeers()
bool Connection::getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst) bool Connection::getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst)
{ {
core::map<u16, Peer*>::Iterator j; for(std::map<u16, Peer*>::iterator j = m_peers.begin();
j = m_peers.getIterator(); j != m_peers.end(); ++j)
for(; j.atEnd() == false; j++)
{ {
Peer *peer = j.getNode()->getValue(); Peer *peer = j->second;
for(u16 i=0; i<CHANNEL_COUNT; i++) for(u16 i=0; i<CHANNEL_COUNT; i++)
{ {
Channel *channel = &peer->channels[i]; Channel *channel = &peer->channels[i];
@ -1538,7 +1528,7 @@ SharedBuffer<u8> Connection::processPacket(Channel *channel,
bool Connection::deletePeer(u16 peer_id, bool timeout) 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; return false;
Peer *peer = m_peers[peer_id]; Peer *peer = m_peers[peer_id];
@ -1549,7 +1539,7 @@ bool Connection::deletePeer(u16 peer_id, bool timeout)
putEvent(e); putEvent(e);
delete m_peers[peer_id]; delete m_peers[peer_id];
m_peers.remove(peer_id); m_peers.erase(peer_id);
return true; return true;
} }
@ -1557,7 +1547,7 @@ bool Connection::deletePeer(u16 peer_id, bool timeout)
ConnectionEvent Connection::getEvent() ConnectionEvent Connection::getEvent()
{ {
if(m_event_queue.size() == 0){ if(m_event_queue.empty()){
ConnectionEvent e; ConnectionEvent e;
e.type = CONNEVENT_NONE; e.type = CONNEVENT_NONE;
return e; return e;
@ -1602,8 +1592,8 @@ bool Connection::Connected()
if(m_peers.size() != 1) if(m_peers.size() != 1)
return false; return false;
core::map<u16, Peer*>::Node *node = m_peers.find(PEER_ID_SERVER); std::map<u16, Peer*>::iterator node = m_peers.find(PEER_ID_SERVER);
if(node == NULL) if(node == m_peers.end())
return false; return false;
if(m_peer_id == PEER_ID_INEXISTENT) if(m_peer_id == PEER_ID_INEXISTENT)

@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/thread.h" #include "util/thread.h"
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <list>
#include <map>
namespace con namespace con
{ {
@ -142,14 +144,14 @@ SharedBuffer<u8> makeOriginalPacket(
SharedBuffer<u8> data); SharedBuffer<u8> data);
// Split data in chunks and add TYPE_SPLIT headers to them // Split data in chunks and add TYPE_SPLIT headers to them
core::list<SharedBuffer<u8> > makeSplitPacket( std::list<SharedBuffer<u8> > makeSplitPacket(
SharedBuffer<u8> data, SharedBuffer<u8> data,
u32 chunksize_max, u32 chunksize_max,
u16 seqnum); u16 seqnum);
// Depending on size, make a TYPE_ORIGINAL or TYPE_SPLIT packet // Depending on size, make a TYPE_ORIGINAL or TYPE_SPLIT packet
// Increments split_seqnum if a split packet is made // Increments split_seqnum if a split packet is made
core::list<SharedBuffer<u8> > makeAutoSplitPacket( std::list<SharedBuffer<u8> > makeAutoSplitPacket(
SharedBuffer<u8> data, SharedBuffer<u8> data,
u32 chunksize_max, u32 chunksize_max,
u16 &split_seqnum); u16 &split_seqnum);
@ -167,7 +169,7 @@ struct IncomingSplitPacket
reliable = false; reliable = false;
} }
// Key is chunk number, value is data without headers // Key is chunk number, value is data without headers
core::map<u16, SharedBuffer<u8> > chunks; std::map<u16, SharedBuffer<u8> > chunks;
u32 chunk_count; u32 chunk_count;
float time; // Seconds from adding float time; // Seconds from adding
bool reliable; // If true, isn't deleted on timeout 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. for fast access to the smallest one.
*/ */
typedef core::list<BufferedPacket>::Iterator RPBSearchResult; typedef std::list<BufferedPacket>::iterator RPBSearchResult;
class ReliablePacketBuffer class ReliablePacketBuffer
{ {
public: public:
ReliablePacketBuffer();
void print(); void print();
bool empty(); bool empty();
u32 size(); u32 size();
@ -286,10 +288,11 @@ public:
void incrementTimeouts(float dtime); void incrementTimeouts(float dtime);
void resetTimedOuts(float timeout); void resetTimedOuts(float timeout);
bool anyTotaltimeReached(float timeout); bool anyTotaltimeReached(float timeout);
core::list<BufferedPacket> getTimedOuts(float timeout); std::list<BufferedPacket> getTimedOuts(float timeout);
private: private:
core::list<BufferedPacket> m_list; std::list<BufferedPacket> m_list;
u16 m_list_size;
}; };
/* /*
@ -310,7 +313,7 @@ public:
private: private:
// Key is seqnum // Key is seqnum
core::map<u16, IncomingSplitPacket*> m_buf; std::map<u16, IncomingSplitPacket*> m_buf;
}; };
class Connection; class Connection;
@ -589,7 +592,7 @@ private:
void rawSend(const BufferedPacket &packet); void rawSend(const BufferedPacket &packet);
Peer* getPeer(u16 peer_id); Peer* getPeer(u16 peer_id);
Peer* getPeerNoEx(u16 peer_id); Peer* getPeerNoEx(u16 peer_id);
core::list<Peer*> getPeers(); std::list<Peer*> getPeers();
bool getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst); bool getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst);
// Returns next data from a buffer if possible // Returns next data from a buffer if possible
// If found, returns true; if not, false. // If found, returns true; if not, false.
@ -619,7 +622,7 @@ private:
UDPSocket m_socket; UDPSocket m_socket;
u16 m_peer_id; u16 m_peer_id;
core::map<u16, Peer*> m_peers; std::map<u16, Peer*> m_peers;
JMutex m_peers_mutex; JMutex m_peers_mutex;
// Backwards compatibility // Backwards compatibility

@ -94,11 +94,22 @@ public:
class MakeTreesFromSaplingsABM : public ActiveBlockModifier class MakeTreesFromSaplingsABM : public ActiveBlockModifier
{ {
private: private:
content_t c_junglesapling;
content_t c_dirt;
content_t c_dirt_with_grass;
public: 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() virtual std::set<std::string> getTriggerContents()
{ {
std::set<std::string> s; std::set<std::string> s;
s.insert("sapling"); s.insert("sapling");
s.insert("junglesapling");
return s; return s;
} }
virtual float getTriggerInterval() virtual float getTriggerInterval()
@ -111,37 +122,46 @@ public:
INodeDefManager *ndef = env->getGameDef()->ndef(); INodeDefManager *ndef = env->getGameDef()->ndef();
ServerMap *map = &env->getServerMap(); ServerMap *map = &env->getServerMap();
actionstream<<"A sapling grows into a tree at " MapNode n_below = map->getNodeNoEx(p - v3s16(0, 1, 0));
<<PP(p)<<std::endl; if (n_below.getContent() != c_dirt &&
n_below.getContent() != c_dirt_with_grass)
return;
core::map<v3s16, MapBlock*> modified_blocks; bool is_jungle_tree = n.getContent() == c_junglesapling;
actionstream <<"A " << (is_jungle_tree ? "jungle " : "")
<< "sapling grows into a tree at "
<< PP(p) << std::endl;
std::map<v3s16, MapBlock*> modified_blocks;
v3s16 tree_p = p; v3s16 tree_p = p;
ManualMapVoxelManipulator vmanip(map); ManualMapVoxelManipulator vmanip(map);
v3s16 tree_blockp = getNodeBlockPos(tree_p); v3s16 tree_blockp = getNodeBlockPos(tree_p);
vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1)); 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); vmanip.blitBackAll(&modified_blocks);
// update lighting // update lighting
core::map<v3s16, MapBlock*> lighting_modified_blocks; std::map<v3s16, MapBlock*> lighting_modified_blocks;
for(core::map<v3s16, MapBlock*>::Iterator lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
i = modified_blocks.getIterator();
i.atEnd() == false; i++)
{
lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
}
map->updateLighting(lighting_modified_blocks, modified_blocks); map->updateLighting(lighting_modified_blocks, modified_blocks);
// Send a MEET_OTHER event // Send a MEET_OTHER event
MapEditEvent event; MapEditEvent event;
event.type = MEET_OTHER; event.type = MEET_OTHER;
for(core::map<v3s16, MapBlock*>::Iterator // event.modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
i = modified_blocks.getIterator(); for(std::map<v3s16, MapBlock*>::iterator
i.atEnd() == false; i++) i = modified_blocks.begin();
i != modified_blocks.end(); ++i)
{ {
v3s16 p = i.getNode()->getKey(); event.modified_blocks.insert(i->first);
event.modified_blocks.insert(p, true);
} }
map->dispatchEvent(&event); map->dispatchEvent(&event);
} }
@ -182,7 +202,7 @@ void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef)
{ {
env->addActiveBlockModifier(new GrowGrassABM()); env->addActiveBlockModifier(new GrowGrassABM());
env->addActiveBlockModifier(new RemoveGrassABM()); env->addActiveBlockModifier(new RemoveGrassABM());
env->addActiveBlockModifier(new MakeTreesFromSaplingsABM()); env->addActiveBlockModifier(new MakeTreesFromSaplingsABM(env, nodedef));
if (g_settings->getBool("liquid_finite")) if (g_settings->getBool("liquid_finite"))
env->addActiveBlockModifier(new LiquidFlowABM(env, nodedef)); env->addActiveBlockModifier(new LiquidFlowABM(env, nodedef));
} }

@ -50,7 +50,7 @@ struct ToolCapabilities;
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" #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 SmoothTranslator
@ -174,6 +174,7 @@ public:
void processMessage(const std::string &data); void processMessage(const std::string &data);
bool getCollisionBox(aabb3f *toset) { return false; }
private: private:
scene::IMeshSceneNode *m_node; scene::IMeshSceneNode *m_node;
v3f m_position; v3f m_position;
@ -329,6 +330,7 @@ public:
std::string infoText() std::string infoText()
{return m_infotext;} {return m_infotext;}
bool getCollisionBox(aabb3f *toset) { return false; }
private: private:
core::aabbox3d<f32> m_selection_box; core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node; scene::IMeshSceneNode *m_node;
@ -643,6 +645,22 @@ public:
ClientActiveObject::registerType(getType(), create); 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) void initialize(const std::string &data)
{ {
infostream<<"GenericCAO: Got init data"<<std::endl; infostream<<"GenericCAO: Got init data"<<std::endl;
@ -1127,8 +1145,7 @@ public:
v3f p_pos = m_position; v3f p_pos = m_position;
v3f p_velocity = m_velocity; v3f p_velocity = m_velocity;
v3f p_acceleration = m_acceleration; v3f p_acceleration = m_acceleration;
IGameDef *gamedef = env->getGameDef(); moveresult = collisionMoveSimple(env,env->getGameDef(),
moveresult = collisionMoveSimple(&env->getMap(), gamedef,
pos_max_d, box, stepheight, dtime, pos_max_d, box, stepheight, dtime,
p_pos, p_velocity, p_acceleration); p_pos, p_velocity, p_acceleration);
// Apply results // Apply results

@ -42,7 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// (compatible with ContentFeatures). If you specified 0,0,1,1 // (compatible with ContentFeatures). If you specified 0,0,1,1
// for each face, that would be the same as passing NULL. // for each face, that would be the same as passing NULL.
void makeCuboid(MeshCollector *collector, const aabb3f &box, void makeCuboid(MeshCollector *collector, const aabb3f &box,
const TileSpec *tiles, int tilecount, TileSpec *tiles, int tilecount,
video::SColor &c, const f32* txc) video::SColor &c, const f32* txc)
{ {
assert(tilecount >= 1 && tilecount <= 6); assert(tilecount >= 1 && tilecount <= 6);
@ -50,6 +50,8 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
v3f min = box.MinEdge; v3f min = box.MinEdge;
v3f max = box.MaxEdge; v3f max = box.MaxEdge;
if(txc == NULL) if(txc == NULL)
{ {
static const f32 txc_default[24] = { 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]), 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); int tileindex = MYMIN(j/4, tilecount-1);
vertices[j].TCoords *= tiles[tileindex].texture.size; vertices[j].TCoords *= tiles[tileindex].texture.size;
vertices[j].TCoords += tiles[tileindex].texture.pos; vertices[j].TCoords += tiles[tileindex].texture.pos;
} }
u16 indices[] = {0,1,2,2,3,0}; u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector // Add to mesh collector
for(s32 j=0; j<24; j+=4) for(s32 j=0; j<24; j+=4)
{ {
@ -160,19 +217,146 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
Add water sources to mesh if using new style Add water sources to mesh if using new style
*/ */
TileSpec tile_liquid = f.special_tiles[0]; 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; AtlasPointer &pa_liquid = tile_liquid.texture;
bool top_is_air = false; bool top_is_same_liquid = false;
MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
if(n.getContent() == CONTENT_AIR) content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);
top_is_air = true; content_t c_source = nodedef->getId(f.liquid_alternative_source);
if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
if(top_is_air == false) top_is_same_liquid = true;
continue;
u16 l = getInteriorLight(n, 0, data); u16 l = getInteriorLight(n, 0, data);
video::SColor c = MapBlock_LightColor(f.alpha, l, decode_light(f.light_source)); 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] = video::S3DVertex vertices[4] =
{ {
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
@ -185,7 +369,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
pa_liquid.x0(), pa_liquid.y0()), 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++) for(s32 i=0; i<4; i++)
{ {
vertices[i].Pos += offset; vertices[i].Pos += offset;
@ -230,9 +414,9 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Neighbor liquid levels (key = relative position) // Neighbor liquid levels (key = relative position)
// Includes current node // Includes current node
core::map<v3s16, f32> neighbor_levels; std::map<v3s16, f32> neighbor_levels;
core::map<v3s16, content_t> neighbor_contents; std::map<v3s16, content_t> neighbor_contents;
core::map<v3s16, u8> neighbor_flags; std::map<v3s16, u8> neighbor_flags;
const u8 neighborflag_top_is_same_liquid = 0x01; const u8 neighborflag_top_is_same_liquid = 0x01;
v3s16 neighbor_dirs[9] = { v3s16 neighbor_dirs[9] = {
v3s16(0,0,0), v3s16(0,0,0),
@ -273,9 +457,9 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
flags |= neighborflag_top_is_same_liquid; flags |= neighborflag_top_is_same_liquid;
} }
neighbor_levels.insert(neighbor_dirs[i], level); neighbor_levels[neighbor_dirs[i]] = level;
neighbor_contents.insert(neighbor_dirs[i], content); neighbor_contents[neighbor_dirs[i]] = content;
neighbor_flags.insert(neighbor_dirs[i], flags); neighbor_flags[neighbor_dirs[i]] = flags;
} }
// Corner heights (average between four liquids) // Corner heights (average between four liquids)
@ -324,7 +508,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
} }
} }
if(air_count >= 2) if(air_count >= 2)
cornerlevel = -0.5*BS+0.1; cornerlevel = -0.5*BS+0.2;
else if(valid_count > 0) else if(valid_count > 0)
cornerlevel /= valid_count; cornerlevel /= valid_count;
corner_levels[i] = cornerlevel; corner_levels[i] = cornerlevel;
@ -1027,13 +1211,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
v3s16(0, 0, 1), v3s16(0, 0, 1),
v3s16(0, 0, -1) v3s16(0, 0, -1)
}; };
TileSpec tiles[6]; 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); u16 l = getInteriorLight(n, 0, data);
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); 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.begin();
i != boxes.end(); i++) 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; aabb3f box = *i;
box.MinEdge += pos; box.MinEdge += pos;
box.MaxEdge += 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 // Compute texture coords
f32 tx1 = (i->MinEdge.X/BS)+0.5; f32 tx1 = (box.MinEdge.X/BS)+0.5;
f32 ty1 = (i->MinEdge.Y/BS)+0.5; f32 ty1 = (box.MinEdge.Y/BS)+0.5;
f32 tz1 = (i->MinEdge.Z/BS)+0.5; f32 tz1 = (box.MinEdge.Z/BS)+0.5;
f32 tx2 = (i->MaxEdge.X/BS)+0.5; f32 tx2 = (box.MaxEdge.X/BS)+0.5;
f32 ty2 = (i->MaxEdge.Y/BS)+0.5; f32 ty2 = (box.MaxEdge.Y/BS)+0.5;
f32 tz2 = (i->MaxEdge.Z/BS)+0.5; f32 tz2 = (box.MaxEdge.Z/BS)+0.5;
f32 txc[24] = { f32 txc[24] = {
// up // up
tx1, 1-tz2, tx2, 1-tz1, tx1, 1-tz2, tx2, 1-tz1,
@ -1070,7 +1274,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// front // front
tx1, 1-ty2, tx2, 1-ty1, tx1, 1-ty2, tx2, 1-ty1,
}; };
makeCuboid(&collector, box, tiles, 6, c, txc); makeCuboid(&collector, box, tiles, 6, c, txc);
} }
break;} break;}

@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "genericobject.h" #include "genericobject.h"
#include "util/serialize.h" #include "util/serialize.h"
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types; std::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
/* /*
DummyLoadSAO DummyLoadSAO
@ -64,6 +64,10 @@ public:
infostream<<"DummyLoadSAO step"<<std::endl; infostream<<"DummyLoadSAO step"<<std::endl;
} }
bool getCollisionBox(aabb3f *toset) {
return false;
}
private: private:
}; };
@ -132,6 +136,10 @@ public:
} }
} }
bool getCollisionBox(aabb3f *toset) {
return false;
}
private: private:
float m_timer1; float m_timer1;
float m_age; float m_age;
@ -208,8 +216,7 @@ public:
v3f pos_f_old = pos_f; v3f pos_f_old = pos_f;
v3f accel_f = v3f(0,0,0); v3f accel_f = v3f(0,0,0);
f32 stepheight = 0; f32 stepheight = 0;
IGameDef *gamedef = m_env->getGameDef(); moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
pos_max_d, box, stepheight, dtime, pos_max_d, box, stepheight, dtime,
pos_f, m_speed_f, accel_f); pos_f, m_speed_f, accel_f);
@ -314,6 +321,10 @@ public:
return 0; return 0;
} }
bool getCollisionBox(aabb3f *toset) {
return false;
}
private: private:
std::string m_itemstring; std::string m_itemstring;
@ -370,8 +381,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
} }
// Initialize something to armor groups // Initialize something to armor groups
m_armor_groups["fleshy"] = 3; m_armor_groups["fleshy"] = 100;
m_armor_groups["snappy"] = 2;
} }
LuaEntitySAO::~LuaEntitySAO() LuaEntitySAO::~LuaEntitySAO()
@ -490,8 +500,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
v3f p_pos = m_base_position; v3f p_pos = m_base_position;
v3f p_velocity = m_velocity; v3f p_velocity = m_velocity;
v3f p_acceleration = m_acceleration; v3f p_acceleration = m_acceleration;
IGameDef *gamedef = m_env->getGameDef(); moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
pos_max_d, box, stepheight, dtime, pos_max_d, box, stepheight, dtime,
p_pos, p_velocity, p_acceleration); p_pos, p_velocity, p_acceleration);
// Apply results // Apply results
@ -880,6 +889,22 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
m_messages_out.push_back(aom); 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 PlayerSAO
*/ */
@ -916,8 +941,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
assert(m_peer_id != 0); assert(m_peer_id != 0);
setBasePosition(m_player->getPosition()); setBasePosition(m_player->getPosition());
m_inventory = &m_player->inventory; m_inventory = &m_player->inventory;
m_armor_groups["choppy"] = 2; m_armor_groups["fleshy"] = 100;
m_armor_groups["fleshy"] = 3;
m_prop.hp_max = PLAYER_MAX_HP; m_prop.hp_max = PLAYER_MAX_HP;
m_prop.physical = false; m_prop.physical = false;
@ -1230,6 +1254,20 @@ void PlayerSAO::moveTo(v3f pos, bool continuous)
m_moved = true; 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, int PlayerSAO::punch(v3f dir,
const ToolCapabilities *toolcap, const ToolCapabilities *toolcap,
ServerActiveObject *puncher, ServerActiveObject *puncher,
@ -1420,3 +1458,7 @@ std::string PlayerSAO::getPropertyPacket()
return gob_cmd_set_properties(m_prop); 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;
}

@ -78,6 +78,7 @@ public:
void setSprite(v2s16 p, int num_frames, float framelength, void setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch); bool select_horiz_by_yawpitch);
std::string getName(); std::string getName();
bool getCollisionBox(aabb3f *toset);
private: private:
std::string getPropertyPacket(); std::string getPropertyPacket();
void sendPosition(bool do_interpolate, bool is_movement_end); void sendPosition(bool do_interpolate, bool is_movement_end);
@ -147,6 +148,8 @@ public:
void setBasePosition(const v3f &position); void setBasePosition(const v3f &position);
void setPos(v3f pos); void setPos(v3f pos);
void moveTo(v3f pos, bool continuous); void moveTo(v3f pos, bool continuous);
void setYaw(float);
void setPitch(float);
/* /*
Interaction interface Interaction interface
@ -233,6 +236,8 @@ public:
m_is_singleplayer = is_singleplayer; m_is_singleplayer = is_singleplayer;
} }
bool getCollisionBox(aabb3f *toset);
private: private:
std::string getPropertyPacket(); std::string getPropertyPacket();

@ -987,6 +987,43 @@ public:
} }
return false; 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 virtual std::string dump() const
{ {
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);

@ -358,6 +358,8 @@ public:
bool decrementInput, IGameDef *gamedef) const=0; bool decrementInput, IGameDef *gamedef) const=0;
virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output, virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
IGameDef *gamedef) const=0; IGameDef *gamedef) const=0;
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
IGameDef *gamedef) const=0;
// Print crafting recipes for debugging // Print crafting recipes for debugging
virtual std::string dump() const=0; virtual std::string dump() const=0;
@ -376,6 +378,8 @@ public:
bool decrementInput, IGameDef *gamedef) const=0; bool decrementInput, IGameDef *gamedef) const=0;
virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output, virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
IGameDef *gamedef) const=0; IGameDef *gamedef) const=0;
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
IGameDef *gamedef) const=0;
// Print crafting recipes for debugging // Print crafting recipes for debugging
virtual std::string dump() const=0; virtual std::string dump() const=0;

@ -130,7 +130,7 @@ void DebugStack::print(std::ostream &os, bool everything)
os<<"Probably overflown."<<std::endl; 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; JMutex g_debug_stacks_mutex;
void debug_stacks_init() void debug_stacks_init()
@ -144,12 +144,11 @@ void debug_stacks_print_to(std::ostream &os)
os<<"Debug stacks:"<<std::endl; os<<"Debug stacks:"<<std::endl;
for(core::map<threadid_t, DebugStack*>::Iterator for(std::map<threadid_t, DebugStack*>::iterator
i = g_debug_stacks.getIterator(); i = g_debug_stacks.begin();
i.atEnd() == false; i++) i != g_debug_stacks.end(); ++i)
{ {
DebugStack *stack = i.getNode()->getValue(); i->second->print(os, false);
stack->print(os, false);
} }
} }
@ -159,11 +158,11 @@ void debug_stacks_print()
DEBUGPRINT("Debug stacks:\n"); DEBUGPRINT("Debug stacks:\n");
for(core::map<threadid_t, DebugStack*>::Iterator for(std::map<threadid_t, DebugStack*>::iterator
i = g_debug_stacks.getIterator(); i = g_debug_stacks.begin();
i.atEnd() == false; i++) i != g_debug_stacks.end(); ++i)
{ {
DebugStack *stack = i.getNode()->getValue(); DebugStack *stack = i->second;
for(int i=0; i<DEBUGSTREAM_COUNT; i++) for(int i=0; i<DEBUGSTREAM_COUNT; i++)
{ {
@ -179,18 +178,18 @@ DebugStacker::DebugStacker(const char *text)
JMutexAutoLock lock(g_debug_stacks_mutex); 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); n = g_debug_stacks.find(threadid);
if(n != NULL) if(n != g_debug_stacks.end())
{ {
m_stack = n->getValue(); m_stack = n->second;
} }
else else
{ {
/*DEBUGPRINT("Creating new debug stack for thread %x\n", /*DEBUGPRINT("Creating new debug stack for thread %x\n",
(unsigned int)threadid);*/ (unsigned int)threadid);*/
m_stack = new DebugStack(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) if(m_stack->stack_i >= DEBUG_STACK_SIZE)
@ -224,7 +223,7 @@ DebugStacker::~DebugStacker()
/*DEBUGPRINT("Deleting debug stack for thread %x\n", /*DEBUGPRINT("Deleting debug stack for thread %x\n",
(unsigned int)threadid);*/ (unsigned int)threadid);*/
delete m_stack; delete m_stack;
g_debug_stacks.remove(threadid); g_debug_stacks.erase(threadid);
} }
} }

@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "threads.h" #include "threads.h"
#include "gettime.h" #include "gettime.h"
#include "exceptions.h" #include "exceptions.h"
#include <map>
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
@ -165,7 +166,7 @@ struct DebugStack
int stack_max_i; // Highest i that was seen 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 JMutex g_debug_stacks_mutex;
extern void debug_stacks_init(); extern void debug_stacks_init();
@ -205,42 +206,42 @@ public:
void add(u16 command) void add(u16 command)
{ {
core::map<u16, u16>::Node *n = m_packets.find(command); std::map<u16, u16>::iterator n = m_packets.find(command);
if(n == NULL) if(n == m_packets.end())
{ {
m_packets[command] = 1; m_packets[command] = 1;
} }
else else
{ {
n->setValue(n->getValue()+1); n->second++;
} }
} }
void clear() void clear()
{ {
for(core::map<u16, u16>::Iterator for(std::map<u16, u16>::iterator
i = m_packets.getIterator(); i = m_packets.begin();
i.atEnd() == false; i++) i != m_packets.end(); ++i)
{ {
i.getNode()->setValue(0); i->second = 0;
} }
} }
void print(std::ostream &o) void print(std::ostream &o)
{ {
for(core::map<u16, u16>::Iterator for(std::map<u16, u16>::iterator
i = m_packets.getIterator(); i = m_packets.begin();
i.atEnd() == false; i++) i != m_packets.end(); ++i)
{ {
o<<"cmd "<<i.getNode()->getKey() o<<"cmd "<<i->first
<<" count "<<i.getNode()->getValue() <<" count "<<i->second
<<std::endl; <<std::endl;
} }
} }
private: private:
// command, count // command, count
core::map<u16, u16> m_packets; std::map<u16, u16> m_packets;
}; };
/* /*

@ -109,6 +109,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("view_bobbing_amount", "1.0"); settings->setDefault("view_bobbing_amount", "1.0");
settings->setDefault("enable_3d_clouds", "true"); settings->setDefault("enable_3d_clouds", "true");
settings->setDefault("cloud_height", "120"); settings->setDefault("cloud_height", "120");
settings->setDefault("menu_clouds", "true");
settings->setDefault("opaque_water", "false"); settings->setDefault("opaque_water", "false");
settings->setDefault("console_color", "(0,0,0)"); settings->setDefault("console_color", "(0,0,0)");
settings->setDefault("console_alpha", "200"); settings->setDefault("console_alpha", "200");
@ -206,8 +207,9 @@ void set_default_settings(Settings *settings)
//liquid stuff //liquid stuff
settings->setDefault("liquid_finite", "false"); settings->setDefault("liquid_finite", "false");
settings->setDefault("liquid_update", "1.0"); settings->setDefault("liquid_update", "1.0");
settings->setDefault("liquid_relax", "1"); settings->setDefault("liquid_relax", "2");
settings->setDefault("liquid_fast_flood", "1"); settings->setDefault("liquid_fast_flood", "1");
settings->setDefault("underground_springs", "1");
//mapgen stuff //mapgen stuff
settings->setDefault("mg_name", "v6"); settings->setDefault("mg_name", "v6");
@ -217,19 +219,41 @@ void set_default_settings(Settings *settings)
settings->setDefault("mgv6_freq_desert", "0.45"); settings->setDefault("mgv6_freq_desert", "0.45");
settings->setDefault("mgv6_freq_beach", "0.15"); 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_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_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_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_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_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_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_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_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_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_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("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));
}
} }

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Settings; class Settings;
void set_default_settings(Settings *settings); void set_default_settings(Settings *settings);
void override_default_settings(Settings *settings, Settings *from);
#endif #endif

634
src/dungeongen.cpp Normal file

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

128
src/dungeongen.h Normal file

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

@ -39,6 +39,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "biome.h" #include "biome.h"
#include "emerge.h" #include "emerge.h"
#include "mapgen_v6.h" #include "mapgen_v6.h"
#include "mapgen_indev.h"
#include "mapgen_singlenode.h"
/////////////////////////////// Emerge Manager //////////////////////////////// /////////////////////////////// Emerge Manager ////////////////////////////////
@ -46,6 +48,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) { EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) {
//register built-in mapgens //register built-in mapgens
registerMapgen("v6", new MapgenFactoryV6()); registerMapgen("v6", new MapgenFactoryV6());
registerMapgen("indev", new MapgenFactoryIndev());
registerMapgen("singlenode", new MapgenFactorySinglenode());
this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef); this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
this->params = NULL; this->params = NULL;
@ -359,7 +363,7 @@ void *EmergeThread::Thread() {
*/ */
BlockMakeData data; BlockMakeData data;
MapBlock *block = NULL; MapBlock *block = NULL;
core::map<v3s16, MapBlock *> modified_blocks; std::map<v3s16, MapBlock *> modified_blocks;
if (getBlockOrStartGen(p, &block, &data, allow_generate)) { if (getBlockOrStartGen(p, &block, &data, allow_generate)) {
{ {
@ -415,13 +419,13 @@ void *EmergeThread::Thread() {
JMutexAutoLock lock(m_server->m_con_mutex); JMutexAutoLock lock(m_server->m_con_mutex);
// Add the originally fetched block to the modified list // Add the originally fetched block to the modified list
if (block) if (block)
modified_blocks.insert(p, block); modified_blocks[p] = block;
// Set the modified blocks unsent for all the clients // Set the modified blocks unsent for all the clients
for (core::map<u16, RemoteClient*>::Iterator for (std::map<u16, RemoteClient*>::iterator
i = m_server->m_clients.getIterator(); i = m_server->m_clients.begin();
i.atEnd() == false; i++) { i != m_server->m_clients.end(); ++i) {
RemoteClient *client = i.getNode()->getValue(); RemoteClient *client = i->second;
if (modified_blocks.size() > 0) { if (modified_blocks.size() > 0) {
// Remove block from sent history // Remove block from sent history
client->SetBlocksNotSent(modified_blocks); client->SetBlocksNotSent(modified_blocks);

@ -63,8 +63,9 @@ public:
std::map<v3s16, BlockEmergeData *> blocks_enqueued; std::map<v3s16, BlockEmergeData *> blocks_enqueued;
std::map<u16, u16> peer_queue_count; std::map<u16, u16> peer_queue_count;
//biome manager //Mapgen-related structures
BiomeDefManager *biomedef; BiomeDefManager *biomedef;
std::vector<Ore *> ores;
EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef); EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef);
~EmergeManager(); ~EmergeManager();

@ -58,8 +58,8 @@ Environment::Environment():
Environment::~Environment() Environment::~Environment()
{ {
// Deallocate players // Deallocate players
for(core::list<Player*>::Iterator i = m_players.begin(); for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
delete (*i); delete (*i);
} }
@ -86,8 +86,8 @@ void Environment::removePlayer(u16 peer_id)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
re_search: re_search:
for(core::list<Player*>::Iterator i = m_players.begin(); for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
if(player->peer_id != peer_id) if(player->peer_id != peer_id)
@ -103,8 +103,8 @@ re_search:
Player * Environment::getPlayer(u16 peer_id) Player * Environment::getPlayer(u16 peer_id)
{ {
for(core::list<Player*>::Iterator i = m_players.begin(); for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
if(player->peer_id == peer_id) if(player->peer_id == peer_id)
@ -115,8 +115,8 @@ Player * Environment::getPlayer(u16 peer_id)
Player * Environment::getPlayer(const char *name) Player * Environment::getPlayer(const char *name)
{ {
for(core::list<Player*>::Iterator i = m_players.begin(); for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
if(strcmp(player->getName(), name) == 0) if(strcmp(player->getName(), name) == 0)
@ -127,12 +127,12 @@ Player * Environment::getPlayer(const char *name)
Player * Environment::getRandomConnectedPlayer() 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 chosen_one = myrand() % connected_players.size();
u32 j = 0; u32 j = 0;
for(core::list<Player*>::Iterator for(std::list<Player*>::iterator
i = connected_players.begin(); i = connected_players.begin();
i != connected_players.end(); i++) i != connected_players.end(); ++i)
{ {
if(j == chosen_one) if(j == chosen_one)
{ {
@ -146,12 +146,12 @@ Player * Environment::getRandomConnectedPlayer()
Player * Environment::getNearestConnectedPlayer(v3f pos) Player * Environment::getNearestConnectedPlayer(v3f pos)
{ {
core::list<Player*> connected_players = getPlayers(true); std::list<Player*> connected_players = getPlayers(true);
f32 nearest_d = 0; f32 nearest_d = 0;
Player *nearest_player = NULL; Player *nearest_player = NULL;
for(core::list<Player*>::Iterator for(std::list<Player*>::iterator
i = connected_players.begin(); i = connected_players.begin();
i != connected_players.end(); i++) i != connected_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
f32 d = player->getPosition().getDistanceFrom(pos); f32 d = player->getPosition().getDistanceFrom(pos);
@ -164,17 +164,17 @@ Player * Environment::getNearestConnectedPlayer(v3f pos)
return nearest_player; return nearest_player;
} }
core::list<Player*> Environment::getPlayers() std::list<Player*> Environment::getPlayers()
{ {
return m_players; return m_players;
} }
core::list<Player*> Environment::getPlayers(bool ignore_disconnected) std::list<Player*> Environment::getPlayers(bool ignore_disconnected)
{ {
core::list<Player*> newlist; std::list<Player*> newlist;
for(core::list<Player*>::Iterator for(std::list<Player*>::iterator
i = m_players.begin(); i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
@ -193,7 +193,7 @@ core::list<Player*> Environment::getPlayers(bool ignore_disconnected)
void Environment::printPlayers(std::ostream &o) void Environment::printPlayers(std::ostream &o)
{ {
o<<"Players in environment:"<<std::endl; 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++) i != m_players.end(); i++)
{ {
Player *player = *i; Player *player = *i;
@ -251,7 +251,7 @@ ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
ActiveBlockList ActiveBlockList
*/ */
void fillRadiusBlock(v3s16 p0, s16 r, core::map<v3s16, bool> &list) void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
{ {
v3s16 p; v3s16 p;
for(p.X=p0.X-r; p.X<=p0.X+r; p.X++) 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++) for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
{ {
// Set in list // 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, s16 radius,
core::map<v3s16, bool> &blocks_removed, std::set<v3s16> &blocks_removed,
core::map<v3s16, bool> &blocks_added) std::set<v3s16> &blocks_added)
{ {
/* /*
Create the new list Create the new list
*/ */
core::map<v3s16, bool> newlist; std::set<v3s16> newlist;
for(core::list<v3s16>::Iterator i = active_positions.begin(); for(std::list<v3s16>::iterator i = active_positions.begin();
i != active_positions.end(); i++) i != active_positions.end(); ++i)
{ {
fillRadiusBlock(*i, radius, newlist); 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 Find out which blocks on the old list are not on the new list
*/ */
// Go through old list // Go through old list
for(core::map<v3s16, bool>::Iterator i = m_list.getIterator(); for(std::set<v3s16>::iterator i = m_list.begin();
i.atEnd()==false; i++) i != m_list.end(); ++i)
{ {
v3s16 p = i.getNode()->getKey(); v3s16 p = *i;
// If not on new list, it's been removed // If not on new list, it's been removed
if(newlist.find(p) == NULL) if(newlist.find(p) == newlist.end())
blocks_removed.insert(p, true); blocks_removed.insert(p);
} }
/* /*
Find out which blocks on the new list are not on the old list Find out which blocks on the new list are not on the old list
*/ */
// Go through new list // Go through new list
for(core::map<v3s16, bool>::Iterator i = newlist.getIterator(); for(std::set<v3s16>::iterator i = newlist.begin();
i.atEnd()==false; i++) i != newlist.end(); ++i)
{ {
v3s16 p = i.getNode()->getKey(); v3s16 p = *i;
// If not on old list, it's been added // If not on old list, it's been added
if(m_list.find(p) == NULL) if(m_list.find(p) == m_list.end())
blocks_added.insert(p, true); blocks_added.insert(p);
} }
/* /*
Update m_list Update m_list
*/ */
m_list.clear(); m_list.clear();
for(core::map<v3s16, bool>::Iterator i = newlist.getIterator(); for(std::set<v3s16>::iterator i = newlist.begin();
i.atEnd()==false; i++) i != newlist.end(); ++i)
{ {
v3s16 p = i.getNode()->getKey(); v3s16 p = *i;
m_list.insert(p, true); m_list.insert(p);
} }
} }
@ -348,8 +348,8 @@ ServerEnvironment::~ServerEnvironment()
m_map->drop(); m_map->drop();
// Delete ActiveBlockModifiers // Delete ActiveBlockModifiers
for(core::list<ABMWithState>::Iterator for(std::list<ABMWithState>::iterator
i = m_abms.begin(); i != m_abms.end(); i++){ i = m_abms.begin(); i != m_abms.end(); ++i){
delete i->abm; delete i->abm;
} }
} }
@ -370,7 +370,7 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
std::string players_path = savedir + "/players"; std::string players_path = savedir + "/players";
fs::CreateDir(players_path); 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); std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
for(u32 i=0; i<player_files.size(); i++) for(u32 i=0; i<player_files.size(); i++)
@ -419,15 +419,15 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
continue; continue;
} }
player->serialize(os); player->serialize(os);
saved_players.insert(player, true); saved_players.insert(player);
} }
} }
for(core::list<Player*>::Iterator i = m_players.begin(); for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
if(saved_players.find(player) != NULL) if(saved_players.find(player) != saved_players.end())
{ {
/*infostream<<"Player "<<player->getName() /*infostream<<"Player "<<player->getName()
<<" was already saved."<<std::endl;*/ <<" was already saved."<<std::endl;*/
@ -473,7 +473,7 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
continue; continue;
} }
player->serialize(os); 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"; std::string players_path = savedir + "/players";
core::map<Player*, bool> saved_players;
std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path); std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
for(u32 i=0; i<player_files.size(); i++) for(u32 i=0; i<player_files.size(); i++)
{ {
@ -627,7 +625,7 @@ private:
ServerEnvironment *m_env; ServerEnvironment *m_env;
std::map<content_t, std::list<ActiveABM> > m_aabms; std::map<content_t, std::list<ActiveABM> > m_aabms;
public: public:
ABMHandler(core::list<ABMWithState> &abms, ABMHandler(std::list<ABMWithState> &abms,
float dtime_s, ServerEnvironment *env, float dtime_s, ServerEnvironment *env,
bool use_timers): bool use_timers):
m_env(env) m_env(env)
@ -635,8 +633,8 @@ public:
if(dtime_s < 0.001) if(dtime_s < 0.001)
return; return;
INodeDefManager *ndef = env->getGameDef()->ndef(); INodeDefManager *ndef = env->getGameDef()->ndef();
for(core::list<ABMWithState>::Iterator for(std::list<ABMWithState>::iterator
i = abms.begin(); i != abms.end(); i++){ i = abms.begin(); i != abms.end(); ++i){
ActiveBlockModifier *abm = i->abm; ActiveBlockModifier *abm = i->abm;
float trigger_interval = abm->getTriggerInterval(); float trigger_interval = abm->getTriggerInterval();
if(trigger_interval < 0.001) 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> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
{ {
std::set<u16> objects; std::set<u16> objects;
for(core::map<u16, ServerActiveObject*>::Iterator for(std::map<u16, ServerActiveObject*>::iterator
i = m_active_objects.getIterator(); i = m_active_objects.begin();
i.atEnd()==false; i++) i != m_active_objects.end(); ++i)
{ {
ServerActiveObject* obj = i.getNode()->getValue(); ServerActiveObject* obj = i->second;
u16 id = i.getNode()->getKey(); u16 id = i->first;
v3f objectpos = obj->getBasePosition(); v3f objectpos = obj->getBasePosition();
if(objectpos.getDistanceFrom(pos) > radius) if(objectpos.getDistanceFrom(pos) > radius)
continue; continue;
@ -880,15 +878,15 @@ void ServerEnvironment::clearAllObjects()
{ {
infostream<<"ServerEnvironment::clearAllObjects(): " infostream<<"ServerEnvironment::clearAllObjects(): "
<<"Removing all active objects"<<std::endl; <<"Removing all active objects"<<std::endl;
core::list<u16> objects_to_remove; std::list<u16> objects_to_remove;
for(core::map<u16, ServerActiveObject*>::Iterator for(std::map<u16, ServerActiveObject*>::iterator
i = m_active_objects.getIterator(); i = m_active_objects.begin();
i.atEnd()==false; i++) i != m_active_objects.end(); ++i)
{ {
ServerActiveObject* obj = i.getNode()->getValue(); ServerActiveObject* obj = i->second;
if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER) if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
continue; continue;
u16 id = i.getNode()->getKey(); u16 id = i->first;
v3f objectpos = obj->getBasePosition(); v3f objectpos = obj->getBasePosition();
// Delete static object if block is loaded // Delete static object if block is loaded
if(obj->m_static_exists){ if(obj->m_static_exists){
@ -919,13 +917,13 @@ void ServerEnvironment::clearAllObjects()
objects_to_remove.push_back(id); objects_to_remove.push_back(id);
} }
// Remove references from m_active_objects // Remove references from m_active_objects
for(core::list<u16>::Iterator i = objects_to_remove.begin(); for(std::list<u16>::iterator i = objects_to_remove.begin();
i != objects_to_remove.end(); i++) 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(): " infostream<<"ServerEnvironment::clearAllObjects(): "
<<"Listing all loadable blocks"<<std::endl; <<"Listing all loadable blocks"<<std::endl;
m_map->listAllLoadableBlocks(loadable_blocks); m_map->listAllLoadableBlocks(loadable_blocks);
@ -937,8 +935,8 @@ void ServerEnvironment::clearAllObjects()
u32 num_blocks_checked = 0; u32 num_blocks_checked = 0;
u32 num_blocks_cleared = 0; u32 num_blocks_cleared = 0;
u32 num_objs_cleared = 0; u32 num_objs_cleared = 0;
for(core::list<v3s16>::Iterator i = loadable_blocks.begin(); for(std::list<v3s16>::iterator i = loadable_blocks.begin();
i != loadable_blocks.end(); i++) i != loadable_blocks.end(); ++i)
{ {
v3s16 p = *i; v3s16 p = *i;
MapBlock *block = m_map->emergeBlock(p, false); 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); ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
for(core::list<Player*>::Iterator i = m_players.begin(); for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
@ -1027,10 +1025,10 @@ void ServerEnvironment::step(float dtime)
/* /*
Get player block positions Get player block positions
*/ */
core::list<v3s16> players_blockpos; std::list<v3s16> players_blockpos;
for(core::list<Player*>::Iterator for(std::list<Player*>::iterator
i = m_players.begin(); i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
// Ignore disconnected players // Ignore disconnected players
@ -1045,8 +1043,8 @@ void ServerEnvironment::step(float dtime)
Update list of active blocks, collecting changes Update list of active blocks, collecting changes
*/ */
const s16 active_block_range = g_settings->getS16("active_block_range"); const s16 active_block_range = g_settings->getS16("active_block_range");
core::map<v3s16, bool> blocks_removed; std::set<v3s16> blocks_removed;
core::map<v3s16, bool> blocks_added; std::set<v3s16> blocks_added;
m_active_blocks.update(players_blockpos, active_block_range, m_active_blocks.update(players_blockpos, active_block_range,
blocks_removed, blocks_added); 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 // Convert active objects that are no more in active blocks to static
deactivateFarObjects(false); deactivateFarObjects(false);
for(core::map<v3s16, bool>::Iterator for(std::set<v3s16>::iterator
i = blocks_removed.getIterator(); i = blocks_removed.begin();
i.atEnd()==false; i++) i != blocks_removed.end(); ++i)
{ {
v3s16 p = i.getNode()->getKey(); v3s16 p = *i;
/*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
<<") became inactive"<<std::endl;*/ <<") became inactive"<<std::endl;*/
@ -1078,11 +1076,11 @@ void ServerEnvironment::step(float dtime)
Handle added blocks Handle added blocks
*/ */
for(core::map<v3s16, bool>::Iterator for(std::set<v3s16>::iterator
i = blocks_added.getIterator(); i = blocks_added.begin();
i.atEnd()==false; i++) i != blocks_added.end(); ++i)
{ {
v3s16 p = i.getNode()->getKey(); v3s16 p = *i;
/*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
<<") became active"<<std::endl;*/ <<") became active"<<std::endl;*/
@ -1091,7 +1089,7 @@ void ServerEnvironment::step(float dtime)
if(block==NULL){ if(block==NULL){
// Block needs to be fetched first // Block needs to be fetched first
m_emerger->queueBlockEmerge(p, false); m_emerger->queueBlockEmerge(p, false);
m_active_blocks.m_list.remove(p); m_active_blocks.m_list.erase(p);
continue; continue;
} }
@ -1108,11 +1106,11 @@ void ServerEnvironment::step(float dtime)
float dtime = 1.0; float dtime = 1.0;
for(core::map<v3s16, bool>::Iterator for(std::set<v3s16>::iterator
i = m_active_blocks.m_list.getIterator(); i = m_active_blocks.m_list.begin();
i.atEnd()==false; i++) 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 /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
<<") being handled"<<std::endl;*/ <<") being handled"<<std::endl;*/
@ -1163,11 +1161,11 @@ void ServerEnvironment::step(float dtime)
// Initialize handling of ActiveBlockModifiers // Initialize handling of ActiveBlockModifiers
ABMHandler abmhandler(m_abms, abm_interval, this, true); ABMHandler abmhandler(m_abms, abm_interval, this, true);
for(core::map<v3s16, bool>::Iterator for(std::set<v3s16>::iterator
i = m_active_blocks.m_list.getIterator(); i = m_active_blocks.m_list.begin();
i.atEnd()==false; i++) 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 /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
<<") being handled"<<std::endl;*/ <<") being handled"<<std::endl;*/
@ -1216,11 +1214,11 @@ void ServerEnvironment::step(float dtime)
send_recommended = true; send_recommended = true;
} }
for(core::map<u16, ServerActiveObject*>::Iterator for(std::map<u16, ServerActiveObject*>::iterator
i = m_active_objects.getIterator(); i = m_active_objects.begin();
i.atEnd()==false; i++) i != m_active_objects.end(); ++i)
{ {
ServerActiveObject* obj = i.getNode()->getValue(); ServerActiveObject* obj = i->second;
// Remove non-peaceful mobs on peaceful mode // Remove non-peaceful mobs on peaceful mode
if(g_settings->getBool("only_peaceful_mobs")){ if(g_settings->getBool("only_peaceful_mobs")){
if(!obj->isPeaceful()) if(!obj->isPeaceful())
@ -1232,7 +1230,7 @@ void ServerEnvironment::step(float dtime)
// Step object // Step object
obj->step(dtime, send_recommended); obj->step(dtime, send_recommended);
// Read messages from object // Read messages from object
while(obj->m_messages_out.size() > 0) while(!obj->m_messages_out.empty())
{ {
m_active_object_messages.push_back( m_active_object_messages.push_back(
obj->m_messages_out.pop_front()); obj->m_messages_out.pop_front());
@ -1255,31 +1253,24 @@ void ServerEnvironment::step(float dtime)
ServerActiveObject* ServerEnvironment::getActiveObject(u16 id) ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
{ {
core::map<u16, ServerActiveObject*>::Node *n; std::map<u16, ServerActiveObject*>::iterator n;
n = m_active_objects.find(id); n = m_active_objects.find(id);
if(n == NULL) if(n == m_active_objects.end())
return NULL; return NULL;
return n->getValue(); return n->second;
} }
bool isFreeServerActiveObjectId(u16 id, bool isFreeServerActiveObjectId(u16 id,
core::map<u16, ServerActiveObject*> &objects) std::map<u16, ServerActiveObject*> &objects)
{ {
if(id == 0) if(id == 0)
return false; return false;
for(core::map<u16, ServerActiveObject*>::Iterator return objects.find(id) == objects.end();
i = objects.getIterator();
i.atEnd()==false; i++)
{
if(i.getNode()->getKey() == id)
return false;
}
return true;
} }
u16 getFreeServerActiveObjectId( u16 getFreeServerActiveObjectId(
core::map<u16, ServerActiveObject*> &objects) std::map<u16, ServerActiveObject*> &objects)
{ {
u16 new_id = 1; u16 new_id = 1;
for(;;) for(;;)
@ -1351,8 +1342,8 @@ bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
inside a radius around a position inside a radius around a position
*/ */
void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius, void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
core::map<u16, bool> &current_objects, std::set<u16> &current_objects,
core::map<u16, bool> &added_objects) std::set<u16> &added_objects)
{ {
v3f pos_f = intToFloat(pos, BS); v3f pos_f = intToFloat(pos, BS);
f32 radius_f = radius * 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. - discard objects that are found in current_objects.
- add remaining objects to added_objects - add remaining objects to added_objects
*/ */
for(core::map<u16, ServerActiveObject*>::Iterator for(std::map<u16, ServerActiveObject*>::iterator
i = m_active_objects.getIterator(); i = m_active_objects.begin();
i.atEnd()==false; i++) i != m_active_objects.end(); ++i)
{ {
u16 id = i.getNode()->getKey(); u16 id = i->first;
// Get object // Get object
ServerActiveObject *object = i.getNode()->getValue(); ServerActiveObject *object = i->second;
if(object == NULL) if(object == NULL)
continue; continue;
// Discard if removed // Discard if removed
@ -1382,12 +1373,12 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
continue; continue;
} }
// Discard if already on current_objects // Discard if already on current_objects
core::map<u16, bool>::Node *n; std::set<u16>::iterator n;
n = current_objects.find(id); n = current_objects.find(id);
if(n != NULL) if(n != current_objects.end())
continue; continue;
// Add to added_objects // 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 inside a radius around a position
*/ */
void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius, void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
core::map<u16, bool> &current_objects, std::set<u16> &current_objects,
core::map<u16, bool> &removed_objects) std::set<u16> &removed_objects)
{ {
v3f pos_f = intToFloat(pos, BS); v3f pos_f = intToFloat(pos, BS);
f32 radius_f = radius * BS; f32 radius_f = radius * BS;
@ -1409,23 +1400,23 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
- object has m_removed=true, or - object has m_removed=true, or
- object is too far away - object is too far away
*/ */
for(core::map<u16, bool>::Iterator for(std::set<u16>::iterator
i = current_objects.getIterator(); i = current_objects.begin();
i.atEnd()==false; i++) i != current_objects.end(); ++i)
{ {
u16 id = i.getNode()->getKey(); u16 id = *i;
ServerActiveObject *object = getActiveObject(id); ServerActiveObject *object = getActiveObject(id);
if(object == NULL){ if(object == NULL){
infostream<<"ServerEnvironment::getRemovedActiveObjects():" infostream<<"ServerEnvironment::getRemovedActiveObjects():"
<<" object in current_objects is NULL"<<std::endl; <<" object in current_objects is NULL"<<std::endl;
removed_objects.insert(id, false); removed_objects.insert(id);
continue; continue;
} }
if(object->m_removed) if(object->m_removed)
{ {
removed_objects.insert(id, false); removed_objects.insert(id);
continue; continue;
} }
@ -1437,7 +1428,7 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
if(distance_f >= radius_f) if(distance_f >= radius_f)
{ {
removed_objects.insert(id, false); removed_objects.insert(id);
continue; continue;
} }
@ -1447,7 +1438,7 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
ActiveObjectMessage ServerEnvironment::getActiveObjectMessage() ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
{ {
if(m_active_object_messages.size() == 0) if(m_active_object_messages.empty())
return ActiveObjectMessage(0); return ActiveObjectMessage(0);
return m_active_object_messages.pop_front(); return m_active_object_messages.pop_front();
@ -1488,7 +1479,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
/*infostream<<"ServerEnvironment::addActiveObjectRaw(): " /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
<<"added (id="<<object->getId()<<")"<<std::endl;*/ <<"added (id="<<object->getId()<<")"<<std::endl;*/
m_active_objects.insert(object->getId(), object); m_active_objects[object->getId()] = object;
verbosestream<<"ServerEnvironment::addActiveObjectRaw(): " verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
<<"Added id="<<object->getId()<<"; there are now " <<"Added id="<<object->getId()<<"; there are now "
@ -1512,7 +1503,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos); MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
if(block) 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_exists = true;
object->m_static_block = blockpos; object->m_static_block = blockpos;
@ -1536,13 +1527,13 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
*/ */
void ServerEnvironment::removeRemovedObjects() void ServerEnvironment::removeRemovedObjects()
{ {
core::list<u16> objects_to_remove; std::list<u16> objects_to_remove;
for(core::map<u16, ServerActiveObject*>::Iterator for(std::map<u16, ServerActiveObject*>::iterator
i = m_active_objects.getIterator(); i = m_active_objects.begin();
i.atEnd()==false; i++) i != m_active_objects.end(); ++i)
{ {
u16 id = i.getNode()->getKey(); u16 id = i->first;
ServerActiveObject* obj = i.getNode()->getValue(); ServerActiveObject* obj = i->second;
// This shouldn't happen but check it // This shouldn't happen but check it
if(obj == NULL) if(obj == NULL)
{ {
@ -1593,10 +1584,10 @@ void ServerEnvironment::removeRemovedObjects()
objects_to_remove.push_back(id); objects_to_remove.push_back(id);
} }
// Remove references from m_active_objects // Remove references from m_active_objects
for(core::list<u16>::Iterator i = objects_to_remove.begin(); for(std::list<u16>::iterator i = objects_to_remove.begin();
i != objects_to_remove.end(); i++) 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 // A list for objects that couldn't be converted to active for some
// reason. They will be stored back. // reason. They will be stored back.
core::list<StaticObject> new_stored; std::list<StaticObject> new_stored;
// Loop through stored static objects // 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.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 " /*infostream<<"Server: Creating an active object from "
<<"static data"<<std::endl;*/ <<"static data"<<std::endl;*/
@ -1696,9 +1687,9 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
// Clear stored list // Clear stored list
block->m_static_objects.m_stored.clear(); block->m_static_objects.m_stored.clear();
// Add leftover failed stuff to stored list // Add leftover failed stuff to stored list
for(core::list<StaticObject>::Iterator for(std::list<StaticObject>::iterator
i = new_stored.begin(); i = new_stored.begin();
i != new_stored.end(); i++) i != new_stored.end(); ++i)
{ {
StaticObject &s_obj = *i; StaticObject &s_obj = *i;
block->m_static_objects.m_stored.push_back(s_obj); 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) void ServerEnvironment::deactivateFarObjects(bool force_delete)
{ {
core::list<u16> objects_to_remove; std::list<u16> objects_to_remove;
for(core::map<u16, ServerActiveObject*>::Iterator for(std::map<u16, ServerActiveObject*>::iterator
i = m_active_objects.getIterator(); i = m_active_objects.begin();
i.atEnd()==false; i++) i != m_active_objects.end(); ++i)
{ {
ServerActiveObject* obj = i.getNode()->getValue(); ServerActiveObject* obj = i->second;
assert(obj); assert(obj);
// Do not deactivate if static data creation not allowed // 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) if(!force_delete && obj->m_pending_deactivation)
continue; continue;
u16 id = i.getNode()->getKey(); u16 id = i->first;
v3f objectpos = obj->getBasePosition(); v3f objectpos = obj->getBasePosition();
// The block in which the object resides in // 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); 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); block->m_static_objects.m_active.find(id);
if(n){ if(n != block->m_static_objects.m_active.end()){
StaticObject static_old = n->getValue(); StaticObject static_old = n->second;
float save_movem = obj->getMinimumSavedMovement(); float save_movem = obj->getMinimumSavedMovement();
@ -1840,7 +1831,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
// This shouldn't happen, but happens rarely for some // This shouldn't happen, but happens rarely for some
// unknown reason. Unsuccessful attempts have been made to // unknown reason. Unsuccessful attempts have been made to
// find said reason. // 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" infostream<<"ServerEnv: WARNING: Performing hack #83274"
<<std::endl; <<std::endl;
block->m_static_objects.remove(new_id); block->m_static_objects.remove(new_id);
@ -1900,10 +1891,10 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
} }
// Remove references from m_active_objects // Remove references from m_active_objects
for(core::list<u16>::Iterator i = objects_to_remove.begin(); for(std::list<u16>::iterator i = objects_to_remove.begin();
i != objects_to_remove.end(); i++) 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() ClientEnvironment::~ClientEnvironment()
{ {
// delete active objects // delete active objects
for(core::map<u16, ClientActiveObject*>::Iterator for(std::map<u16, ClientActiveObject*>::iterator
i = m_active_objects.getIterator(); i = m_active_objects.begin();
i.atEnd()==false; i++) i != m_active_objects.end(); ++i)
{ {
delete i.getNode()->getValue(); delete i->second;
} }
for(core::list<ClientSimpleObject*>::Iterator for(std::list<ClientSimpleObject*>::iterator
i = m_simple_objects.begin(); i != m_simple_objects.end(); i++) i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i)
{ {
delete *i; delete *i;
} }
@ -1971,8 +1962,8 @@ void ClientEnvironment::addPlayer(Player *player)
LocalPlayer * ClientEnvironment::getLocalPlayer() LocalPlayer * ClientEnvironment::getLocalPlayer()
{ {
for(core::list<Player*>::Iterator i = m_players.begin(); for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
if(player->isLocal()) if(player->isLocal())
@ -1996,7 +1987,7 @@ void ClientEnvironment::step(float dtime)
LocalPlayer *lplayer = getLocalPlayer(); LocalPlayer *lplayer = getLocalPlayer();
assert(lplayer); assert(lplayer);
// collision info queue // collision info queue
core::list<CollisionInfo> player_collisions; std::list<CollisionInfo> player_collisions;
/* /*
Get the speed the player is going Get the speed the player is going
@ -2105,7 +2096,7 @@ void ClientEnvironment::step(float dtime)
Move the lplayer. Move the lplayer.
This also does collision detection. This also does collision detection.
*/ */
lplayer->move(dtime_part, *m_map, position_max_increment, lplayer->move(dtime_part, this, position_max_increment,
&player_collisions); &player_collisions);
} }
} }
@ -2113,9 +2104,9 @@ void ClientEnvironment::step(float dtime)
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl; //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
for(core::list<CollisionInfo>::Iterator for(std::list<CollisionInfo>::iterator
i = player_collisions.begin(); i = player_collisions.begin();
i != player_collisions.end(); i++) i != player_collisions.end(); ++i)
{ {
CollisionInfo &info = *i; CollisionInfo &info = *i;
v3f speed_diff = info.new_speed - info.old_speed;; 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 Stuff that can be done in an arbitarily large dtime
*/ */
for(core::list<Player*>::Iterator i = m_players.begin(); for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); i++) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
v3f playerpos = player->getPosition(); 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); bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
for(core::map<u16, ClientActiveObject*>::Iterator for(std::map<u16, ClientActiveObject*>::iterator
i = m_active_objects.getIterator(); i = m_active_objects.begin();
i.atEnd()==false; i++) i != m_active_objects.end(); ++i)
{ {
ClientActiveObject* obj = i.getNode()->getValue(); ClientActiveObject* obj = i->second;
// Step object // Step object
obj->step(dtime, this); obj->step(dtime, this);
@ -2242,12 +2233,12 @@ void ClientEnvironment::step(float dtime)
/* /*
Step and handle simple objects 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();) i = m_simple_objects.begin(); i != m_simple_objects.end();)
{ {
ClientSimpleObject *simple = *i; ClientSimpleObject *simple = *i;
core::list<ClientSimpleObject*>::Iterator cur = i; std::list<ClientSimpleObject*>::iterator cur = i;
i++; ++i;
simple->step(dtime); simple->step(dtime);
if(simple->m_to_be_removed){ if(simple->m_to_be_removed){
delete simple; delete simple;
@ -2263,31 +2254,24 @@ void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
ClientActiveObject* ClientEnvironment::getActiveObject(u16 id) ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
{ {
core::map<u16, ClientActiveObject*>::Node *n; std::map<u16, ClientActiveObject*>::iterator n;
n = m_active_objects.find(id); n = m_active_objects.find(id);
if(n == NULL) if(n == m_active_objects.end())
return NULL; return NULL;
return n->getValue(); return n->second;
} }
bool isFreeClientActiveObjectId(u16 id, bool isFreeClientActiveObjectId(u16 id,
core::map<u16, ClientActiveObject*> &objects) std::map<u16, ClientActiveObject*> &objects)
{ {
if(id == 0) if(id == 0)
return false; return false;
for(core::map<u16, ClientActiveObject*>::Iterator return objects.find(id) == objects.end();
i = objects.getIterator();
i.atEnd()==false; i++)
{
if(i.getNode()->getKey() == id)
return false;
}
return true;
} }
u16 getFreeClientActiveObjectId( u16 getFreeClientActiveObjectId(
core::map<u16, ClientActiveObject*> &objects) std::map<u16, ClientActiveObject*> &objects)
{ {
u16 new_id = 1; u16 new_id = 1;
for(;;) for(;;)
@ -2326,7 +2310,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
} }
infostream<<"ClientEnvironment::addActiveObject(): " infostream<<"ClientEnvironment::addActiveObject(): "
<<"added (id="<<object->getId()<<")"<<std::endl; <<"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); object->addToScene(m_smgr, m_texturesource, m_irr);
{ // Update lighting immediately { // Update lighting immediately
u8 light = 0; u8 light = 0;
@ -2389,7 +2373,7 @@ void ClientEnvironment::removeActiveObject(u16 id)
} }
obj->removeFromScene(true); obj->removeFromScene(true);
delete obj; delete obj;
m_active_objects.remove(id); m_active_objects.erase(id);
} }
void ClientEnvironment::processActiveObjectMessage(u16 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, void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
core::array<DistanceSortedActiveObject> &dest) std::vector<DistanceSortedActiveObject> &dest)
{ {
for(core::map<u16, ClientActiveObject*>::Iterator for(std::map<u16, ClientActiveObject*>::iterator
i = m_active_objects.getIterator(); i = m_active_objects.begin();
i.atEnd()==false; i++) i != m_active_objects.end(); ++i)
{ {
ClientActiveObject* obj = i.getNode()->getValue(); ClientActiveObject* obj = i->second;
f32 d = (obj->getPosition() - origin).getLength(); f32 d = (obj->getPosition() - origin).getLength();
@ -2466,7 +2450,7 @@ void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
ClientEnvEvent ClientEnvironment::getClientEvent() ClientEnvEvent ClientEnvironment::getClientEvent()
{ {
if(m_client_event_queue.size() == 0) if(m_client_event_queue.empty())
{ {
ClientEnvEvent event; ClientEnvEvent event;
event.type = CEE_NONE; event.type = CEE_NONE;

@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include <set> #include <set>
#include <list>
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes_extrabloated.h"
#include "player.h" #include "player.h"
#include <ostream> #include <ostream>
@ -73,8 +74,8 @@ public:
Player * getPlayer(const char *name); Player * getPlayer(const char *name);
Player * getRandomConnectedPlayer(); Player * getRandomConnectedPlayer();
Player * getNearestConnectedPlayer(v3f pos); Player * getNearestConnectedPlayer(v3f pos);
core::list<Player*> getPlayers(); std::list<Player*> getPlayers();
core::list<Player*> getPlayers(bool ignore_disconnected); std::list<Player*> getPlayers(bool ignore_disconnected);
void printPlayers(std::ostream &o); void printPlayers(std::ostream &o);
u32 getDayNightRatio(); u32 getDayNightRatio();
@ -102,7 +103,7 @@ public:
protected: protected:
// peer_ids in here should be unique, except that there may be many 0s // 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 // Time of day in milli-hours (0-23999); determines day and night
u32 m_time_of_day; u32 m_time_of_day;
// Time of day in 0...1 // Time of day in 0...1
@ -156,20 +157,20 @@ struct ABMWithState
class ActiveBlockList class ActiveBlockList
{ {
public: public:
void update(core::list<v3s16> &active_positions, void update(std::list<v3s16> &active_positions,
s16 radius, s16 radius,
core::map<v3s16, bool> &blocks_removed, std::set<v3s16> &blocks_removed,
core::map<v3s16, bool> &blocks_added); std::set<v3s16> &blocks_added);
bool contains(v3s16 p){ bool contains(v3s16 p){
return (m_list.find(p) != NULL); return (m_list.find(p) != m_list.end());
} }
void clear(){ void clear(){
m_list.clear(); m_list.clear();
} }
core::map<v3s16, bool> m_list; std::set<v3s16> m_list;
private: private:
}; };
@ -249,16 +250,16 @@ public:
inside a radius around a position inside a radius around a position
*/ */
void getAddedActiveObjects(v3s16 pos, s16 radius, void getAddedActiveObjects(v3s16 pos, s16 radius,
core::map<u16, bool> &current_objects, std::set<u16> &current_objects,
core::map<u16, bool> &added_objects); std::set<u16> &added_objects);
/* /*
Find out what new objects have been removed from Find out what new objects have been removed from
inside a radius around a position inside a radius around a position
*/ */
void getRemovedActiveObjects(v3s16 pos, s16 radius, void getRemovedActiveObjects(v3s16 pos, s16 radius,
core::map<u16, bool> &current_objects, std::set<u16> &current_objects,
core::map<u16, bool> &removed_objects); std::set<u16> &removed_objects);
/* /*
Get the next message emitted by some active object. Get the next message emitted by some active object.
@ -350,7 +351,7 @@ private:
// Background block emerger (the server, in practice) // Background block emerger (the server, in practice)
IBackgroundBlockEmerger *m_emerger; IBackgroundBlockEmerger *m_emerger;
// Active object list // Active object list
core::map<u16, ServerActiveObject*> m_active_objects; std::map<u16, ServerActiveObject*> m_active_objects;
// Outgoing network message buffer for active objects // Outgoing network message buffer for active objects
Queue<ActiveObjectMessage> m_active_object_messages; Queue<ActiveObjectMessage> m_active_object_messages;
// Some timers // Some timers
@ -368,7 +369,7 @@ private:
u32 m_game_time; u32 m_game_time;
// A helper variable for incrementing the latter // A helper variable for incrementing the latter
float m_game_time_fraction_counter; 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 // An interval for generally sending object positions and stuff
float m_recommended_send_interval; float m_recommended_send_interval;
}; };
@ -463,7 +464,7 @@ public:
// Get all nearby objects // Get all nearby objects
void getActiveObjects(v3f origin, f32 max_d, 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. // Get event from queue. CEE_NONE is returned if queue is empty.
ClientEnvEvent getClientEvent(); ClientEnvEvent getClientEvent();
@ -476,8 +477,8 @@ private:
ITextureSource *m_texturesource; ITextureSource *m_texturesource;
IGameDef *m_gamedef; IGameDef *m_gamedef;
IrrlichtDevice *m_irr; IrrlichtDevice *m_irr;
core::map<u16, ClientActiveObject*> m_active_objects; std::map<u16, ClientActiveObject*> m_active_objects;
core::list<ClientSimpleObject*> m_simple_objects; std::list<ClientSimpleObject*> m_simple_objects;
Queue<ClientEnvEvent> m_client_event_queue; Queue<ClientEnvEvent> m_client_event_queue;
IntervalLimiter m_active_object_light_update_interval; IntervalLimiter m_active_object_light_update_interval;
IntervalLimiter m_lava_hurt_interval; IntervalLimiter m_lava_hurt_interval;

@ -112,13 +112,13 @@ struct HeightPoint
float have_sand; float have_sand;
float tree_amount; float tree_amount;
}; };
core::map<v2s16, HeightPoint> g_heights; std::map<v2s16, HeightPoint> g_heights;
HeightPoint ground_height(u64 seed, v2s16 p2d) HeightPoint ground_height(u64 seed, v2s16 p2d)
{ {
core::map<v2s16, HeightPoint>::Node *n = g_heights.find(p2d); std::map<v2s16, HeightPoint>::iterator n = g_heights.find(p2d);
if(n) if(n != g_heights.end())
return n->getValue(); return n->second;
HeightPoint hp; HeightPoint hp;
s16 level = Mapgen::find_ground_level_from_noise(seed, p2d, 3); s16 level = Mapgen::find_ground_level_from_noise(seed, p2d, 3);
hp.gh = (level-4)*BS; hp.gh = (level-4)*BS;

@ -2186,6 +2186,47 @@ void the_game(
{ {
update_wielded_item_trigger = true; 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 Handle digging
*/ */
@ -2415,7 +2451,8 @@ void the_game(
const ContentFeatures &features = const ContentFeatures &features =
client.getNodeDefManager()->get(n); client.getNodeDefManager()->get(n);
addPunchingParticles 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 = const ContentFeatures &features =
client.getNodeDefManager()->get(wasnode); client.getNodeDefManager()->get(wasnode);
addDiggingParticles addDiggingParticles
(gamedef, smgr, player, nodepos, features.tiles); (gamedef, smgr, player, client.getEnv(),
nodepos, features.tiles);
} }
dig_time = 0; dig_time = 0;
@ -2574,6 +2612,9 @@ void the_game(
<<") - Position not loaded"<<std::endl; <<") - Position not loaded"<<std::endl;
} }
}while(0); }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()); allparticles_step(dtime, client.getEnv());
allparticlespawners_step(dtime, client.getEnv());
/* /*
Fog Fog
@ -3220,6 +3262,7 @@ void the_game(
clouds->drop(); clouds->drop();
if(gui_chat_console) if(gui_chat_console)
gui_chat_console->drop(); gui_chat_console->drop();
clear_particles ();
/* /*
Draw a "shutting down" screen, which will be shown while the map Draw a "shutting down" screen, which will be shown while the map

@ -23,17 +23,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes_extrabloated.h"
#include <string> #include <string>
#include "keycode.h" #include "keycode.h"
#include <list>
class KeyList : protected core::list<KeyPress> class KeyList : protected std::list<KeyPress>
{ {
typedef core::list<KeyPress> super; typedef std::list<KeyPress> super;
typedef super::Iterator Iterator; typedef super::iterator iterator;
typedef super::ConstIterator ConstIterator; typedef super::const_iterator const_iterator;
virtual ConstIterator find(const KeyPress &key) const virtual const_iterator find(const KeyPress &key) const
{ {
ConstIterator f(begin()); const_iterator f(begin());
ConstIterator e(end()); const_iterator e(end());
while (f!=e) { while (f!=e) {
if (*f == key) if (*f == key)
return f; return f;
@ -42,10 +43,10 @@ class KeyList : protected core::list<KeyPress>
return e; return e;
} }
virtual Iterator find(const KeyPress &key) virtual iterator find(const KeyPress &key)
{ {
Iterator f(begin()); iterator f(begin());
Iterator e(end()); iterator e(end());
while (f!=e) { while (f!=e) {
if (*f == key) if (*f == key)
return f; return f;
@ -65,14 +66,14 @@ public:
void unset(const KeyPress &key) void unset(const KeyPress &key)
{ {
Iterator p(find(key)); iterator p(find(key));
if (p != end()) if (p != end())
erase(p); erase(p);
} }
void toggle(const KeyPress &key) void toggle(const KeyPress &key)
{ {
Iterator p(this->find(key)); iterator p(this->find(key));
if (p != end()) if (p != end())
erase(p); erase(p);
else else

@ -31,7 +31,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Normal build: main.cpp Normal build: main.cpp
Server build: servermain.cpp Server build: servermain.cpp
*/ */
enum TimePrecision {
PRECISION_SECONDS,
PRECISION_MILLI,
PRECISION_MICRO,
PRECISION_NANO
};
extern u32 getTimeMs(); extern u32 getTimeMs();
extern u32 getTime(TimePrecision prec);
/* /*
Timestamp stuff Timestamp stuff

@ -535,7 +535,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
{ {
// Tab or Shift-Tab pressed // Tab or Shift-Tab pressed
// Nick completion // Nick completion
core::list<std::wstring> names = m_client->getConnectedPlayerNames(); std::list<std::wstring> names = m_client->getConnectedPlayerNames();
bool backwards = event.KeyInput.Shift; bool backwards = event.KeyInput.Shift;
m_chat_backend->getPrompt().nickCompletion(names, backwards); m_chat_backend->getPrompt().nickCompletion(names, backwards);
return true; return true;

@ -207,18 +207,18 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
Strfnd f(m_formspec_string); Strfnd f(m_formspec_string);
while(f.atend() == false) while(f.atend() == false)
{ {
std::string type = trim(f.next("[")); std::string type = trim(f.next_esc("["));
if(type == "invsize" || type == "size") if(type == "invsize" || type == "size")
{ {
v2f invsize; v2f invsize;
invsize.X = stof(f.next(",")); invsize.X = stof(f.next_esc(","));
if(type == "size") if(type == "size")
{ {
invsize.Y = stof(f.next("]")); invsize.Y = stof(f.next_esc("]"));
} }
else{ else{
invsize.Y = stof(f.next(";")); invsize.Y = stof(f.next_esc(";"));
f.next("]"); f.next_esc("]");
} }
infostream<<"Form size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl; infostream<<"Form size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
@ -242,24 +242,24 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
} }
else if(type == "list") else if(type == "list")
{ {
std::string name = f.next(";"); std::string name = f.next_esc(";");
InventoryLocation loc; InventoryLocation loc;
if(name == "context" || name == "current_name") if(name == "context" || name == "current_name")
loc = m_current_inventory_location; loc = m_current_inventory_location;
else else
loc.deSerialize(name); loc.deSerialize(name);
std::string listname = f.next(";"); std::string listname = f.next_esc(";");
v2s32 pos = basepos; v2s32 pos = basepos;
pos.X += stof(f.next(",")) * (float)spacing.X; pos.X += stof(f.next_esc(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y; pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom; v2s32 geom;
geom.X = stoi(f.next(",")); geom.X = stoi(f.next_esc(","));
geom.Y = stoi(f.next(";")); geom.Y = stoi(f.next_esc(";"));
infostream<<"list inv="<<name<<", listname="<<listname infostream<<"list inv="<<name<<", listname="<<listname
<<", pos=("<<pos.X<<","<<pos.Y<<")" <<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")" <<", geom=("<<geom.X<<","<<geom.Y<<")"
<<std::endl; <<std::endl;
std::string start_i_s = f.next("]"); std::string start_i_s = f.next_esc("]");
s32 start_i = 0; s32 start_i = 0;
if(start_i_s != "") if(start_i_s != "")
start_i = stoi(start_i_s); start_i = stoi(start_i_s);
@ -270,12 +270,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "image") else if(type == "image")
{ {
v2s32 pos = basepos; v2s32 pos = basepos;
pos.X += stof(f.next(",")) * (float)spacing.X; pos.X += stof(f.next_esc(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y; pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom; v2s32 geom;
geom.X = stof(f.next(",")) * (float)imgsize.X; geom.X = stof(f.next_esc(",")) * (float)imgsize.X;
geom.Y = stof(f.next(";")) * (float)imgsize.Y; geom.Y = stof(f.next_esc(";")) * (float)imgsize.Y;
std::string name = f.next("]"); std::string name = f.next_esc("]");
infostream<<"image name="<<name infostream<<"image name="<<name
<<", pos=("<<pos.X<<","<<pos.Y<<")" <<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")" <<", geom=("<<geom.X<<","<<geom.Y<<")"
@ -287,12 +287,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "item_image") else if(type == "item_image")
{ {
v2s32 pos = basepos; v2s32 pos = basepos;
pos.X += stof(f.next(",")) * (float)spacing.X; pos.X += stof(f.next_esc(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y; pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom; v2s32 geom;
geom.X = stof(f.next(",")) * (float)imgsize.X; geom.X = stof(f.next_esc(",")) * (float)imgsize.X;
geom.Y = stof(f.next(";")) * (float)imgsize.Y; geom.Y = stof(f.next_esc(";")) * (float)imgsize.Y;
std::string name = f.next("]"); std::string name = f.next_esc("]");
infostream<<"item name="<<name infostream<<"item name="<<name
<<", pos=("<<pos.X<<","<<pos.Y<<")" <<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")" <<", geom=("<<geom.X<<","<<geom.Y<<")"
@ -304,12 +304,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "background") else if(type == "background")
{ {
v2s32 pos = basepos; v2s32 pos = basepos;
pos.X += stof(f.next(",")) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2; pos.X += stof(f.next_esc(",")) * (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.Y += stof(f.next_esc(";")) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2;
v2s32 geom; v2s32 geom;
geom.X = stof(f.next(",")) * (float)spacing.X; geom.X = stof(f.next_esc(",")) * (float)spacing.X;
geom.Y = stof(f.next(";")) * (float)spacing.Y; geom.Y = stof(f.next_esc(";")) * (float)spacing.Y;
std::string name = f.next("]"); std::string name = f.next_esc("]");
infostream<<"image name="<<name infostream<<"image name="<<name
<<", pos=("<<pos.X<<","<<pos.Y<<")" <<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")" <<", geom=("<<geom.X<<","<<geom.Y<<")"
@ -320,8 +320,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
} }
else if(type == "field" || type == "textarea") else if(type == "field" || type == "textarea")
{ {
std::string fname = f.next(";"); std::string fname = f.next_esc(";");
std::string flabel = f.next(";"); std::string flabel = f.next_esc(";");
if(fname.find(",") == std::string::npos && flabel.find(",") == std::string::npos) if(fname.find(",") == std::string::npos && flabel.find(",") == std::string::npos)
{ {
@ -372,14 +372,14 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
fname = f.next(";"); fname = f.next_esc(";");
flabel = f.next(";"); flabel = f.next_esc(";");
if(bp_set != 2) if(bp_set != 2)
errorstream<<"WARNING: invalid use of positioned "<<type<<" without a size[] element"<<std::endl; 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; std::string fdefault;
// fdefault may contain a variable reference, which // fdefault may contain a variable reference, which
@ -389,6 +389,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else else
fdefault = odefault; fdefault = odefault;
fdefault = unescape_string(fdefault);
flabel = unescape_string(flabel);
FieldSpec spec = FieldSpec( FieldSpec spec = FieldSpec(
narrow_to_wide(fname.c_str()), narrow_to_wide(fname.c_str()),
narrow_to_wide(flabel.c_str()), narrow_to_wide(flabel.c_str()),
@ -434,15 +437,17 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "label") else if(type == "label")
{ {
v2s32 pos = padding; v2s32 pos = padding;
pos.X += stof(f.next(",")) * (float)spacing.X; pos.X += stof(f.next_esc(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y; 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)); 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) if(bp_set != 2)
errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl; errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl;
flabel = unescape_string(flabel);
FieldSpec spec = FieldSpec( FieldSpec spec = FieldSpec(
narrow_to_wide(""), narrow_to_wide(""),
narrow_to_wide(flabel.c_str()), narrow_to_wide(flabel.c_str()),
@ -455,19 +460,21 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "button" || type == "button_exit") else if(type == "button" || type == "button_exit")
{ {
v2s32 pos = padding; v2s32 pos = padding;
pos.X += stof(f.next(",")) * (float)spacing.X; pos.X += stof(f.next_esc(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y; pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom; v2s32 geom;
geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X); geom.X = (stof(f.next_esc(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
pos.Y += (stof(f.next(";")) * (float)imgsize.Y)/2; 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); rect = core::rect<s32>(pos.X, pos.Y-15, pos.X+geom.X, pos.Y+15);
std::string fname = f.next(";"); std::string fname = f.next_esc(";");
std::string flabel = f.next("]"); std::string flabel = f.next_esc("]");
if(bp_set != 2) if(bp_set != 2)
errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl; errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
flabel = unescape_string(flabel);
FieldSpec spec = FieldSpec( FieldSpec spec = FieldSpec(
narrow_to_wide(fname.c_str()), narrow_to_wide(fname.c_str()),
narrow_to_wide(flabel.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") else if(type == "image_button" || type == "image_button_exit")
{ {
v2s32 pos = padding; v2s32 pos = padding;
pos.X += stof(f.next(",")) * (float)spacing.X; pos.X += stof(f.next_esc(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y; pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom; v2s32 geom;
geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X); geom.X = (stof(f.next_esc(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y); 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); rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
std::string fimage = f.next(";"); std::string fimage = f.next_esc(";");
std::string fname = f.next(";"); std::string fname = f.next_esc(";");
std::string flabel = f.next("]"); std::string flabel = f.next_esc("]");
if(bp_set != 2) if(bp_set != 2)
errorstream<<"WARNING: invalid use of image_button without a size[] element"<<std::endl; errorstream<<"WARNING: invalid use of image_button without a size[] element"<<std::endl;
flabel = unescape_string(flabel);
FieldSpec spec = FieldSpec( FieldSpec spec = FieldSpec(
narrow_to_wide(fname.c_str()), narrow_to_wide(fname.c_str()),
narrow_to_wide(flabel.c_str()), narrow_to_wide(flabel.c_str()),
@ -519,15 +528,15 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else if(type == "item_image_button") else if(type == "item_image_button")
{ {
v2s32 pos = padding; v2s32 pos = padding;
pos.X += stof(f.next(",")) * (float)spacing.X; pos.X += stof(f.next_esc(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y; pos.Y += stof(f.next_esc(";")) * (float)spacing.Y;
v2s32 geom; v2s32 geom;
geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X); geom.X = (stof(f.next_esc(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y); 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); rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
std::string fimage = f.next(";"); std::string fimage = f.next_esc(";");
std::string fname = f.next(";"); std::string fname = f.next_esc(";");
std::string flabel = f.next("]"); std::string flabel = f.next_esc("]");
if(bp_set != 2) if(bp_set != 2)
errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl; errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl;
IItemDefManager *idef = m_gamedef->idef(); IItemDefManager *idef = m_gamedef->idef();
@ -535,6 +544,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
item.deSerialize(fimage, idef); item.deSerialize(fimage, idef);
video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef); video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
std::string tooltip = item.getDefinition(idef).description; std::string tooltip = item.getDefinition(idef).description;
flabel = unescape_string(flabel);
FieldSpec spec = FieldSpec( FieldSpec spec = FieldSpec(
narrow_to_wide(fname.c_str()), narrow_to_wide(fname.c_str()),
narrow_to_wide(flabel.c_str()), narrow_to_wide(flabel.c_str()),
@ -556,7 +566,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
else else
{ {
// Ignore others // Ignore others
std::string ts = f.next("]"); std::string ts = f.next_esc("]");
infostream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\"" infostream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\""
<<std::endl; <<std::endl;
} }

@ -209,11 +209,11 @@ protected:
IFormSource *m_form_src; IFormSource *m_form_src;
TextDest *m_text_dst; TextDest *m_text_dst;
core::array<ListDrawSpec> m_inventorylists; std::vector<ListDrawSpec> m_inventorylists;
core::array<ImageDrawSpec> m_backgrounds; std::vector<ImageDrawSpec> m_backgrounds;
core::array<ImageDrawSpec> m_images; std::vector<ImageDrawSpec> m_images;
core::array<ImageDrawSpec> m_itemimages; std::vector<ImageDrawSpec> m_itemimages;
core::array<FieldSpec> m_fields; std::vector<FieldSpec> m_fields;
ItemSpec *m_selected_item; ItemSpec *m_selected_item;
u32 m_selected_amount; u32 m_selected_amount;

@ -42,6 +42,43 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h" #include "util/string.h"
#include "subgame.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 struct CreateWorldDestMainMenu : public CreateWorldDest
{ {
CreateWorldDestMainMenu(GUIMainMenu *menu): CreateWorldDestMainMenu(GUIMainMenu *menu):
@ -106,6 +143,7 @@ enum
GUI_ID_SHADERS_CB, GUI_ID_SHADERS_CB,
GUI_ID_PRELOAD_ITEM_VISUALS_CB, GUI_ID_PRELOAD_ITEM_VISUALS_CB,
GUI_ID_ENABLE_PARTICLES_CB, GUI_ID_ENABLE_PARTICLES_CB,
GUI_ID_LIQUID_FINITE_CB,
GUI_ID_DAMAGE_CB, GUI_ID_DAMAGE_CB,
GUI_ID_CREATIVE_CB, GUI_ID_CREATIVE_CB,
GUI_ID_PUBLIC_CB, GUI_ID_PUBLIC_CB,
@ -119,6 +157,7 @@ enum
GUI_ID_SERVERLIST, GUI_ID_SERVERLIST,
GUI_ID_SERVERLIST_TOGGLE, GUI_ID_SERVERLIST_TOGGLE,
GUI_ID_SERVERLIST_DELETE, GUI_ID_SERVERLIST_DELETE,
GUI_ID_SERVERLIST_TITLE,
}; };
enum enum
@ -209,7 +248,6 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
changeCtype(""); changeCtype("");
// Version // Version
//if(m_data->selected_tab != TAB_CREDITS)
{ {
core::rect<s32> rect(0, 0, size.X, 40); core::rect<s32> rect(0, 0, size.X, 40);
rect += v2s32(4, 0); rect += v2s32(4, 0);
@ -219,7 +257,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
} }
//v2s32 center(size.X/2, size.Y/2); //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_topleft_client = c800 + v2s32(90, 70+50+30);
m_size_client = v2s32(620, 270); 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); m_topleft_server = m_topleft_client + v2s32(0, m_size_client.Y+20);
// Tabs // Tabs
#if 1
{ {
core::rect<s32> rect(0, 0, m_size_client.X, 30); core::rect<s32> rect(0, 0, m_size_client.X, 30);
rect += m_topleft_client + v2s32(0, -30); rect += m_topleft_client + v2s32(0, -30);
@ -250,7 +287,6 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
e->addTab(wgettext("Credits")); e->addTab(wgettext("Credits"));
e->setActiveTab(m_data->selected_tab); e->setActiveTab(m_data->selected_tab);
} }
#endif
if(m_data->selected_tab == TAB_SINGLEPLAYER) 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); core::rect<s32> rect(0, 0, 10, m_size_client.Y);
rect += m_topleft_client + v2s32(15, 0); rect += m_topleft_client + v2s32(15, 0);
//const wchar_t *text = L"H\nY\nB\nR\nI\nD"; //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 = gui::IGUIStaticText *t =
Environment->addStaticText(text, rect, false, true, this, -1); Environment->addStaticText(text, rect, false, true, this, -1);
t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER); t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
@ -392,13 +428,38 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
changeCtype(""); changeCtype("");
// Server List // Server List
{ {
core::rect<s32> rect(0, 0, 390, 160); core::rect<s32> rect(0, 0, 390, 140);
rect += m_topleft_client + v2s32(50, 10); rect += m_topleft_client + v2s32(50, 30);
gui::IGUIListBox *e = Environment->addListBox(rect, this, gui::IGUIListBox *e = Environment->addListBox(rect, this,
GUI_ID_SERVERLIST); GUI_ID_SERVERLIST);
e->setDrawBackground(true); 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(); 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(); updateGuiServerList();
e->setSelected(0); e->setSelected(0);
} }
@ -435,7 +496,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_TOGGLE, gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_TOGGLE,
wgettext("Show Public")); wgettext("Show Public"));
e->setIsPushButton(true); e->setIsPushButton(true);
if (m_data->serverlist_show_available) if (m_data->selected_serverlist == SERVERLIST_PUBLIC)
{ {
e->setText(wgettext("Show Favorites")); e->setText(wgettext("Show Favorites"));
e->setPressed(); e->setPressed();
@ -448,7 +509,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
rect += m_topleft_client + v2s32(50+260+10, 180); rect += m_topleft_client + v2s32(50+260+10, 180);
gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_DELETE, gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_DELETE,
wgettext("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); e->setVisible(false);
} }
// Start game button // Start game button
@ -691,6 +752,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
GUI_ID_ENABLE_PARTICLES_CB, wgettext("Enable Particles")); 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 // Key change button
{ {
core::rect<s32> rect(0, 0, 120, 30); core::rect<s32> rect(0, 0, 120, 30);
@ -706,7 +774,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
{ {
// CREDITS // 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); rect += m_topleft_client + v2s32(15, 0);
const wchar_t *text = L"C\nR\nE\nD\nI\nT\nS"; const wchar_t *text = L"C\nR\nE\nD\nI\nT\nS";
gui::IGUIStaticText *t = gui::IGUIStaticText *t =
@ -714,15 +782,34 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER); t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
} }
{ {
core::rect<s32> rect(0, 0, 454, 250); core::rect<s32> rect(0, 0, 130, 70);
rect += m_topleft_client + v2s32(110, 50+35); rect += m_topleft_client + v2s32(35, 160);
Environment->addStaticText(narrow_to_wide( Environment->addStaticText(
"Minetest " VERSION_STRING "\n" L"Minetest " LSTRING(VERSION_STRING) L"\nhttp://minetest.net/",
"http://minetest.net/\n" rect, false, true, this, -1);
"\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." video::SColor yellow(255, 255, 255, 0);
).c_str(), rect, false, true, this, -1); 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); driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
} }
video::ITexture *logotexture = video::ITexture *logotexture =
driver->getTexture(getTexturePath("menulogo.png").c_str()); driver->getTexture(getTexturePath("logo.png").c_str());
if(logotexture) if(logotexture)
{ {
v2s32 logosize(logotexture->getOriginalSize().Width, v2s32 logosize(logotexture->getOriginalSize().Width,
logotexture->getOriginalSize().Height); logotexture->getOriginalSize().Height);
logosize *= 2;
core::rect<s32> rect(0,0,logosize.X,logosize.Y); core::rect<s32> rect(0,0,logosize.X,logosize.Y);
rect += AbsoluteRect.UpperLeftCorner + m_topleft_client; rect += AbsoluteRect.UpperLeftCorner + m_topleft_client;
rect += v2s32(130, 50); rect += v2s32(50, 60);
driver->draw2DImage(logotexture, rect, driver->draw2DImage(logotexture, rect,
core::rect<s32>(core::position2d<s32>(0,0), core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(logotexture->getSize())), core::dimension2di(logotexture->getSize())),
@ -918,6 +1005,12 @@ void GUIMainMenu::readInput(MainMenuData *dst)
dst->enable_particles = ((gui::IGUICheckBox*)e)->isChecked(); dst->enable_particles = ((gui::IGUICheckBox*)e)->isChecked();
} }
{
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); gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX);
if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX) if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX)
@ -1083,25 +1176,28 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
gui::IGUIElement *togglebutton = getElementFromId(GUI_ID_SERVERLIST_TOGGLE); gui::IGUIElement *togglebutton = getElementFromId(GUI_ID_SERVERLIST_TOGGLE);
gui::IGUIElement *deletebutton = getElementFromId(GUI_ID_SERVERLIST_DELETE); gui::IGUIElement *deletebutton = getElementFromId(GUI_ID_SERVERLIST_DELETE);
gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST); 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(); m_data->servers = ServerList::getLocal();
togglebutton->setText(wgettext("Show Public")); togglebutton->setText(wgettext("Show Public"));
title->setText(wgettext("Favorites:"));
deletebutton->setVisible(true); deletebutton->setVisible(true);
updateGuiServerList(); updateGuiServerList();
serverlist->setSelected(0); serverlist->setSelected(0);
m_data->selected_serverlist = SERVERLIST_FAVORITES;
} }
else // switch to online list else // switch to online list
{ {
m_data->servers = ServerList::getOnline(); m_data->servers = ServerList::getOnline();
togglebutton->setText(wgettext("Show Favorites")); togglebutton->setText(wgettext("Show Favorites"));
title->setText(wgettext("Public Server List:"));
deletebutton->setVisible(false); deletebutton->setVisible(false);
updateGuiServerList(); updateGuiServerList();
serverlist->setSelected(0); serverlist->setSelected(0);
m_data->selected_serverlist = SERVERLIST_PUBLIC;
} }
serverListOnSelected(); serverListOnSelected();
m_data->serverlist_show_available = !m_data->serverlist_show_available;
} }
#endif #endif
} }

@ -29,6 +29,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class IGameCallback; class IGameCallback;
enum {
SERVERLIST_FAVORITES,
SERVERLIST_PUBLIC,
};
struct MainMenuData struct MainMenuData
{ {
// These are in the native format of the gui elements // These are in the native format of the gui elements
@ -52,6 +57,7 @@ struct MainMenuData
int enable_shaders; int enable_shaders;
bool preload_item_visuals; bool preload_item_visuals;
bool enable_particles; bool enable_particles;
bool liquid_finite;
// Server options // Server options
bool creative_mode; bool creative_mode;
bool enable_damage; bool enable_damage;
@ -63,7 +69,7 @@ struct MainMenuData
std::string create_world_gameid; std::string create_world_gameid;
bool only_refresh; bool only_refresh;
bool serverlist_show_available; // if false show local favorites only int selected_serverlist;
std::vector<WorldSpec> worlds; std::vector<WorldSpec> worlds;
std::vector<SubgameSpec> games; std::vector<SubgameSpec> games;
@ -84,7 +90,7 @@ struct MainMenuData
// Actions // Actions
only_refresh(false), only_refresh(false),
serverlist_show_available(false) selected_serverlist(SERVERLIST_FAVORITES)
{} {}
}; };

@ -903,6 +903,10 @@ void Inventory::deSerialize(std::istream &is)
m_lists.push_back(list); m_lists.push_back(list);
} }
else
{
throw SerializationError("invalid inventory specifier");
}
} }
} }

@ -75,6 +75,7 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
} }
groups = def.groups; groups = def.groups;
node_placement_prediction = def.node_placement_prediction; node_placement_prediction = def.node_placement_prediction;
sound_place = def.sound_place;
return *this; return *this;
} }
@ -107,13 +108,17 @@ void ItemDefinition::reset()
tool_capabilities = NULL; tool_capabilities = NULL;
} }
groups.clear(); groups.clear();
sound_place = SimpleSoundSpec();
node_placement_prediction = ""; 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); writeU8(os, type);
os<<serializeString(name); os<<serializeString(name);
os<<serializeString(description); os<<serializeString(description);
@ -126,7 +131,7 @@ void ItemDefinition::serialize(std::ostream &os) const
std::string tool_capabilities_s = ""; std::string tool_capabilities_s = "";
if(tool_capabilities){ if(tool_capabilities){
std::ostringstream tmp_os(std::ios::binary); 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(); tool_capabilities_s = tmp_os.str();
} }
os<<serializeString(tool_capabilities_s); os<<serializeString(tool_capabilities_s);
@ -137,6 +142,11 @@ void ItemDefinition::serialize(std::ostream &os) const
writeS16(os, i->second); writeS16(os, i->second);
} }
os<<serializeString(node_placement_prediction); 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) void ItemDefinition::deSerialize(std::istream &is)
@ -146,7 +156,7 @@ void ItemDefinition::deSerialize(std::istream &is)
// Deserialize // Deserialize
int version = readU8(is); int version = readU8(is);
if(version != 1) if(version != 1 && version != 2)
throw SerializationError("unsupported ItemDefinition version"); throw SerializationError("unsupported ItemDefinition version");
type = (enum ItemType)readU8(is); type = (enum ItemType)readU8(is);
name = deSerializeString(is); name = deSerializeString(is);
@ -171,10 +181,24 @@ void ItemDefinition::deSerialize(std::istream &is)
int value = readS16(is); int value = readS16(is);
groups[name] = value; 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 // If you add anything here, insert it primarily inside the try-catch
// block to not need to increase the version. // block to not need to increase the version.
try{ try{
node_placement_prediction = deSerializeString(is);
}catch(SerializationError &e) {}; }catch(SerializationError &e) {};
} }
@ -211,8 +235,8 @@ public:
virtual ~CItemDefManager() virtual ~CItemDefManager()
{ {
#ifndef SERVER #ifndef SERVER
const core::list<ClientCached*> &values = m_clientcached.getValues(); const std::list<ClientCached*> &values = m_clientcached.getValues();
for(core::list<ClientCached*>::ConstIterator for(std::list<ClientCached*>::const_iterator
i = values.begin(); i != values.end(); ++i) i = values.begin(); i != values.end(); ++i)
{ {
ClientCached *cc = *i; ClientCached *cc = *i;
@ -547,7 +571,7 @@ public:
m_aliases[name] = convert_to; m_aliases[name] = convert_to;
} }
} }
void serialize(std::ostream &os) void serialize(std::ostream &os, u16 protocol_version)
{ {
writeU8(os, 0); // version writeU8(os, 0); // version
u16 count = m_item_definitions.size(); u16 count = m_item_definitions.size();
@ -559,7 +583,7 @@ public:
ItemDefinition *def = i->second; ItemDefinition *def = i->second;
// Serialize ItemDefinition and write wrapped in a string // Serialize ItemDefinition and write wrapped in a string
std::ostringstream tmp_os(std::ios::binary); std::ostringstream tmp_os(std::ios::binary);
def->serialize(tmp_os); def->serialize(tmp_os, protocol_version);
os<<serializeString(tmp_os.str()); os<<serializeString(tmp_os.str());
} }
writeU16(os, m_aliases.size()); writeU16(os, m_aliases.size());
@ -599,7 +623,7 @@ public:
void processQueue(IGameDef *gamedef) void processQueue(IGameDef *gamedef)
{ {
#ifndef SERVER #ifndef SERVER
while(m_get_clientcached_queue.size() > 0) while(!m_get_clientcached_queue.empty())
{ {
GetRequest<std::string, ClientCached*, u8, u8> GetRequest<std::string, ClientCached*, u8, u8>
request = m_get_clientcached_queue.pop(); request = m_get_clientcached_queue.pop();

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream> #include <iostream>
#include <set> #include <set>
#include "itemgroup.h" #include "itemgroup.h"
#include "sound.h"
class IGameDef; class IGameDef;
struct ToolCapabilities; struct ToolCapabilities;
@ -66,6 +67,7 @@ struct ItemDefinition
// May be NULL. If non-NULL, deleted by destructor // May be NULL. If non-NULL, deleted by destructor
ToolCapabilities *tool_capabilities; ToolCapabilities *tool_capabilities;
ItemGroupList groups; ItemGroupList groups;
SimpleSoundSpec sound_place;
// Client shall immediately place this node when player places the item. // Client shall immediately place this node when player places the item.
// Server will update the precise end result a moment later. // Server will update the precise end result a moment later.
@ -80,7 +82,7 @@ struct ItemDefinition
ItemDefinition& operator=(const ItemDefinition &def); ItemDefinition& operator=(const ItemDefinition &def);
~ItemDefinition(); ~ItemDefinition();
void reset(); void reset();
void serialize(std::ostream &os) const; void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is); void deSerialize(std::istream &is);
private: private:
void resetInitial(); void resetInitial();
@ -109,7 +111,7 @@ public:
IGameDef *gamedef) const=0; IGameDef *gamedef) const=0;
#endif #endif
virtual void serialize(std::ostream &os)=0; virtual void serialize(std::ostream &os, u16 protocol_version)=0;
}; };
class IWritableItemDefManager : public IItemDefManager class IWritableItemDefManager : public IItemDefManager
@ -146,7 +148,7 @@ public:
virtual void registerAlias(const std::string &name, virtual void registerAlias(const std::string &name,
const std::string &convert_to)=0; 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; virtual void deSerialize(std::istream &is)=0;
// Do stuff asked by threads that can only be done in the main thread // Do stuff asked by threads that can only be done in the main thread

@ -6,9 +6,9 @@ else( UNIX )
set(json_platform_LIBS "") set(json_platform_LIBS "")
endif( UNIX ) endif( UNIX )
add_library(json ${json_SRCS}) add_library(jsoncpp ${json_SRCS})
target_link_libraries( target_link_libraries(
json jsoncpp
${json_platform_LIBS} ${json_platform_LIBS}
) )

@ -345,17 +345,16 @@ const KeyPress NumberKey[] = {
*/ */
// A simple cache for quicker lookup // 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) 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); n = g_key_setting_cache.find(settingname);
if(n) if(n != g_key_setting_cache.end())
return n->getValue(); return n->second;
g_key_setting_cache.insert(settingname, g_key_setting_cache[settingname] = g_settings->get(settingname).c_str();
g_settings->get(settingname).c_str()); return g_key_setting_cache.find(settingname)->second;
return g_key_setting_cache.find(settingname)->getValue();
} }
void clearKeyCache() void clearKeyCache()

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h" #include "gamedef.h"
#include "nodedef.h" #include "nodedef.h"
#include "settings.h" #include "settings.h"
#include "environment.h"
#include "map.h" #include "map.h"
#include "util/numeric.h" #include "util/numeric.h"
@ -57,9 +58,10 @@ LocalPlayer::~LocalPlayer()
{ {
} }
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
core::list<CollisionInfo> *collision_info) std::list<CollisionInfo> *collision_info)
{ {
Map *map = &env->getMap();
INodeDefManager *nodemgr = m_gamedef->ndef(); INodeDefManager *nodemgr = m_gamedef->ndef();
v3f position = getPosition(); v3f position = getPosition();
@ -97,15 +99,15 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
if(in_liquid) if(in_liquid)
{ {
v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS); v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid(); in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid();
liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity; liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity;
} }
// If not in liquid, the threshold of going in is at lower y // If not in liquid, the threshold of going in is at lower y
else else
{ {
v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS); v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid(); in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid();
liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity; liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity;
} }
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
@ -118,7 +120,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
*/ */
try{ try{
v3s16 pp = floatToInt(position + v3f(0,0,0), BS); 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) catch(InvalidPositionException &e)
{ {
@ -132,8 +134,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
try { try {
v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS); v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS); v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
is_climbing = ((nodemgr->get(map.getNode(pp).getContent()).climbable || is_climbing = ((nodemgr->get(map->getNode(pp).getContent()).climbable ||
nodemgr->get(map.getNode(pp2).getContent()).climbable) && !free_move); nodemgr->get(map->getNode(pp2).getContent()).climbable) && !free_move);
} }
catch(InvalidPositionException &e) 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); 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, pos_max_d, playerbox, player_stepheight, dtime,
position, m_speed, accel_f); 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); v3s16 current_node = floatToInt(position - v3f(0,BS/2,0), BS);
if(m_sneak_node_exists && 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") m_old_node_below_type != "air")
{ {
// Old node appears to have been removed; that is, // 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_need_to_get_new_sneak_node = false;
m_sneak_node_exists = 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 // We are on something, so make sure to recalculate the sneak
// node. // node.
@ -267,10 +269,10 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
try{ try{
// The node to be sneaked on has to be walkable // 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; continue;
// And the node above it has to be nonwalkable // 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; continue;
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
@ -331,7 +333,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
{ {
camera_barely_in_ceiling = false; camera_barely_in_ceiling = false;
v3s16 camera_np = floatToInt(getEyePosition(), BS); v3s16 camera_np = floatToInt(getEyePosition(), BS);
MapNode n = map.getNodeNoEx(camera_np); MapNode n = map->getNodeNoEx(camera_np);
if(n.getContent() != CONTENT_IGNORE){ if(n.getContent() != CONTENT_IGNORE){
if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){ if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
camera_barely_in_ceiling = true; 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 Update the node last under the player
*/ */
m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS); 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 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 // Determine if jumping is possible
m_can_jump = touching_ground && !in_liquid; m_can_jump = touching_ground && !in_liquid;
if(itemgroup_get(f.groups, "disable_jump")) if(itemgroup_get(f.groups, "disable_jump"))
m_can_jump = false; 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) void LocalPlayer::applyControl(float dtime)

@ -21,6 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define LOCALPLAYER_HEADER #define LOCALPLAYER_HEADER
#include "player.h" #include "player.h"
#include <list>
class ClientEnvironment;
class LocalPlayer : public Player class LocalPlayer : public Player
{ {
@ -37,9 +40,9 @@ public:
v3f overridePosition; v3f overridePosition;
void move(f32 dtime, Map &map, f32 pos_max_d, void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
core::list<CollisionInfo> *collision_info); std::list<CollisionInfo> *collision_info);
void move(f32 dtime, Map &map, f32 pos_max_d); void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d);
void applyControl(float dtime); void applyControl(float dtime);

@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes_extrabloated.h"
#include "debug.h" #include "debug.h"
#include "test.h" #include "test.h"
#include "clouds.h"
#include "server.h" #include "server.h"
#include "constants.h" #include "constants.h"
#include "porting.h" #include "porting.h"
@ -132,7 +133,12 @@ MainGameCallback *g_gamecallback = NULL;
u32 getTimeMs() u32 getTimeMs()
{ {
/* Use imprecise system calls directly (from porting.h) */ /* 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 #else
@ -141,7 +147,7 @@ u32 getTimeMs()
class TimeGetter class TimeGetter
{ {
public: public:
virtual u32 getTime() = 0; virtual u32 getTime(TimePrecision prec) = 0;
}; };
// A precise irrlicht one // A precise irrlicht one
@ -151,11 +157,15 @@ public:
IrrlichtTimeGetter(IrrlichtDevice *device): IrrlichtTimeGetter(IrrlichtDevice *device):
m_device(device) m_device(device)
{} {}
u32 getTime() u32 getTime(TimePrecision prec)
{ {
if(m_device == NULL) if (prec == PRECISION_MILLI) {
return 0; if(m_device == NULL)
return m_device->getTimer()->getRealTime(); return 0;
return m_device->getTimer()->getRealTime();
} else {
return porting::getTime(prec);
}
} }
private: private:
IrrlichtDevice *m_device; IrrlichtDevice *m_device;
@ -164,9 +174,9 @@ private:
class SimpleTimeGetter: public TimeGetter class SimpleTimeGetter: public TimeGetter
{ {
public: public:
u32 getTime() u32 getTime(TimePrecision prec)
{ {
return porting::getTimeMs(); return porting::getTime(prec);
} }
}; };
@ -178,7 +188,13 @@ u32 getTimeMs()
{ {
if(g_timegetter == NULL) if(g_timegetter == NULL)
return 0; 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 #endif
@ -596,50 +612,120 @@ private:
bool rightreleased; bool rightreleased;
}; };
void drawMenuBackground(video::IVideoDriver* driver) //Draw the tiled menu background
{ void drawMenuBackground(video::IVideoDriver* driver) {
core::dimension2d<u32> screensize = driver->getScreenSize(); core::dimension2d<u32> screensize = driver->getScreenSize();
video::ITexture *bgtexture = std::string path = getTexturePath("menubg.png");
driver->getTexture(getTexturePath("menubg.png").c_str()); if (path[0]) {
if(bgtexture) video::ITexture *bgtexture =
{ driver->getTexture(path.c_str());
s32 scaledsize = 128;
// The important difference between destsize and screensize is if (bgtexture) {
// that destsize is rounded to whole scaled pixels. s32 scaledsize = 128;
// 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. // The important difference between destsize and screensize is
driver->draw2DImage(bgtexture, // that destsize is rounded to whole scaled pixels.
core::rect<s32>(0, 0, destsize.X, destsize.Y), // These formulas use component-wise multiplication and division of v2u32.
core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y), v2u32 texturesize = bgtexture->getSize();
NULL, NULL, true); 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);
}
} }
}
video::ITexture *logotexture = //Draw the footer at the bottom of the window
driver->getTexture(getTexturePath("menulogo.png").c_str()); void drawMenuFooter(video::IVideoDriver* driver, bool clouds) {
if(logotexture) core::dimension2d<u32> screensize = driver->getScreenSize();
{ std::string path = getTexturePath(clouds ?
v2s32 logosize(logotexture->getOriginalSize().Width, "menufooter_clouds.png" : "menufooter.png");
logotexture->getOriginalSize().Height); if (path[0]) {
logosize *= 4; video::ITexture *footertexture =
driver->getTexture(path.c_str());
video::SColor bgcolor(255,50,50,50); if (footertexture) {
core::rect<s32> bgrect(0, screensize.Height-logosize.Y-20, f32 mult = (((f32)screensize.Width)) /
screensize.Width, screensize.Height); ((f32)footertexture->getOriginalSize().Width);
driver->draw2DRectangle(bgcolor, bgrect, NULL);
core::rect<s32> rect(0,0,logosize.X,logosize.Y); v2s32 footersize(((f32)footertexture->getOriginalSize().Width) * mult,
rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y); ((f32)footertexture->getOriginalSize().Height) * mult);
rect -= v2s32(logosize.X/2, 0);
driver->draw2DImage(logotexture, rect, // Don't draw the footer if there isn't enough room
core::rect<s32>(core::position2d<s32>(0,0), s32 free_space = (((s32)screensize.Height)-320)/2;
core::dimension2di(logotexture->getSize())), if (free_space > footersize.Y) {
NULL, NULL, true); 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; tempf = -324;
const s16 ii=300; const s16 ii=300;
for(s16 y=0; y<ii; y++){ for(s16 y=0; y<ii; y++){
for(s16 x=0; x<ii; x++){ for(s16 x=0; x<ii; x++){
map1.insert(v2s16(x,y), tempf); map1[v2s16(x,y)] = tempf;
tempf += 1; tempf += 1;
} }
} }
@ -734,7 +820,7 @@ void SpeedTests()
} }
} }
// Do at least 10ms // Do at least 10ms
while(timer.getTime() < 10); while(timer.getTimerTime() < 10);
u32 dtime = timer.stop(); u32 dtime = timer.stop();
u32 per_ms = n / dtime; u32 per_ms = n / dtime;
@ -788,48 +874,48 @@ int main(int argc, char *argv[])
*/ */
// List all allowed options // List all allowed options
core::map<std::string, ValueSpec> allowed_options; std::map<std::string, ValueSpec> allowed_options;
allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("help", ValueSpec(VALUETYPE_FLAG,
_("Show allowed options"))); _("Show allowed options"))));
allowed_options.insert("config", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("config", ValueSpec(VALUETYPE_STRING,
_("Load configuration from specified file"))); _("Load configuration from specified file"))));
allowed_options.insert("port", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("port", ValueSpec(VALUETYPE_STRING,
_("Set network port (UDP)"))); _("Set network port (UDP)"))));
allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("disable-unittests", ValueSpec(VALUETYPE_FLAG,
_("Disable unit tests"))); _("Disable unit tests"))));
allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("enable-unittests", ValueSpec(VALUETYPE_FLAG,
_("Enable unit tests"))); _("Enable unit tests"))));
allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("map-dir", ValueSpec(VALUETYPE_STRING,
_("Same as --world (deprecated)"))); _("Same as --world (deprecated)"))));
allowed_options.insert("world", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("world", ValueSpec(VALUETYPE_STRING,
_("Set world path (implies local game) ('list' lists all)"))); _("Set world path (implies local game) ('list' lists all)"))));
allowed_options.insert("worldname", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("worldname", ValueSpec(VALUETYPE_STRING,
_("Set world by name (implies local game)"))); _("Set world by name (implies local game)"))));
allowed_options.insert("info", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("info", ValueSpec(VALUETYPE_FLAG,
_("Print more information to console"))); _("Print more information to console"))));
allowed_options.insert("verbose", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("verbose", ValueSpec(VALUETYPE_FLAG,
_("Print even more information to console"))); _("Print even more information to console"))));
allowed_options.insert("trace", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("trace", ValueSpec(VALUETYPE_FLAG,
_("Print enormous amounts of information to log and console"))); _("Print enormous amounts of information to log and console"))));
allowed_options.insert("logfile", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("logfile", ValueSpec(VALUETYPE_STRING,
_("Set logfile path ('' = no logging)"))); _("Set logfile path ('' = no logging)"))));
allowed_options.insert("gameid", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("gameid", ValueSpec(VALUETYPE_STRING,
_("Set gameid (\"--gameid list\" prints available ones)"))); _("Set gameid (\"--gameid list\" prints available ones)"))));
#ifndef SERVER #ifndef SERVER
allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("speedtests", ValueSpec(VALUETYPE_FLAG,
_("Run speed tests"))); _("Run speed tests"))));
allowed_options.insert("address", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("address", ValueSpec(VALUETYPE_STRING,
_("Address to connect to. ('' = local game)"))); _("Address to connect to. ('' = local game)"))));
allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("random-input", ValueSpec(VALUETYPE_FLAG,
_("Enable random user input, for testing"))); _("Enable random user input, for testing"))));
allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("server", ValueSpec(VALUETYPE_FLAG,
_("Run dedicated server"))); _("Run dedicated server"))));
allowed_options.insert("name", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("name", ValueSpec(VALUETYPE_STRING,
_("Set player name"))); _("Set player name"))));
allowed_options.insert("password", ValueSpec(VALUETYPE_STRING, allowed_options.insert(std::make_pair("password", ValueSpec(VALUETYPE_STRING,
_("Set password"))); _("Set password"))));
allowed_options.insert("go", ValueSpec(VALUETYPE_FLAG, allowed_options.insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG,
_("Disable main menu"))); _("Disable main menu"))));
#endif #endif
Settings cmd_args; Settings cmd_args;
@ -839,20 +925,20 @@ int main(int argc, char *argv[])
if(ret == false || cmd_args.getFlag("help") || cmd_args.exists("nonopt1")) if(ret == false || cmd_args.getFlag("help") || cmd_args.exists("nonopt1"))
{ {
dstream<<_("Allowed options:")<<std::endl; dstream<<_("Allowed options:")<<std::endl;
for(core::map<std::string, ValueSpec>::Iterator for(std::map<std::string, ValueSpec>::iterator
i = allowed_options.getIterator(); i = allowed_options.begin();
i.atEnd() == false; i++) i != allowed_options.end(); ++i)
{ {
std::ostringstream os1(std::ios::binary); std::ostringstream os1(std::ios::binary);
os1<<" --"<<i.getNode()->getKey(); os1<<" --"<<i->first;
if(i.getNode()->getValue().type == VALUETYPE_FLAG) if(i->second.type == VALUETYPE_FLAG)
{} {}
else else
os1<<_(" <value>"); os1<<_(" <value>");
dstream<<padStringRight(os1.str(), 24); dstream<<padStringRight(os1.str(), 24);
if(i.getNode()->getValue().help != NULL) if(i->second.help != NULL)
dstream<<i.getNode()->getValue().help; dstream<<i->second.help;
dstream<<std::endl; dstream<<std::endl;
} }
@ -953,7 +1039,7 @@ int main(int argc, char *argv[])
} }
else else
{ {
core::array<std::string> filenames; std::vector<std::string> filenames;
filenames.push_back(porting::path_user + filenames.push_back(porting::path_user +
DIR_DELIM + "minetest.conf"); DIR_DELIM + "minetest.conf");
// Legacy configuration file location // Legacy configuration file location
@ -1279,6 +1365,14 @@ int main(int argc, char *argv[])
driverType = video::EDT_DIRECT3D9; driverType = video::EDT_DIRECT3D9;
else if(driverstring == "opengl") else if(driverstring == "opengl")
driverType = video::EDT_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 else
{ {
errorstream<<"WARNING: Invalid video_driver specified; defaulting " errorstream<<"WARNING: Invalid video_driver specified; defaulting "
@ -1462,6 +1556,8 @@ int main(int argc, char *argv[])
MainMenuData menudata; MainMenuData menudata;
if(g_settings->exists("selected_mainmenu_tab")) if(g_settings->exists("selected_mainmenu_tab"))
menudata.selected_tab = g_settings->getS32("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.address = narrow_to_wide(address);
menudata.name = narrow_to_wide(playername); menudata.name = narrow_to_wide(playername);
menudata.port = narrow_to_wide(itos(port)); 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.enable_shaders = g_settings->getS32("enable_shaders");
menudata.preload_item_visuals = g_settings->getBool("preload_item_visuals"); menudata.preload_item_visuals = g_settings->getBool("preload_item_visuals");
menudata.enable_particles = g_settings->getBool("enable_particles"); 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); driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, menudata.mip_map);
menudata.creative_mode = g_settings->getBool("creative_mode"); menudata.creative_mode = g_settings->getBool("creative_mode");
menudata.enable_damage = g_settings->getBool("enable_damage"); menudata.enable_damage = g_settings->getBool("enable_damage");
@ -1518,7 +1615,7 @@ int main(int argc, char *argv[])
if(skip_main_menu == false) if(skip_main_menu == false)
{ {
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
float fps_max = g_settings->getFloat("fps_max");
infostream<<"Waiting for other menus"<<std::endl; infostream<<"Waiting for other menus"<<std::endl;
while(device->run() && kill == false) while(device->run() && kill == false)
{ {
@ -1540,6 +1637,22 @@ int main(int argc, char *argv[])
&g_menumgr, &menudata, g_gamecallback); &g_menumgr, &menudata, g_gamecallback);
menu->allowFocusRemoval(true); 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"") if(error_message != L"")
{ {
verbosestream<<"error_message = " verbosestream<<"error_message = "
@ -1552,6 +1665,9 @@ int main(int argc, char *argv[])
error_message = L""; error_message = L"";
} }
// Time is in milliseconds, for clouds
u32 lasttime = device->getTimer()->getTime();
infostream<<"Created main menu"<<std::endl; infostream<<"Created main menu"<<std::endl;
while(device->run() && kill == false) while(device->run() && kill == false)
@ -1559,10 +1675,32 @@ int main(int argc, char *argv[])
if(menu->getStatus() == true) if(menu->getStatus() == true)
break; break;
//driver->beginScene(true, true, video::SColor(255,0,0,0)); // Time calc for the clouds
driver->beginScene(true, true, video::SColor(255,128,128,128)); 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(); guienv->drawAll();
@ -1570,15 +1708,42 @@ int main(int argc, char *argv[])
// On some computers framerate doesn't seem to be // On some computers framerate doesn't seem to be
// automatically limited // 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; infostream<<"Dropping main menu"<<std::endl;
menu->drop(); menu->drop();
if (cloud_menu_background) {
clouds->drop();
smgr->clear();
}
} }
playername = wide_to_narrow(menudata.name); playername = wide_to_narrow(menudata.name);
if (playername == "")
playername = std::string("Guest") + itos(myrand_range(1000,9999));
password = translatePassword(playername, menudata.password); password = translatePassword(playername, menudata.password);
//infostream<<"Main: password hash: '"<<password<<"'"<<std::endl; //infostream<<"Main: password hash: '"<<password<<"'"<<std::endl;
@ -1589,6 +1754,7 @@ int main(int argc, char *argv[])
simple_singleplayer_mode = menudata.simple_singleplayer_mode; simple_singleplayer_mode = menudata.simple_singleplayer_mode;
// Save settings // Save settings
g_settings->setS32("selected_mainmenu_tab", menudata.selected_tab); 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("new_style_leaves", itos(menudata.fancy_trees));
g_settings->set("smooth_lighting", itos(menudata.smooth_lighting)); g_settings->set("smooth_lighting", itos(menudata.smooth_lighting));
g_settings->set("enable_3d_clouds", itos(menudata.clouds_3d)); 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->setS32("enable_shaders", menudata.enable_shaders);
g_settings->set("preload_item_visuals", itos(menudata.preload_item_visuals)); g_settings->set("preload_item_visuals", itos(menudata.preload_item_visuals));
g_settings->set("enable_particles", itos(menudata.enable_particles)); 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("creative_mode", itos(menudata.creative_mode));
g_settings->set("enable_damage", itos(menudata.enable_damage)); g_settings->set("enable_damage", itos(menudata.enable_damage));

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h" // assert #include "debug.h" // assert
#include "modalMenu.h" #include "modalMenu.h"
#include "guiPauseMenu.h" //For IGameCallback #include "guiPauseMenu.h" //For IGameCallback
#include <list>
extern gui::IGUIEnvironment* guienv; extern gui::IGUIEnvironment* guienv;
extern gui::IGUIStaticText *guiroot; extern gui::IGUIStaticText *guiroot;
@ -37,15 +38,15 @@ class MainMenuManager : public IMenuManager
public: public:
virtual void createdMenu(GUIModalMenu *menu) virtual void createdMenu(GUIModalMenu *menu)
{ {
for(core::list<GUIModalMenu*>::Iterator for(std::list<GUIModalMenu*>::iterator
i = m_stack.begin(); i = m_stack.begin();
i != m_stack.end(); i++) i != m_stack.end(); ++i)
{ {
assert(*i != menu); assert(*i != menu);
} }
if(m_stack.size() != 0) if(m_stack.size() != 0)
(*m_stack.getLast())->setVisible(false); m_stack.back()->setVisible(false);
m_stack.push_back(menu); m_stack.push_back(menu);
} }
@ -55,9 +56,9 @@ public:
bool removed_entry; bool removed_entry;
do{ do{
removed_entry = false; removed_entry = false;
for(core::list<GUIModalMenu*>::Iterator for(std::list<GUIModalMenu*>::iterator
i = m_stack.begin(); i = m_stack.begin();
i != m_stack.end(); i++) i != m_stack.end(); ++i)
{ {
if(*i == menu) if(*i == menu)
{ {
@ -73,7 +74,7 @@ public:
m_stack.erase(i);*/ m_stack.erase(i);*/
if(m_stack.size() != 0) if(m_stack.size() != 0)
(*m_stack.getLast())->setVisible(true); m_stack.back()->setVisible(true);
} }
u32 menuCount() u32 menuCount()
@ -81,7 +82,7 @@ public:
return m_stack.size(); return m_stack.size();
} }
core::list<GUIModalMenu*> m_stack; std::list<GUIModalMenu*> m_stack;
}; };
extern MainMenuManager g_menumgr; extern MainMenuManager g_menumgr;

File diff suppressed because it is too large Load Diff

@ -25,6 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <jthread.h> #include <jthread.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <set>
#include <map>
#include <list>
#include "irrlichttypes_bloated.h" #include "irrlichttypes_bloated.h"
#include "mapnode.h" #include "mapnode.h"
@ -47,7 +50,7 @@ class NodeMetadata;
class IGameDef; class IGameDef;
class IRollbackReportSink; class IRollbackReportSink;
class EmergeManager; class EmergeManager;
class BlockMakeData; struct BlockMakeData;
/* /*
@ -75,7 +78,7 @@ struct MapEditEvent
MapEditEventType type; MapEditEventType type;
v3s16 p; v3s16 p;
MapNode n; MapNode n;
core::map<v3s16, bool> modified_blocks; std::set<v3s16> modified_blocks;
u16 already_known_by_peer; u16 already_known_by_peer;
MapEditEvent(): MapEditEvent():
@ -90,14 +93,7 @@ struct MapEditEvent
event->type = type; event->type = type;
event->p = p; event->p = p;
event->n = n; event->n = n;
for(core::map<v3s16, bool>::Iterator event->modified_blocks = modified_blocks;
i = modified_blocks.getIterator();
i.atEnd()==false; i++)
{
v3s16 p = i.getNode()->getKey();
bool v = i.getNode()->getValue();
event->modified_blocks.insert(p, v);
}
return event; return event;
} }
@ -117,11 +113,11 @@ struct MapEditEvent
case MEET_OTHER: case MEET_OTHER:
{ {
VoxelArea a; VoxelArea a;
for(core::map<v3s16, bool>::Iterator for(std::set<v3s16>::iterator
i = modified_blocks.getIterator(); i = modified_blocks.begin();
i.atEnd()==false; i++) i != modified_blocks.end(); ++i)
{ {
v3s16 p = i.getNode()->getKey(); v3s16 p = *i;
v3s16 np1 = p*MAP_BLOCKSIZE; v3s16 np1 = p*MAP_BLOCKSIZE;
v3s16 np2 = np1 + v3s16(1,1,1)*MAP_BLOCKSIZE - v3s16(1,1,1); v3s16 np2 = np1 + v3s16(1,1,1)*MAP_BLOCKSIZE - v3s16(1,1,1);
a.addPoint(np1); a.addPoint(np1);
@ -186,7 +182,7 @@ public:
*/ */
virtual MapSector * emergeSector(v2s16 p){ return NULL; } virtual MapSector * emergeSector(v2s16 p){ return NULL; }
virtual MapSector * emergeSector(v2s16 p, 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 // Returns InvalidPositionException if not found
MapBlock * getBlockNoCreate(v3s16 p); MapBlock * getBlockNoCreate(v3s16 p);
@ -212,42 +208,42 @@ public:
MapNode getNodeNoEx(v3s16 p); MapNode getNodeNoEx(v3s16 p);
void unspreadLight(enum LightBank bank, void unspreadLight(enum LightBank bank,
core::map<v3s16, u8> & from_nodes, std::map<v3s16, u8> & from_nodes,
core::map<v3s16, bool> & light_sources, std::set<v3s16> & light_sources,
core::map<v3s16, MapBlock*> & modified_blocks); std::map<v3s16, MapBlock*> & modified_blocks);
void unLightNeighbors(enum LightBank bank, void unLightNeighbors(enum LightBank bank,
v3s16 pos, u8 lightwas, v3s16 pos, u8 lightwas,
core::map<v3s16, bool> & light_sources, std::set<v3s16> & light_sources,
core::map<v3s16, MapBlock*> & modified_blocks); std::map<v3s16, MapBlock*> & modified_blocks);
void spreadLight(enum LightBank bank, void spreadLight(enum LightBank bank,
core::map<v3s16, bool> & from_nodes, std::set<v3s16> & from_nodes,
core::map<v3s16, MapBlock*> & modified_blocks); std::map<v3s16, MapBlock*> & modified_blocks);
void lightNeighbors(enum LightBank bank, void lightNeighbors(enum LightBank bank,
v3s16 pos, v3s16 pos,
core::map<v3s16, MapBlock*> & modified_blocks); std::map<v3s16, MapBlock*> & modified_blocks);
v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p); v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p);
s16 propagateSunlight(v3s16 start, s16 propagateSunlight(v3s16 start,
core::map<v3s16, MapBlock*> & modified_blocks); std::map<v3s16, MapBlock*> & modified_blocks);
void updateLighting(enum LightBank bank, void updateLighting(enum LightBank bank,
core::map<v3s16, MapBlock*> & a_blocks, std::map<v3s16, MapBlock*> & a_blocks,
core::map<v3s16, MapBlock*> & modified_blocks); std::map<v3s16, MapBlock*> & modified_blocks);
void updateLighting(core::map<v3s16, MapBlock*> & a_blocks, void updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
core::map<v3s16, MapBlock*> & modified_blocks); std::map<v3s16, MapBlock*> & modified_blocks);
/* /*
These handle lighting but not faces. These handle lighting but not faces.
*/ */
void addNodeAndUpdate(v3s16 p, MapNode n, void addNodeAndUpdate(v3s16 p, MapNode n,
core::map<v3s16, MapBlock*> &modified_blocks); std::map<v3s16, MapBlock*> &modified_blocks);
void removeNodeAndUpdate(v3s16 p, void removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks); std::map<v3s16, MapBlock*> &modified_blocks);
/* /*
Wrappers for the latter ones. Wrappers for the latter ones.
@ -281,12 +277,12 @@ public:
Saves modified blocks before unloading on MAPTYPE_SERVER. Saves modified blocks before unloading on MAPTYPE_SERVER.
*/ */
void timerUpdate(float dtime, float unload_timeout, 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 // Deletes sectors and their blocks from memory
// Takes cache into account // Takes cache into account
// If deleted sector is in sector cache, clears cache // If deleted sector is in sector cache, clears cache
void deleteSectors(core::list<v2s16> &list); void deleteSectors(std::list<v2s16> &list);
#if 0 #if 0
/* /*
@ -301,8 +297,8 @@ public:
// For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: " // For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: "
virtual void PrintInfo(std::ostream &out); virtual void PrintInfo(std::ostream &out);
void transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks); void transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks);
void transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks); void transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks);
/* /*
Node metadata Node metadata
@ -325,7 +321,7 @@ public:
/* /*
Misc. Misc.
*/ */
core::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;} std::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
/* /*
Variables Variables
@ -340,9 +336,9 @@ protected:
IGameDef *m_gamedef; 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 // Be sure to set this to NULL when the cached sector is deleted
MapSector *m_sector_cache; MapSector *m_sector_cache;
@ -385,13 +381,7 @@ public:
*/ */
bool initBlockMake(BlockMakeData *data, v3s16 blockpos); bool initBlockMake(BlockMakeData *data, v3s16 blockpos);
MapBlock *finishBlockMake(BlockMakeData *data, MapBlock *finishBlockMake(BlockMakeData *data,
core::map<v3s16, MapBlock*> &changed_blocks); std::map<v3s16, MapBlock*> &changed_blocks);
// A non-threaded wrapper to the above - DEFUNCT
/* MapBlock * generateBlock(
v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks
);*/
/* /*
Get a block from somewhere. Get a block from somewhere.
@ -444,9 +434,7 @@ public:
void save(ModifiedState save_level); void save(ModifiedState save_level);
//void loadAll(); //void loadAll();
void listAllLoadableBlocks(std::list<v3s16> &dst);
void listAllLoadableBlocks(core::list<v3s16> &dst);
// Saves map seed and possibly other stuff // Saves map seed and possibly other stuff
void saveMapMeta(); void saveMapMeta();
void loadMapMeta(); void loadMapMeta();
@ -538,15 +526,15 @@ public:
virtual void emerge(VoxelArea a, s32 caller_id=-1); 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 key = blockpos
value = flags describing the block value = flags describing the block
*/ */
core::map<v3s16, u8> m_loaded_blocks; std::map<v3s16, u8> m_loaded_blocks;
protected:
Map *m_map;
}; };
class ManualMapVoxelManipulator : public MapVoxelManipulator class ManualMapVoxelManipulator : public MapVoxelManipulator
@ -563,7 +551,7 @@ public:
void initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max); void initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max);
// This is much faster with big chunks of generated data // 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: protected:
bool m_create_area; bool m_create_area;

@ -168,7 +168,7 @@ MapNode MapBlock::getNodeParentNoEx(v3s16 p)
if black_air_left!=NULL, it is set to true if non-sunlighted if black_air_left!=NULL, it is set to true if non-sunlighted
air is left in block. 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) bool remove_light, bool *black_air_left)
{ {
INodeDefManager *nodemgr = m_gamedef->ndef(); INodeDefManager *nodemgr = m_gamedef->ndef();
@ -287,7 +287,7 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
if(diminish_light(current_light) != 0) 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) if(current_light == 0 && stopped_to_solid_object)

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <jmutex.h> #include <jmutex.h>
#include <jmutexautolock.h> #include <jmutexautolock.h>
#include <exception> #include <exception>
#include <set>
#include "debug.h" #include "debug.h"
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include "irr_v3d.h" #include "irr_v3d.h"
@ -352,7 +353,7 @@ public:
} }
// See comments in mapblock.cpp // 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); bool remove_light=false, bool *black_air_left=NULL);
// Copies data to VoxelManipulator to getPosRelative() // Copies data to VoxelManipulator to getPosRelative()

@ -445,7 +445,7 @@ struct FastFace
}; };
static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3, 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; FastFace face;
@ -455,6 +455,80 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
v3f vertex_pos[4]; v3f vertex_pos[4];
v3s16 vertex_dirs[4]; v3s16 vertex_dirs[4];
getNodeVertexDirs(dir, vertex_dirs); 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++) for(u16 i=0; i<4; i++)
{ {
vertex_pos[i] = v3f( vertex_pos[i] = v3f(
@ -601,60 +675,50 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
// 5 = (0,0,-1) // 5 = (0,0,-1)
// 6 = (0,-1,0) // 6 = (0,-1,0)
// 7 = (-1,0,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 // Get rotation for things like chests
u8 facedir = mn.getFaceDir(ndef); u8 facedir = mn.getFaceDir(ndef);
assert(facedir <= 3); assert(facedir <= 23);
static const u16 dir_to_tile[24 * 16] =
static const u8 dir_to_tile[4 * 8] =
{ {
// 0 +X +Y +Z 0 -Z -Y -X // 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
0, 2, 0, 4, 0, 5, 1, 3, // facedir = 0 0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
0, 4, 0, 3, 0, 2, 1, 5, // facedir = 1 0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
0, 3, 0, 5, 0, 4, 1, 2, // facedir = 2 0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
0, 5, 0, 2, 0, 3, 1, 4, // facedir = 3 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]; u16 tile_index=facedir*16 + dir_i;
TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
// If not rotated or is side tile, we're done spec.rotation=dir_to_tile[tile_index + 1];
if(facedir == 0 || (tileindex != 0 && tileindex != 1)) std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
return getNodeTileN(mn, p, tileindex, data); spec.texture = data->m_gamedef->tsrc()->getTexture(name);
// 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);
}
}
return spec; return spec;
} }
@ -745,7 +809,7 @@ static void updateFastFaceRow(
v3f translate_dir_f, v3f translate_dir_f,
v3s16 face_dir, v3s16 face_dir,
v3f face_dir_f, v3f face_dir_f,
core::array<FastFace> &dest) std::vector<FastFace> &dest)
{ {
v3s16 p = startpos; v3s16 p = startpos;
@ -794,6 +858,7 @@ static void updateFastFaceRow(
&& next_lights[2] == lights[2] && next_lights[2] == lights[2]
&& next_lights[3] == lights[3] && next_lights[3] == lights[3]
&& next_tile == tile && next_tile == tile
&& tile.rotation == 0
&& next_light_source == light_source) && next_light_source == light_source)
{ {
next_is_different = false; next_is_different = false;
@ -897,7 +962,7 @@ static void updateFastFaceRow(
} }
static void updateAllFastFaceRows(MeshMakeData *data, 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+ 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) // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
//TimeTaker timer1("MapBlockMesh()"); //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. We are including the faces of the trailing edges of the block.
@ -1124,8 +1189,8 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
m_mesh->addMeshBuffer(buf); m_mesh->addMeshBuffer(buf);
// Mesh grabbed it // Mesh grabbed it
buf->drop(); buf->drop();
buf->append(p.vertices.pointer(), p.vertices.size(), buf->append(&p.vertices[0], p.vertices.size(),
p.indices.pointer(), p.indices.size()); &p.indices[0], p.indices.size());
} }
/* /*

@ -143,13 +143,13 @@ private:
struct PreMeshBuffer struct PreMeshBuffer
{ {
TileSpec tile; TileSpec tile;
core::array<u16> indices; std::vector<u16> indices;
core::array<video::S3DVertex> vertices; std::vector<video::S3DVertex> vertices;
}; };
struct MeshCollector struct MeshCollector
{ {
core::array<PreMeshBuffer> prebuffers; std::vector<PreMeshBuffer> prebuffers;
void append(const TileSpec &material, void append(const TileSpec &material,
const video::S3DVertex *vertices, u32 numVertices, const video::S3DVertex *vertices, u32 numVertices,

File diff suppressed because it is too large Load Diff

@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MG_TREES 0x01 #define MG_TREES 0x01
#define MG_CAVES 0x02 #define MG_CAVES 0x02
#define MG_DUNGEONS 0x04 #define MG_DUNGEONS 0x04
#define MGV6_FORESTS 0x08 #define MGV6_JUNGLES 0x08
#define MGV6_BIOME_BLEND 0x10 #define MGV6_BIOME_BLEND 0x10
#define MG_FLAT 0x20 #define MG_FLAT 0x20
@ -45,7 +45,8 @@ class MapBlock;
class ManualMapVoxelManipulator; class ManualMapVoxelManipulator;
class VoxelManipulator; class VoxelManipulator;
class INodeDefManager; class INodeDefManager;
class BlockMakeData; struct BlockMakeData;
class VoxelArea;
struct MapgenParams { struct MapgenParams {
std::string mg_name; std::string mg_name;
@ -72,6 +73,14 @@ public:
int water_level; int water_level;
bool generating; bool generating;
int id; 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 void makeChunk(BlockMakeData *data) {};
virtual int getGroundLevelAtPoint(v2s16 p) = 0; virtual int getGroundLevelAtPoint(v2s16 p) = 0;
@ -88,5 +97,48 @@ struct MapgenFactory {
virtual MapgenParams *createMapgenParams() = 0; 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 #endif

371
src/mapgen_indev.cpp Normal file

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

152
src/mapgen_indev.h Normal file

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

102
src/mapgen_singlenode.cpp Normal file

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

53
src/mapgen_singlenode.h Normal file

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

File diff suppressed because it is too large Load Diff

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h" #include "mapgen.h"
#define AVERAGE_MUD_AMOUNT 4 #define AVERAGE_MUD_AMOUNT 4
#define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
enum BiomeType 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_terrain_higher;
extern NoiseParams nparams_v6_def_steepness; extern NoiseParams nparams_v6_def_steepness;
extern NoiseParams nparams_v6_def_height_select; extern NoiseParams nparams_v6_def_height_select;
extern NoiseParams nparams_v6_def_trees;
extern NoiseParams nparams_v6_def_mud; extern NoiseParams nparams_v6_def_mud;
extern NoiseParams nparams_v6_def_beach; extern NoiseParams nparams_v6_def_beach;
extern NoiseParams nparams_v6_def_biome; extern NoiseParams nparams_v6_def_biome;
extern NoiseParams nparams_v6_def_cave; 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 { struct MapgenV6Params : public MapgenParams {
float freq_desert; float freq_desert;
@ -47,11 +60,13 @@ struct MapgenV6Params : public MapgenParams {
NoiseParams *np_terrain_higher; NoiseParams *np_terrain_higher;
NoiseParams *np_steepness; NoiseParams *np_steepness;
NoiseParams *np_height_select; NoiseParams *np_height_select;
NoiseParams *np_trees;
NoiseParams *np_mud; NoiseParams *np_mud;
NoiseParams *np_beach; NoiseParams *np_beach;
NoiseParams *np_biome; NoiseParams *np_biome;
NoiseParams *np_cave; NoiseParams *np_cave;
NoiseParams *np_humidity;
NoiseParams *np_trees;
NoiseParams *np_apple_trees;
MapgenV6Params() { MapgenV6Params() {
freq_desert = 0.45; freq_desert = 0.45;
@ -60,11 +75,14 @@ struct MapgenV6Params : public MapgenParams {
np_terrain_higher = &nparams_v6_def_terrain_higher; np_terrain_higher = &nparams_v6_def_terrain_higher;
np_steepness = &nparams_v6_def_steepness; np_steepness = &nparams_v6_def_steepness;
np_height_select = &nparams_v6_def_height_select; np_height_select = &nparams_v6_def_height_select;
np_trees = &nparams_v6_def_trees;
np_mud = &nparams_v6_def_mud; np_mud = &nparams_v6_def_mud;
np_beach = &nparams_v6_def_beach; np_beach = &nparams_v6_def_beach;
np_biome = &nparams_v6_def_biome; np_biome = &nparams_v6_def_biome;
np_cave = &nparams_v6_def_cave; 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); bool readParams(Settings *settings);
@ -73,64 +91,90 @@ struct MapgenV6Params : public MapgenParams {
class MapgenV6 : public Mapgen { class MapgenV6 : public Mapgen {
public: public:
//ManualMapVoxelManipulator &vmanip; EmergeManager *emerge;
int ystride; int ystride;
v3s16 csize; v3s16 csize;
u32 flags;
u32 blockseed;
v3s16 node_min; v3s16 node_min;
v3s16 node_max; 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_base;
Noise *noise_terrain_higher; Noise *noise_terrain_higher;
Noise *noise_steepness; Noise *noise_steepness;
Noise *noise_height_select; Noise *noise_height_select;
Noise *noise_trees;
Noise *noise_mud; Noise *noise_mud;
Noise *noise_beach; Noise *noise_beach;
Noise *noise_biome; 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; NoiseParams *np_cave;
NoiseParams *np_humidity;
u32 flags; NoiseParams *np_trees;
NoiseParams *np_apple_trees;
float freq_desert; float freq_desert;
float freq_beach; 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(); ~MapgenV6();
void makeChunk(BlockMakeData *data); void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p); int getGroundLevelAtPoint(v2s16 p);
double baseRockLevelFromNoise(v2s16 p); float baseTerrainLevel(float terrain_base, float terrain_higher,
static s16 find_ground_level(VoxelManipulator &vmanip, float steepness, float height_select);
v2s16 p2d, INodeDefManager *ndef); virtual float baseTerrainLevelFromNoise(v2s16 p);
static s16 find_stone_level(VoxelManipulator &vmanip, virtual float baseTerrainLevelFromMap(v2s16 p);
v2s16 p2d, INodeDefManager *ndef); virtual float baseTerrainLevelFromMap(int index);
void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
bool is_apple_tree, INodeDefManager *ndef); s16 find_ground_level(v2s16 p2d);
double tree_amount_2d(u64 seed, v2s16 p); s16 find_stone_level(v2s16 p2d);
bool block_is_underground(u64 seed, v3s16 blockpos); 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); 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); float getHumidity(v2s16 p);
BiomeType get_biome(u64 seed, v2s16 p2d); 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); 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 { struct MapgenFactoryV6 : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) { Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenV6(mgid, (MapgenV6Params *)params); return new MapgenV6(mgid, (MapgenV6Params *)params, emerge);
}; };
MapgenParams *createMapgenParams() { MapgenParams *createMapgenParams() {

@ -107,7 +107,7 @@ u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
{ {
const ContentFeatures &f = nodemgr->get(*this); const ContentFeatures &f = nodemgr->get(*this);
if(f.param_type_2 == CPT2_FACEDIR) if(f.param_type_2 == CPT2_FACEDIR)
return getParam2() & 0x03; return getParam2() & 0x1F;
return 0; return 0;
} }
@ -140,29 +140,131 @@ static std::vector<aabb3f> transformNodeBox(const MapNode &n,
{ {
const std::vector<aabb3f> &fixed = nodebox.fixed; const std::vector<aabb3f> &fixed = nodebox.fixed;
int facedir = n.getFaceDir(nodemgr); int facedir = n.getFaceDir(nodemgr);
u8 axisdir = facedir>>2;
facedir&=0x03;
for(std::vector<aabb3f>::const_iterator for(std::vector<aabb3f>::const_iterator
i = fixed.begin(); i = fixed.begin();
i != fixed.end(); i++) i != fixed.end(); i++)
{ {
aabb3f box = *i; aabb3f box = *i;
if(facedir == 1) switch (axisdir)
{ {
box.MinEdge.rotateXZBy(-90); case 0:
box.MaxEdge.rotateXZBy(-90); if(facedir == 1)
box.repair(); {
} box.MinEdge.rotateXZBy(-90);
else if(facedir == 2) box.MaxEdge.rotateXZBy(-90);
{ }
box.MinEdge.rotateXZBy(180); else if(facedir == 2)
box.MaxEdge.rotateXZBy(180); {
box.repair(); box.MinEdge.rotateXZBy(180);
} box.MaxEdge.rotateXZBy(180);
else if(facedir == 3) }
{ else if(facedir == 3)
box.MinEdge.rotateXZBy(90); {
box.MaxEdge.rotateXZBy(90); box.MinEdge.rotateXZBy(90);
box.repair(); 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); boxes.push_back(box);
} }
} }

@ -45,10 +45,10 @@ void MapSector::deleteBlocks()
m_block_cache = NULL; m_block_cache = NULL;
// Delete all // Delete all
core::map<s16, MapBlock*>::Iterator i = m_blocks.getIterator(); for(std::map<s16, MapBlock*>::iterator i = m_blocks.begin();
for(; i.atEnd() == false; i++) i != m_blocks.end(); ++i)
{ {
delete i.getNode()->getValue(); delete i->second;
} }
// Clear container // Clear container
@ -64,14 +64,14 @@ MapBlock * MapSector::getBlockBuffered(s16 y)
} }
// If block doesn't exist, return NULL // If block doesn't exist, return NULL
core::map<s16, MapBlock*>::Node *n = m_blocks.find(y); std::map<s16, MapBlock*>::iterator n = m_blocks.find(y);
if(n == NULL) if(n == m_blocks.end())
{ {
block = NULL; block = NULL;
} }
// If block exists, return it // If block exists, return it
else{ else{
block = n->getValue(); block = n->second;
} }
// Cache the last result // Cache the last result
@ -101,7 +101,7 @@ MapBlock * MapSector::createBlankBlock(s16 y)
{ {
MapBlock *block = createBlankBlockNoInsert(y); MapBlock *block = createBlankBlockNoInsert(y);
m_blocks.insert(y, block); m_blocks[y] = block;
return block; return block;
} }
@ -119,7 +119,7 @@ void MapSector::insertBlock(MapBlock *block)
assert(p2d == m_pos); assert(p2d == m_pos);
// Insert into container // Insert into container
m_blocks.insert(block_y, block); m_blocks[block_y] = block;
} }
void MapSector::deleteBlock(MapBlock *block) void MapSector::deleteBlock(MapBlock *block)
@ -130,23 +130,18 @@ void MapSector::deleteBlock(MapBlock *block)
m_block_cache = NULL; m_block_cache = NULL;
// Remove from container // Remove from container
m_blocks.remove(block_y); m_blocks.erase(block_y);
// Delete // Delete
delete block; delete block;
} }
void MapSector::getBlocks(core::list<MapBlock*> &dest) void MapSector::getBlocks(std::list<MapBlock*> &dest)
{ {
core::list<MapBlock*> ref_list; for(std::map<s16, MapBlock*>::iterator bi = m_blocks.begin();
bi != m_blocks.end(); ++bi)
core::map<s16, MapBlock*>::Iterator bi;
bi = m_blocks.getIterator();
for(; bi.atEnd() == false; bi++)
{ {
MapBlock *b = bi.getNode()->getValue(); dest.push_back(bi->second);
dest.push_back(b);
} }
} }
@ -189,7 +184,7 @@ ServerMapSector* ServerMapSector::deSerialize(
std::istream &is, std::istream &is,
Map *parent, Map *parent,
v2s16 p2d, v2s16 p2d,
core::map<v2s16, MapSector*> & sectors, std::map<v2s16, MapSector*> & sectors,
IGameDef *gamedef IGameDef *gamedef
) )
{ {
@ -219,22 +214,22 @@ ServerMapSector* ServerMapSector::deSerialize(
ServerMapSector *sector = NULL; 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 " dstream<<"WARNING: deSerializing existent sectors not supported "
"at the moment, because code hasn't been tested." "at the moment, because code hasn't been tested."
<<std::endl; <<std::endl;
MapSector *sector = n->getValue(); MapSector *sector = n->second;
assert(sector->getId() == MAPSECTOR_SERVER); assert(sector->getId() == MAPSECTOR_SERVER);
return (ServerMapSector*)sector; return (ServerMapSector*)sector;
} }
else else
{ {
sector = new ServerMapSector(parent, p2d, gamedef); sector = new ServerMapSector(parent, p2d, gamedef);
sectors.insert(p2d, sector); sectors[p2d] = sector;
} }
/* /*

@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h" #include "irrlichttypes_bloated.h"
#include "exceptions.h" #include "exceptions.h"
#include <ostream> #include <ostream>
#include <map>
#include <list>
class MapBlock; class MapBlock;
class Map; class Map;
@ -60,7 +62,7 @@ public:
void deleteBlock(MapBlock *block); 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. // Always false at the moment, because sector contains no metadata.
bool differs_from_disk; bool differs_from_disk;
@ -68,7 +70,7 @@ public:
protected: protected:
// The pile of MapBlocks // The pile of MapBlocks
core::map<s16, MapBlock*> m_blocks; std::map<s16, MapBlock*> m_blocks;
Map *m_parent; Map *m_parent;
// Position on parent (in MapBlock widths) // Position on parent (in MapBlock widths)
@ -110,7 +112,7 @@ public:
std::istream &is, std::istream &is,
Map *parent, Map *parent,
v2s16 p2d, v2s16 p2d,
core::map<v2s16, MapSector*> & sectors, std::map<v2s16, MapSector*> & sectors,
IGameDef *gamedef IGameDef *gamedef
); );

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h" #include "log.h"
#include "subgame.h" #include "subgame.h"
#include "settings.h" #include "settings.h"
#include "strfnd.h"
std::map<std::string, ModSpec> getModsInPath(std::string path) 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) 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 // Add all world mods and all game mods
addModsInPath(worldpath + DIR_DELIM + "worldmods"); addModsInPath(worldpath + DIR_DELIM + "worldmods");
SubgameSpec gamespec = findWorldSubgame(worldpath);
addModsInPath(gamespec.gamemods_path); addModsInPath(gamespec.gamemods_path);
// check world.mt file for mods explicitely declared to be // 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(); 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); addModsInPathFiltered((*i),exclude_mod_names);
} }

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string> #include <string>
#include <map> #include <map>
#include <exception> #include <exception>
#include <list>
class ModError : public std::exception class ModError : public std::exception
{ {
@ -68,7 +69,6 @@ struct ModSpec
{} {}
}; };
std::map<std::string,ModSpec> getModsInPath(std::string path); std::map<std::string,ModSpec> getModsInPath(std::string path);
// expands modpack contents, but does not replace them. // expands modpack contents, but does not replace them.
@ -140,6 +140,4 @@ private:
}; };
#endif #endif

@ -107,26 +107,31 @@ void NodeBox::deSerialize(std::istream &is)
TileDef 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); os<<serializeString(name);
writeU8(os, animation.type); writeU8(os, animation.type);
writeU16(os, animation.aspect_w); writeU16(os, animation.aspect_w);
writeU16(os, animation.aspect_h); writeU16(os, animation.aspect_h);
writeF1000(os, animation.length); writeF1000(os, animation.length);
if(protocol_version >= 17)
writeU8(os, backface_culling);
} }
void TileDef::deSerialize(std::istream &is) void TileDef::deSerialize(std::istream &is)
{ {
int version = readU8(is); int version = readU8(is);
if(version != 0)
throw SerializationError("unsupported TileDef version");
name = deSerializeString(is); name = deSerializeString(is);
animation.type = (TileAnimationType)readU8(is); animation.type = (TileAnimationType)readU8(is);
animation.aspect_w = readU16(is); animation.aspect_w = readU16(is);
animation.aspect_h = readU16(is); animation.aspect_h = readU16(is);
animation.length = readF1000(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); writeF1000(os, visual_scale);
writeU8(os, 6); writeU8(os, 6);
for(u32 i=0; i<6; i++) for(u32 i=0; i<6; i++)
tiledef[i].serialize(os); tiledef[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT); writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){ 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, alpha);
writeU8(os, post_effect_color.getAlpha()); 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_footstep, os);
serializeSimpleSoundSpec(sound_dig, os); serializeSimpleSoundSpec(sound_dig, os);
serializeSimpleSoundSpec(sound_dug, os); serializeSimpleSoundSpec(sound_dug, os);
writeU8(os, rightclickable);
// Stuff below should be moved to correct place in a version that otherwise changes // Stuff below should be moved to correct place in a version that otherwise changes
// the protocol version // the protocol version
writeU8(os, rightclickable);
} }
void ContentFeatures::deSerialize(std::istream &is) void ContentFeatures::deSerialize(std::istream &is)
@ -331,12 +336,12 @@ void ContentFeatures::deSerialize(std::istream &is)
deSerializeSimpleSoundSpec(sound_footstep, is); deSerializeSimpleSoundSpec(sound_footstep, is);
deSerializeSimpleSoundSpec(sound_dig, is); deSerializeSimpleSoundSpec(sound_dig, is);
deSerializeSimpleSoundSpec(sound_dug, is); deSerializeSimpleSoundSpec(sound_dug, is);
rightclickable = readU8(is);
// If you add anything here, insert it primarily inside the try-catch // If you add anything here, insert it primarily inside the try-catch
// block to not need to increase the version. // block to not need to increase the version.
try{ try{
// Stuff below should be moved to correct place in a version that // Stuff below should be moved to correct place in a version that
// otherwise changes the protocol version // otherwise changes the protocol version
rightclickable = readU8(is);
}catch(SerializationError &e) {}; }catch(SerializationError &e) {};
} }
@ -809,10 +814,10 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version)
writeF1000(os, visual_scale); writeF1000(os, visual_scale);
writeU8(os, 6); writeU8(os, 6);
for(u32 i=0; i<6; i++) for(u32 i=0; i<6; i++)
tiledef[i].serialize(os); tiledef[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT); writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){ 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, alpha);
writeU8(os, post_effect_color.getAlpha()); writeU8(os, post_effect_color.getAlpha());

@ -119,7 +119,7 @@ struct TileDef
animation.length = 1.0; animation.length = 1.0;
} }
void serialize(std::ostream &os) const; void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is); void deSerialize(std::istream &is);
}; };

@ -89,7 +89,7 @@ public:
Noise(NoiseParams *np, int seed, int sx, int sy, int sz); Noise(NoiseParams *np, int seed, int sx, int sy, int sz);
~Noise(); ~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);
void setSize(int sx, int sy, int sz); void setSize(int sx, int sy, int sz);
void setSpreadFactor(v3f spread); void setSpreadFactor(v3f spread);
@ -157,7 +157,7 @@ inline float easeCurve(float t) {
(s) + (np)->seed, (np)->octaves, (np)->persist)) (s) + (np)->seed, (np)->octaves, (np)->persist))
#define NoisePerlin3D(np, x, y, z, s) ((np)->offset + (np)->scale * \ #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)) (float)(z) / (np)->spread.Z, (s) + (np)->seed, (np)->octaves, (np)->persist))
#endif #endif

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h" #include "irrlichttypes_bloated.h"
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <vector>
struct ObjectProperties struct ObjectProperties
{ {
@ -35,8 +36,8 @@ struct ObjectProperties
std::string visual; std::string visual;
std::string mesh; std::string mesh;
v2f visual_size; v2f visual_size;
core::array<std::string> textures; std::vector<std::string> textures;
core::array<video::SColor> colors; std::vector<video::SColor> colors;
v2s16 spritediv; v2s16 spritediv;
v2s16 initial_sprite_basepos; v2s16 initial_sprite_basepos;
bool is_visible; bool is_visible;

@ -32,19 +32,34 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientmap.h" #include "clientmap.h"
#include "mapnode.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( Particle::Particle(
IGameDef *gamedef, IGameDef *gamedef,
scene::ISceneManager* smgr, scene::ISceneManager* smgr,
LocalPlayer *player, LocalPlayer *player,
s32 id, ClientEnvironment &env,
v3f pos, v3f pos,
v3f velocity, v3f velocity,
v3f acceleration, v3f acceleration,
float expirationtime, float expirationtime,
float size, float size,
bool collisiondetection,
AtlasPointer ap AtlasPointer ap
): ):
scene::ISceneNode(smgr->getRootSceneNode(), smgr, id) scene::ISceneNode(smgr->getRootSceneNode(), smgr)
{ {
// Misc // Misc
m_gamedef = gamedef; m_gamedef = gamedef;
@ -57,7 +72,6 @@ Particle::Particle(
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
m_material.setTexture(0, ap.atlas); m_material.setTexture(0, ap.atlas);
m_ap = ap; m_ap = ap;
m_light = 0;
// Particle related // Particle related
@ -68,10 +82,20 @@ Particle::Particle(
m_time = 0; m_time = 0;
m_player = player; m_player = player;
m_size = size; m_size = size;
m_collisiondetection = collisiondetection;
// Irrlicht stuff (TODO) // Irrlicht stuff
m_collisionbox = core::aabbox3d<f32>(-size/2,-size/2,-size/2,size/2,size/2,size/2); m_collisionbox = core::aabbox3d<f32>
(-size/2,-size/2,-size/2,size/2,size/2,size/2);
this->setAutomaticCulling(scene::EAC_OFF); this->setAutomaticCulling(scene::EAC_OFF);
// Init lighting
updateLight(env);
// Init model
updateVertices();
all_particles.push_back(this);
} }
Particle::~Particle() Particle::~Particle()
@ -82,8 +106,10 @@ void Particle::OnRegisterSceneNode()
{ {
if (IsVisible) if (IsVisible)
{ {
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); SceneManager->registerNodeForRendering
SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID); (this, scene::ESNRP_TRANSPARENT);
SceneManager->registerNodeForRendering
(this, scene::ESNRP_SOLID);
} }
ISceneNode::OnRegisterSceneNode(); ISceneNode::OnRegisterSceneNode();
@ -96,45 +122,45 @@ void Particle::render()
video::IVideoDriver* driver = SceneManager->getVideoDriver(); video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setMaterial(m_material); driver->setMaterial(m_material);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); 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}; u16 indices[] = {0,1,2, 2,3,0};
driver->drawVertexPrimitiveList(vertices, 4, indices, 2, driver->drawVertexPrimitiveList(m_vertices, 4,
video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT); indices, 2, video::EVT_STANDARD,
scene::EPT_TRIANGLES, video::EIT_16BIT);
} }
void Particle::step(float dtime, ClientEnvironment &env) 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; 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 // Update lighting
updateLight(env);
// Update model
updateVertices();
}
void Particle::updateLight(ClientEnvironment &env)
{
u8 light = 0; u8 light = 0;
try{ try{
v3s16 p = v3s16( v3s16 p = v3s16(
@ -151,11 +177,37 @@ void Particle::step(float dtime, ClientEnvironment &env)
m_light = decode_light(light); 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) 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()) 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 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 // add a particle of a node
// used by digging and punching particles // 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 // Texture
u8 texid = myrand_range(0,5); 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); ap.pos.Y = ap.y0() + (y1 - ap.y0()) * ((rand()%64)/64.-texsize);
// Physics // 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 acceleration(0,-9,0);
v3f particlepos = v3f( v3f particlepos = v3f(
(f32)pos.X+rand()%100/200.-0.25, (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 (f32)pos.Z+rand()%100/200.-0.25
); );
Particle *particle = new Particle( new Particle(
gamedef, gamedef,
smgr, smgr,
player, player,
0, env,
particlepos, particlepos,
velocity, velocity,
acceleration, acceleration,
rand()%100/100., // expiration time rand()%100/100., // expiration time
visual_size, visual_size,
true,
ap); 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);
}
} }

@ -35,12 +35,13 @@ class Particle : public scene::ISceneNode
IGameDef* gamedef, IGameDef* gamedef,
scene::ISceneManager* mgr, scene::ISceneManager* mgr,
LocalPlayer *player, LocalPlayer *player,
s32 id, ClientEnvironment &env,
v3f pos, v3f pos,
v3f velocity, v3f velocity,
v3f acceleration, v3f acceleration,
float expirationtime, float expirationtime,
float size, float size,
bool collisiondetection,
AtlasPointer texture AtlasPointer texture
); );
~Particle(); ~Particle();
@ -69,6 +70,10 @@ class Particle : public scene::ISceneNode
{ return m_expiration < m_time; } { return m_expiration < m_time; }
private: private:
void updateLight(ClientEnvironment &env);
void updateVertices();
video::S3DVertex m_vertices[4];
float m_time; float m_time;
float m_expiration; float m_expiration;
@ -87,12 +92,71 @@ private:
float m_size; float m_size;
AtlasPointer m_ap; AtlasPointer m_ap;
u8 m_light; 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 allparticles_step (float dtime, ClientEnvironment &env);
void allparticlespawners_step (float dtime, ClientEnvironment &env);
void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]); void delete_particlespawner (u32 id);
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]); void clear_particles ();
void addNodeParticle(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[]);
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
const TileSpec tiles[]);
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
const TileSpec tiles[]);
#endif #endif

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h" // u32 #include "irrlichttypes.h" // u32
#include "debug.h" #include "debug.h"
#include "constants.h" #include "constants.h"
#include "gettime.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#define SWPRINTF_CHARSTRING L"%S" #define SWPRINTF_CHARSTRING L"%S"
@ -153,18 +154,65 @@ bool threadSetPriority(threadid_t tid, int prio);
*/ */
#ifdef _WIN32 // Windows #ifdef _WIN32 // Windows
#include <windows.h> #include <windows.h>
inline u32 getTimeS()
{
return GetTickCount() / 1000;
}
inline u32 getTimeMs() inline u32 getTimeMs()
{ {
return GetTickCount(); 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 #else // Posix
#include <sys/time.h> #include <sys/time.h>
#include <time.h>
inline u32 getTimeS()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec;
}
inline u32 getTimeMs() inline u32 getTimeMs()
{ {
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000; 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> /*#include <sys/timeb.h>
inline u32 getTimeMs() inline u32 getTimeMs()
{ {
@ -174,6 +222,22 @@ bool threadSetPriority(threadid_t tid, int prio);
}*/ }*/
#endif #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 } // namespace porting
#endif // PORTING_HEADER #endif // PORTING_HEADER

@ -45,21 +45,21 @@ public:
JMutexAutoLock lock(m_mutex); JMutexAutoLock lock(m_mutex);
{ {
/* No average shall have been used; mark add used as -2 */ /* No average shall have been used; mark add used as -2 */
core::map<std::string, int>::Node *n = m_avgcounts.find(name); std::map<std::string, int>::iterator n = m_avgcounts.find(name);
if(n == NULL) if(n == m_avgcounts.end())
m_avgcounts[name] = -2; m_avgcounts[name] = -2;
else{ else{
if(n->getValue() == -1) if(n->second == -1)
n->setValue(-2); n->second = -2;
assert(n->getValue() == -2); assert(n->second == -2);
} }
} }
{ {
core::map<std::string, float>::Node *n = m_data.find(name); std::map<std::string, float>::iterator n = m_data.find(name);
if(n == NULL) if(n == m_data.end())
m_data[name] = value; m_data[name] = value;
else else
n->setValue(n->getValue() + value); n->second += value;
} }
} }
@ -67,35 +67,32 @@ public:
{ {
JMutexAutoLock lock(m_mutex); JMutexAutoLock lock(m_mutex);
{ {
core::map<std::string, int>::Node *n = m_avgcounts.find(name); std::map<std::string, int>::iterator n = m_avgcounts.find(name);
if(n == NULL) if(n == m_avgcounts.end())
m_avgcounts[name] = 1; m_avgcounts[name] = 1;
else{ else{
/* No add shall have been used */ /* No add shall have been used */
assert(n->getValue() != -2); assert(n->second != -2);
if(n->getValue() <= 0) n->second = (std::max)(n->second, 0) + 1;
n->setValue(1);
else
n->setValue(n->getValue() + 1);
} }
} }
{ {
core::map<std::string, float>::Node *n = m_data.find(name); std::map<std::string, float>::iterator n = m_data.find(name);
if(n == NULL) if(n == m_data.end())
m_data[name] = value; m_data[name] = value;
else else
n->setValue(n->getValue() + value); n->second += value;
} }
} }
void clear() void clear()
{ {
JMutexAutoLock lock(m_mutex); JMutexAutoLock lock(m_mutex);
for(core::map<std::string, float>::Iterator for(std::map<std::string, float>::iterator
i = m_data.getIterator(); i = m_data.begin();
i.atEnd() == false; i++) i != m_data.end(); ++i)
{ {
i.getNode()->setValue(0); i->second = 0;
} }
m_avgcounts.clear(); m_avgcounts.clear();
} }
@ -112,9 +109,9 @@ public:
u32 minindex, maxindex; u32 minindex, maxindex;
paging(m_data.size(), page, pagecount, minindex, maxindex); paging(m_data.size(), page, pagecount, minindex, maxindex);
for(core::map<std::string, float>::Iterator for(std::map<std::string, float>::iterator
i = m_data.getIterator(); i = m_data.begin();
i.atEnd() == false; i++) i != m_data.end(); ++i)
{ {
if(maxindex == 0) if(maxindex == 0)
break; break;
@ -126,12 +123,12 @@ public:
continue; continue;
} }
std::string name = i.getNode()->getKey(); std::string name = i->first;
int avgcount = 1; int avgcount = 1;
core::map<std::string, int>::Node *n = m_avgcounts.find(name); std::map<std::string, int>::iterator n = m_avgcounts.find(name);
if(n){ if(n != m_avgcounts.end()){
if(n->getValue() >= 1) if(n->second >= 1)
avgcount = n->getValue(); avgcount = n->second;
} }
o<<" "<<name<<": "; o<<" "<<name<<": ";
s32 clampsize = 40; s32 clampsize = 40;
@ -143,7 +140,7 @@ public:
else else
o<<" "; o<<" ";
} }
o<<(i.getNode()->getValue() / avgcount); o<<(i->second / avgcount);
o<<std::endl; o<<std::endl;
} }
} }
@ -169,8 +166,8 @@ public:
private: private:
JMutex m_mutex; JMutex m_mutex;
core::map<std::string, float> m_data; std::map<std::string, float> m_data;
core::map<std::string, int> m_avgcounts; std::map<std::string, int> m_avgcounts;
std::map<std::string, float> m_graphvalues; std::map<std::string, float> m_graphvalues;
}; };

File diff suppressed because it is too large Load Diff

@ -20,41 +20,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef SCRIPTAPI_HEADER #ifndef SCRIPTAPI_HEADER
#define SCRIPTAPI_HEADER #define SCRIPTAPI_HEADER
#include "irrlichttypes_bloated.h"
#include <string> #include <string>
#include "mapnode.h"
#include <set> #include <set>
#include <map> #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 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); void scriptapi_export(lua_State *L, Server *server);
bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath, bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
const std::string &modname); 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 // Returns true if script handled message
bool scriptapi_on_chat_message(lua_State *L, const std::string &name, bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
const std::string &message); 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 */ /* server */
void scriptapi_on_shutdown(lua_State *L); 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::string &formname,
const std::map<std::string, std::string> &fields); 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 #endif

311
src/scriptapi_common.cpp Normal file

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

112
src/scriptapi_common.h Normal file

@ -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_ */

322
src/scriptapi_content.cpp Normal file

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

37
src/scriptapi_content.h Normal file

@ -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_ */

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