Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2013-06-01 13:18:52 +02:00
commit 1dfc2e02b3
138 changed files with 7034 additions and 6000 deletions

5
.gitignore vendored

@ -32,6 +32,11 @@ src/CMakeFiles/*
src/Makefile src/Makefile
src/cmake_config.h src/cmake_config.h
src/cmake_install.cmake src/cmake_install.cmake
src/script/CMakeFiles/*
src/script/common/CMakeFiles/*
src/script/cpp_api/CMakeFiles/*
src/script/lua_api/CMakeFiles/*
src/util/CMakeFiles/*
src/jthread/CMakeFiles/* src/jthread/CMakeFiles/*
src/jthread/Makefile src/jthread/Makefile
src/jthread/cmake_config.h src/jthread/cmake_config.h

@ -133,11 +133,6 @@ 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/")
@ -145,24 +140,12 @@ if(EXISTS ${MINETEST_GAME_SOURCE} AND IS_DIRECTORY ${MINETEST_GAME_SOURCE})
install(DIRECTORY ${MINETEST_GAME_SOURCE}/mods DESTINATION "${SHAREDIR}/games/minetest_game") install(DIRECTORY ${MINETEST_GAME_SOURCE}/mods DESTINATION "${SHAREDIR}/games/minetest_game")
install(DIRECTORY ${MINETEST_GAME_SOURCE}/menu DESTINATION "${SHAREDIR}/games/minetest_game") install(DIRECTORY ${MINETEST_GAME_SOURCE}/menu DESTINATION "${SHAREDIR}/games/minetest_game")
endif() endif()
set(MINETEST_BUILD_GAME_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/games/build")
if(EXISTS ${MINETEST_BUILD_GAME_SOURCE} AND IS_DIRECTORY ${MINETEST_BUILD_GAME_SOURCE})
install(FILES ${MINETEST_BUILD_GAME_SOURCE}/game.conf DESTINATION "${SHAREDIR}/games/build/")
install(FILES ${MINETEST_BUILD_GAME_SOURCE}/README.txt DESTINATION "${SHAREDIR}/games/build/")
install(DIRECTORY ${MINETEST_BUILD_GAME_SOURCE}/mods DESTINATION "${SHAREDIR}/games/build")
endif()
set(MINETEST_SURVIVAL_GAME_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/games/survival")
if(EXISTS ${MINETEST_SURVIVAL_GAME_SOURCE} AND IS_DIRECTORY ${MINETEST_SURVIVAL_GAME_SOURCE})
install(FILES ${MINETEST_SURVIVAL_GAME_SOURCE}/game.conf DESTINATION "${SHAREDIR}/games/survival/")
install(FILES ${MINETEST_SURVIVAL_GAME_SOURCE}/README.txt DESTINATION "${SHAREDIR}/games/survival/")
install(DIRECTORY ${MINETEST_SURVIVAL_GAME_SOURCE}/mods DESTINATION "${SHAREDIR}/games/survival")
endif()
if(BUILD_CLIENT) if(BUILD_CLIENT)
#install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/sounds/base/pack" DESTINATION "${SHAREDIR}/sounds/base") #install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/sounds/base/pack" DESTINATION "${SHAREDIR}/sounds/base")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/textures/base/pack" DESTINATION "${SHAREDIR}/textures/base") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/textures/base/pack" DESTINATION "${SHAREDIR}/textures/base")
endif() endif()
if(RUN_IN_PLACE) if(RUN_IN_PLACE)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/mods/minetest/mods_here.txt" DESTINATION "${SHAREDIR}/mods/minetest") install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/mods/mods_here.txt" DESTINATION "${SHAREDIR}/mods")
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/all/textures_here.txt" DESTINATION "${SHAREDIR}/textures/all") install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/all/textures_here.txt" DESTINATION "${SHAREDIR}/textures/all")
endif() endif()

@ -9,10 +9,9 @@ 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 these projects too: contained, you probably want to download the minetest_game project too:
https://github.com/minetest/common/
https://github.com/minetest/minetest_game/ https://github.com/minetest/minetest_game/
See the README.txt in them. See the README.txt in it.
Further documentation Further documentation
---------------------- ----------------------
@ -92,13 +91,6 @@ $ 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 minetest_game.tar.gz $ wget https://github.com/minetest/minetest_game/tarball/master -O minetest_game.tar.gz
@ -124,7 +116,7 @@ $ ./minetest
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 common and minetest_game. - In addition to minetest, you need to download 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:
@ -267,6 +259,20 @@ distribution.
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
http://creativecommons.org/licenses/by-sa/3.0/ http://creativecommons.org/licenses/by-sa/3.0/
Authors of media files
-----------------------
Everything not listed in here:
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
BlockMen:
textures/base/pack/menuheader.png
erlehmann:
misc/minetest-icon-24x24.png
misc/minetest-icon.ico
misc/minetest-icon.svg
textures/base/pack/logo.png
License of Minetest source code License of Minetest source code
------------------------------- -------------------------------

@ -261,7 +261,7 @@ minetest.register_chatcommand("teleport", {
} }
for _, d in ipairs(tries) do for _, d in ipairs(tries) do
local p = {x = pos.x+d.x, y = pos.y+d.y, z = pos.z+d.z} local p = {x = pos.x+d.x, y = pos.y+d.y, z = pos.z+d.z}
local n = minetest.env:get_node(p) local n = minetest.get_node(p)
if not minetest.registered_nodes[n.name].walkable then if not minetest.registered_nodes[n.name].walkable then
return p, true return p, true
end end
@ -272,7 +272,7 @@ minetest.register_chatcommand("teleport", {
local teleportee = nil local teleportee = nil
local p = {} local p = {}
p.x, p.y, p.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$") p.x, p.y, p.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
teleportee = minetest.env:get_player_by_name(name) teleportee = minetest.get_player_by_name(name)
if teleportee and p.x and p.y and p.z then if teleportee and p.x and p.y and p.z then
minetest.chat_send_player(name, "Teleporting to ("..p.x..", "..p.y..", "..p.z..")") minetest.chat_send_player(name, "Teleporting to ("..p.x..", "..p.y..", "..p.z..")")
teleportee:setpos(p) teleportee:setpos(p)
@ -283,9 +283,9 @@ minetest.register_chatcommand("teleport", {
local p = nil local p = nil
local target_name = nil local target_name = nil
target_name = string.match(param, "^([^ ]+)$") target_name = string.match(param, "^([^ ]+)$")
teleportee = minetest.env:get_player_by_name(name) teleportee = minetest.get_player_by_name(name)
if target_name then if target_name then
local target = minetest.env:get_player_by_name(target_name) local target = minetest.get_player_by_name(target_name)
if target then if target then
p = target:getpos() p = target:getpos()
end end
@ -303,7 +303,7 @@ minetest.register_chatcommand("teleport", {
local teleportee_name = nil local teleportee_name = nil
teleportee_name, p.x, p.y, p.z = string.match(param, "^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$") teleportee_name, p.x, p.y, p.z = string.match(param, "^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
if teleportee_name then if teleportee_name then
teleportee = minetest.env:get_player_by_name(teleportee_name) teleportee = minetest.get_player_by_name(teleportee_name)
end end
if teleportee and p.x and p.y and p.z then if teleportee and p.x and p.y and p.z then
minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to ("..p.x..", "..p.y..", "..p.z..")") minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to ("..p.x..", "..p.y..", "..p.z..")")
@ -317,10 +317,10 @@ minetest.register_chatcommand("teleport", {
local target_name = nil local target_name = nil
teleportee_name, target_name = string.match(param, "^([^ ]+) +([^ ]+)$") teleportee_name, target_name = string.match(param, "^([^ ]+) +([^ ]+)$")
if teleportee_name then if teleportee_name then
teleportee = minetest.env:get_player_by_name(teleportee_name) teleportee = minetest.get_player_by_name(teleportee_name)
end end
if target_name then if target_name then
local target = minetest.env:get_player_by_name(target_name) local target = minetest.get_player_by_name(target_name)
if target then if target then
p = target:getpos() p = target:getpos()
end end
@ -402,7 +402,7 @@ local function handle_give_command(cmd, giver, receiver, stackstring)
minetest.chat_send_player(giver, 'error: cannot give an unknown item') minetest.chat_send_player(giver, 'error: cannot give an unknown item')
return return
end end
local receiverref = minetest.env:get_player_by_name(receiver) local receiverref = minetest.get_player_by_name(receiver)
if receiverref == nil then if receiverref == nil then
minetest.chat_send_player(giver, receiver..' is not a known player') minetest.chat_send_player(giver, receiver..' is not a known player')
return return
@ -466,14 +466,14 @@ minetest.register_chatcommand("spawnentity", {
return return
end end
print('/spawnentity invoked, entityname="'..entityname..'"') print('/spawnentity invoked, entityname="'..entityname..'"')
local player = minetest.env:get_player_by_name(name) local player = minetest.get_player_by_name(name)
if player == nil then if player == nil then
print("Unable to spawn entity, player is nil") print("Unable to spawn entity, player is nil")
return true -- Handled chat message return true -- Handled chat message
end end
local p = player:getpos() local p = player:getpos()
p.y = p.y + 1 p.y = p.y + 1
minetest.env:add_entity(p, entityname) minetest.add_entity(p, entityname)
minetest.chat_send_player(name, '"'..entityname minetest.chat_send_player(name, '"'..entityname
..'" spawned.'); ..'" spawned.');
end, end,
@ -483,7 +483,7 @@ minetest.register_chatcommand("pulverize", {
description = "delete item in hand", description = "delete item in hand",
privs = {}, privs = {},
func = function(name, param) func = function(name, param)
local player = minetest.env:get_player_by_name(name) local player = minetest.get_player_by_name(name)
if player == nil then if player == nil then
print("Unable to pulverize, player is nil") print("Unable to pulverize, player is nil")
return true -- Handled chat message return true -- Handled chat message
@ -533,7 +533,7 @@ minetest.register_chatcommand("rollback_check", {
if act_p.x ~= pos.x or act_p.y ~= pos.y or act_p.z ~= pos.z then if act_p.x ~= pos.x or act_p.y ~= pos.y or act_p.z ~= pos.z then
nodedesc = minetest.pos_to_string(act_p) nodedesc = minetest.pos_to_string(act_p)
end end
local nodename = minetest.env:get_node(act_p).name local nodename = minetest.get_node(act_p).name
minetest.chat_send_player(name, "Last actor on "..nodedesc.. minetest.chat_send_player(name, "Last actor on "..nodedesc..
" was "..actor..", "..dump(act_seconds).. " was "..actor..", "..dump(act_seconds)..
"s ago (node is now "..nodename..")") "s ago (node is now "..nodename..")")
@ -598,7 +598,7 @@ minetest.register_chatcommand("time", {
if newtime == nil then if newtime == nil then
minetest.chat_send_player(name, "Invalid time") minetest.chat_send_player(name, "Invalid time")
else else
minetest.env:set_timeofday((newtime % 24000) / 24000) minetest.set_timeofday((newtime % 24000) / 24000)
minetest.chat_send_player(name, "Time of day changed.") minetest.chat_send_player(name, "Time of day changed.")
minetest.log("action", name .. " sets time " .. newtime) minetest.log("action", name .. " sets time " .. newtime)
end end
@ -625,7 +625,7 @@ minetest.register_chatcommand("ban", {
minetest.chat_send_player(name, "Ban list: " .. minetest.get_ban_list()) minetest.chat_send_player(name, "Ban list: " .. minetest.get_ban_list())
return return
end end
if not minetest.env:get_player_by_name(param) then if not minetest.get_player_by_name(param) then
minetest.chat_send_player(name, "No such player") minetest.chat_send_player(name, "No such player")
return return
end end
@ -660,7 +660,7 @@ minetest.register_chatcommand("clearobjects", {
func = function(name, param) func = function(name, param)
minetest.log("action", name .. " clears all objects") minetest.log("action", name .. " clears all objects")
minetest.chat_send_all("Clearing all objects. This may take long. You may experience a timeout. (by " .. name .. ")") minetest.chat_send_all("Clearing all objects. This may take long. You may experience a timeout. (by " .. name .. ")")
minetest.env:clear_objects() minetest.clear_objects()
minetest.log("action", "object clearing done") minetest.log("action", "object clearing done")
minetest.chat_send_all("*** Cleared all objects.") minetest.chat_send_all("*** Cleared all objects.")
end, end,
@ -673,7 +673,7 @@ minetest.register_chatcommand("msg", {
func = function(name, param) func = function(name, param)
local found, _, sendto, message = param:find("^([^%s]+)%s(.+)$") local found, _, sendto, message = param:find("^([^%s]+)%s(.+)$")
if found then if found then
if minetest.env:get_player_by_name(sendto) then if minetest.get_player_by_name(sendto) then
minetest.log("action", "PM from "..name.." to "..sendto..": "..message) minetest.log("action", "PM from "..name.." to "..sendto..": "..message)
minetest.chat_send_player(sendto, "PM from "..name..": "..message, false) minetest.chat_send_player(sendto, "PM from "..name..": "..message, false)
minetest.chat_send_player(name, "Message sent") minetest.chat_send_player(name, "Message sent")

@ -24,3 +24,25 @@ minetest.add_to_creative_inventory = function(itemstring)
minetest.log('info', "WARNING: minetest.add_to_creative_inventory: This function is deprecated and does nothing.") minetest.log('info', "WARNING: minetest.add_to_creative_inventory: This function is deprecated and does nothing.")
end end
--
-- EnvRef
--
minetest.env = {}
local envref_deprecation_message_printed = false
setmetatable(minetest.env, {
__index = function(table, key)
if not envref_deprecation_message_printed then
minetest.log("info", "WARNING: minetest.env:[...] is deprecated and should be replaced with minetest.[...]")
envref_deprecation_message_printed = true
end
local func = minetest[key]
if type(func) == "function" then
rawset(table, key, function(self, ...)
return func(unpack({...}))
end)
else
rawset(table, key, nil)
end
return rawget(table, key)
end
})

@ -53,27 +53,27 @@ minetest.register_entity("__builtin:falling_node", {
-- Turn to actual sand when collides to ground or just move -- Turn to actual sand when collides to ground or just move
local pos = self.object:getpos() local pos = self.object:getpos()
local bcp = {x=pos.x, y=pos.y-0.7, z=pos.z} -- Position of bottom center point local bcp = {x=pos.x, y=pos.y-0.7, z=pos.z} -- Position of bottom center point
local bcn = minetest.env:get_node(bcp) local bcn = minetest.get_node(bcp)
-- 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 if minetest.registered_nodes[bcn.name].buildable_to then
minetest.env:remove_node(bcp) minetest.remove_node(bcp)
return return
end 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.get_node(np)
-- If it's not air or liquid, remove node and replace it with -- If it's not air or liquid, remove node and replace it with
-- it's drops -- it's drops
if n2.name ~= "air" and (not minetest.registered_nodes[n2.name] or if n2.name ~= "air" and (not minetest.registered_nodes[n2.name] or
minetest.registered_nodes[n2.name].liquidtype == "none") then minetest.registered_nodes[n2.name].liquidtype == "none") then
local drops = minetest.get_node_drops(n2.name, "") local drops = minetest.get_node_drops(n2.name, "")
minetest.env:remove_node(np) minetest.remove_node(np)
-- Add dropped items -- Add dropped items
local _, dropped_item local _, dropped_item
for _, dropped_item in ipairs(drops) do for _, dropped_item in ipairs(drops) do
minetest.env:add_item(np, dropped_item) minetest.add_item(np, dropped_item)
end end
-- Run script hook -- Run script hook
local _, callback local _, callback
@ -82,7 +82,7 @@ minetest.register_entity("__builtin:falling_node", {
end end
end end
-- Create node and remove entity -- Create node and remove entity
minetest.env:add_node(np, {name=self.nodename}) minetest.add_node(np, {name=self.nodename})
self.object:remove() self.object:remove()
nodeupdate(np) nodeupdate(np)
else else
@ -92,20 +92,20 @@ minetest.register_entity("__builtin:falling_node", {
}) })
function spawn_falling_node(p, nodename) function spawn_falling_node(p, nodename)
obj = minetest.env:add_entity(p, "__builtin:falling_node") obj = minetest.add_entity(p, "__builtin:falling_node")
obj:get_luaentity():set_node(nodename) obj:get_luaentity():set_node(nodename)
end end
function drop_attached_node(p) function drop_attached_node(p)
local nn = minetest.env:get_node(p).name local nn = minetest.get_node(p).name
minetest.env:remove_node(p) minetest.remove_node(p)
for _,item in ipairs(minetest.get_node_drops(nn, "")) do for _,item in ipairs(minetest.get_node_drops(nn, "")) do
local pos = { local pos = {
x = p.x + math.random()/2 - 0.25, x = p.x + math.random()/2 - 0.25,
y = p.y + math.random()/2 - 0.25, y = p.y + math.random()/2 - 0.25,
z = p.z + math.random()/2 - 0.25, z = p.z + math.random()/2 - 0.25,
} }
minetest.env:add_item(pos, item) minetest.add_item(pos, item)
end end
end end
@ -130,7 +130,7 @@ function check_attached_node(p, n)
d.y = -1 d.y = -1
end end
local p2 = {x=p.x+d.x, y=p.y+d.y, z=p.z+d.z} local p2 = {x=p.x+d.x, y=p.y+d.y, z=p.z+d.z}
local nn = minetest.env:get_node(p2).name local nn = minetest.get_node(p2).name
local def2 = minetest.registered_nodes[nn] local def2 = minetest.registered_nodes[nn]
if def2 and not def2.walkable then if def2 and not def2.walkable then
return false return false
@ -143,10 +143,10 @@ end
-- --
function nodeupdate_single(p, delay) function nodeupdate_single(p, delay)
n = minetest.env:get_node(p) n = minetest.get_node(p)
if minetest.get_node_group(n.name, "falling_node") ~= 0 then if minetest.get_node_group(n.name, "falling_node") ~= 0 then
p_bottom = {x=p.x, y=p.y-1, z=p.z} p_bottom = {x=p.x, y=p.y-1, z=p.z}
n_bottom = minetest.env:get_node(p_bottom) n_bottom = minetest.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 or (not minetest.registered_nodes[n_bottom.name].walkable or
@ -154,7 +154,7 @@ function nodeupdate_single(p, delay)
if delay then if delay then
minetest.after(0.1, nodeupdate_single, {x=p.x, y=p.y, z=p.z}, false) minetest.after(0.1, nodeupdate_single, {x=p.x, y=p.y, z=p.z}, false)
else else
minetest.env:remove_node(p) minetest.remove_node(p)
spawn_falling_node(p, n.name) spawn_falling_node(p, n.name)
nodeupdate(p) nodeupdate(p)
end end

@ -129,9 +129,9 @@ 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_or_nil(under) local oldnode_under = minetest.get_node_or_nil(under)
local above = pointed_thing.above local above = pointed_thing.above
local oldnode_above = minetest.env:get_node_or_nil(above) local oldnode_above = minetest.get_node_or_nil(above)
if not oldnode_under or not oldnode_above then if not oldnode_under or not oldnode_above then
minetest.log("info", placer:get_player_name() .. " tried to place" minetest.log("info", placer:get_player_name() .. " tried to place"
@ -163,7 +163,7 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
minetest.log("action", placer:get_player_name() .. " places node " minetest.log("action", placer:get_player_name() .. " places node "
.. def.name .. " at " .. minetest.pos_to_string(place_to)) .. def.name .. " at " .. minetest.pos_to_string(place_to))
local oldnode = minetest.env:get_node(place_to) local oldnode = minetest.get_node(place_to)
local newnode = {name = def.name, param1 = 0, param2 = 0} local newnode = {name = def.name, param1 = 0, param2 = 0}
-- Calculate direction for wall mounted stuff like torches and signs -- Calculate direction for wall mounted stuff like torches and signs
@ -197,7 +197,7 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
end end
-- Add node and update -- Add node and update
minetest.env:add_node(place_to, newnode) minetest.add_node(place_to, newnode)
local take_item = true local take_item = true
@ -232,7 +232,7 @@ function minetest.item_place_object(itemstack, placer, pointed_thing)
local pos = minetest.get_pointed_thing_position(pointed_thing, true) local pos = minetest.get_pointed_thing_position(pointed_thing, true)
if pos ~= nil then if pos ~= nil then
local item = itemstack:take_item() local item = itemstack:take_item()
minetest.env:add_item(pos, item) minetest.add_item(pos, item)
end end
return itemstack return itemstack
end end
@ -241,7 +241,7 @@ function minetest.item_place(itemstack, placer, pointed_thing)
-- Call on_rightclick if the pointed node defines it -- Call on_rightclick if the pointed node defines it
if pointed_thing.type == "node" and placer and if pointed_thing.type == "node" and placer and
not placer:get_player_control().sneak then not placer:get_player_control().sneak then
local n = minetest.env:get_node(pointed_thing.under) local n = minetest.get_node(pointed_thing.under)
local nn = n.name local nn = n.name
if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].on_rightclick then if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].on_rightclick then
return minetest.registered_nodes[nn].on_rightclick(pointed_thing.under, n, placer, itemstack) or itemstack return minetest.registered_nodes[nn].on_rightclick(pointed_thing.under, n, placer, itemstack) or itemstack
@ -258,7 +258,7 @@ function minetest.item_drop(itemstack, dropper, pos)
if dropper.get_player_name then if dropper.get_player_name then
local v = dropper:get_look_dir() local v = dropper:get_look_dir()
local p = {x=pos.x+v.x, y=pos.y+1.5+v.y, z=pos.z+v.z} local p = {x=pos.x+v.x, y=pos.y+1.5+v.y, z=pos.z+v.z}
local obj = minetest.env:add_item(p, itemstack) local obj = minetest.add_item(p, itemstack)
if obj then if obj then
v.x = v.x*2 v.x = v.x*2
v.y = v.y*2 + 1 v.y = v.y*2 + 1
@ -266,7 +266,7 @@ function minetest.item_drop(itemstack, dropper, pos)
obj:setvelocity(v) obj:setvelocity(v)
end end
else else
minetest.env:add_item(pos, itemstack) minetest.add_item(pos, itemstack)
end end
return ItemStack("") return ItemStack("")
end end
@ -304,7 +304,7 @@ function minetest.handle_node_drops(pos, drops, digger)
y = pos.y + math.random()/2-0.25, y = pos.y + math.random()/2-0.25,
z = pos.z + math.random()/2-0.25, z = pos.z + math.random()/2-0.25,
} }
minetest.env:add_item(p, left) minetest.add_item(p, left)
end end
end end
end end
@ -340,11 +340,11 @@ function minetest.node_dig(pos, node, digger)
local oldmetadata = nil local oldmetadata = nil
if def.after_dig_node then if def.after_dig_node then
oldmetadata = minetest.env:get_meta(pos):to_table() oldmetadata = minetest.get_meta(pos):to_table()
end end
-- Remove node and update -- Remove node and update
minetest.env:remove_node(pos) minetest.remove_node(pos)
-- Run callback -- Run callback
if def.after_dig_node then if def.after_dig_node then

@ -3,7 +3,7 @@
function minetest.spawn_item(pos, item) function minetest.spawn_item(pos, item)
-- Take item in any format -- Take item in any format
local stack = ItemStack(item) local stack = ItemStack(item)
local obj = minetest.env:add_entity(pos, "__builtin:item") local obj = minetest.add_entity(pos, "__builtin:item")
obj:get_luaentity():set_item(stack:to_string()) obj:get_luaentity():set_item(stack:to_string())
return obj return obj
end end
@ -83,7 +83,7 @@ minetest.register_entity("__builtin:item", {
on_step = function(self, dtime) on_step = function(self, dtime)
local p = self.object:getpos() local p = self.object:getpos()
p.y = p.y - 0.3 p.y = p.y - 0.3
local nn = minetest.env:get_node(p).name local nn = minetest.get_node(p).name
-- If node is not registered or node is walkably solid and resting on nodebox -- If node is not registered or node is walkably solid and resting on nodebox
local v = self.object:getvelocity() local v = self.object:getvelocity()
if not minetest.registered_nodes[nn] or minetest.registered_nodes[nn].walkable and v.y == 0 then if not minetest.registered_nodes[nn] or minetest.registered_nodes[nn].walkable and v.y == 0 then

@ -43,7 +43,7 @@ end
function minetest.get_connected_players() function minetest.get_connected_players()
-- This could be optimized a bit, but leave that for later -- This could be optimized a bit, but leave that for later
local list = {} local list = {}
for _, obj in pairs(minetest.env:get_objects_inside_radius({x=0,y=0,z=0}, 1000000)) do for _, obj in pairs(minetest.get_objects_inside_radius({x=0,y=0,z=0}, 1000000)) do
if obj:is_player() then if obj:is_player() then
table.insert(list, obj) table.insert(list, obj)
end end

@ -50,12 +50,8 @@ where gameid is unique to each game.
The game directory contains the file game.conf, which contains these fields: The game directory contains the file game.conf, which contains these fields:
name = <Human-readable full name of the game> name = <Human-readable full name of the game>
common_mods = <Comma-separated list of common mods>
eg. eg.
name = Minetest 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 The game directory can contain the file minetest.conf, which will be used
to set default settings when running the particular game. to set default settings when running the particular game.
@ -64,9 +60,9 @@ Mod load path
------------- -------------
Generic: Generic:
$path_share/games/gameid/mods/ $path_share/games/gameid/mods/
$path_share/mods/gameid/ $path_share/mods/
$path_user/games/gameid/mods/ $path_user/games/gameid/mods/
$path_user/mods/gameid/ <-- User-installed mods $path_user/mods/ <-- User-installed mods
$worldpath/worldmods/ $worldpath/worldmods/
In a run-in-place version (eg. the distributed windows version): In a run-in-place version (eg. the distributed windows version):
@ -514,7 +510,7 @@ Usage:
- Groups are stored in a table, having the group names with keys and the - Groups are stored in a table, having the group names with keys and the
group ratings as values. For example: group ratings as values. For example:
groups = {crumbly=3, soil=1} groups = {crumbly=3, soil=1}
^ Default dirt (soil group actually currently not defined; TODO) ^ Default dirt
groups = {crumbly=2, soil=1, level=2, outerspace=1} groups = {crumbly=2, soil=1, level=2, outerspace=1}
^ A more special dirt-kind of thing ^ A more special dirt-kind of thing
- Groups always have a rating associated with them. If there is no - Groups always have a rating associated with them. If there is no
@ -587,6 +583,9 @@ Special groups
- attached_node: if the node under it is not a walkable block the node will be - attached_node: if the node under it is not a walkable block the node will be
dropped as an item. If the node is wallmounted the dropped as an item. If the node is wallmounted the
wallmounted direction is checked. wallmounted direction is checked.
- soil: saplings will grow on nodes in this group
- connect_to_raillike: makes nodes of raillike drawtype connect to
other group members with same drawtype
Known damage and digging time defining groups Known damage and digging time defining groups
---------------------------------------------- ----------------------------------------------
@ -769,7 +768,7 @@ Some of the values in the key-value store are handled specially:
Example stuff: Example stuff:
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("formspec", meta:set_string("formspec",
"invsize[8,9;]".. "invsize[8,9;]"..
"list[context;main;0,0;8,4;]".. "list[context;main;0,0;8,4;]"..
@ -915,6 +914,7 @@ minetest.formspec_escape(string) -> string
minetest namespace reference minetest namespace reference
----------------------------- -----------------------------
Utilities:
minetest.get_current_modname() -> string minetest.get_current_modname() -> string
minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname" minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname"
^ Useful for loading additional .lua modules or static data from mod ^ Useful for loading additional .lua modules or static data from mod
@ -929,6 +929,7 @@ minetest.has_feature(arg) -> bool, missing_features
^ arg: string or table in format {foo=true, bar=true} ^ arg: string or table in format {foo=true, bar=true}
^ missing_features: {foo=true, bar=true} ^ missing_features: {foo=true, bar=true}
Logging:
minetest.debug(line) minetest.debug(line)
^ Always printed to stderr and logfile (print() is redirected here) ^ Always printed to stderr and logfile (print() is redirected here)
minetest.log(line) minetest.log(line)
@ -956,10 +957,12 @@ minetest.register_on_shutdown(func())
minetest.register_on_placenode(func(pos, newnode, placer, oldnode, itemstack)) minetest.register_on_placenode(func(pos, newnode, placer, oldnode, itemstack))
^ Called when a node has been placed ^ Called when a node has been placed
^ If return true no item is taken from itemstack ^ If return true no item is taken from itemstack
^ Deprecated: Use on_construct or after_place_node in node definition instead ^ Not recommended; use on_construct or after_place_node in node definition
^ whenever possible
minetest.register_on_dignode(func(pos, oldnode, digger)) minetest.register_on_dignode(func(pos, oldnode, digger))
^ Called when a node has been dug. ^ Called when a node has been dug.
^ Deprecated: Use on_destruct or after_dig_node in node definition instead ^ Not recommended: Use on_destruct or after_dig_node in node definition
^ whenever possible
minetest.register_on_punchnode(func(pos, node, puncher)) minetest.register_on_punchnode(func(pos, node, puncher))
^ Called when a node is punched ^ Called when a node is punched
minetest.register_on_generated(func(minp, maxp, blockseed)) minetest.register_on_generated(func(minp, maxp, blockseed))
@ -1026,6 +1029,64 @@ minetest.chat_send_all(text)
minetest.chat_send_player(name, text, prepend) minetest.chat_send_player(name, text, prepend)
^ prepend: optional, if it is set to false "Server -!- " will not be prepended to the message ^ prepend: optional, if it is set to false "Server -!- " will not be prepended to the message
Environment access:
minetest.set_node(pos, node)
minetest.add_node(pos, node): alias set_node(pos, node)
^ Set node at position (node = {name="foo", param1=0, param2=0})
minetest.remove_node(pos)
^ Equivalent to set_node(pos, "air")
minetest.get_node(pos)
^ Returns {name="ignore", ...} for unloaded area
minetest.get_node_or_nil(pos)
^ Returns nil for unloaded area
minetest.get_node_light(pos, timeofday) -> 0...15 or nil
^ timeofday: nil = current time, 0 = night, 0.5 = day
minetest.place_node(pos, node)
^ Place node with the same effects that a player would cause
minetest.dig_node(pos)
^ Dig node with the same effects that a player would cause
minetest.punch_node(pos)
^ Punch node with the same effects that a player would cause
minetest.get_meta(pos) -- Get a NodeMetaRef at that position
minetest.get_node_timer(pos) -- Get NodeTimerRef
minetest.add_entity(pos, name): Spawn Lua-defined entity at position
^ Returns ObjectRef, or nil if failed
minetest.add_item(pos, item): Spawn item
^ Returns ObjectRef, or nil if failed
minetest.get_player_by_name(name) -- Get an ObjectRef to a player
minetest.get_objects_inside_radius(pos, radius)
minetest.set_timeofday(val): val: 0...1; 0 = midnight, 0.5 = midday
minetest.get_timeofday()
minetest.find_node_near(pos, radius, nodenames) -> pos or nil
^ nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
minetest.find_nodes_in_area(minp, maxp, nodenames) -> list of positions
^ nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
minetest.get_perlin(seeddiff, octaves, persistence, scale)
^ Return world-specific perlin noise (int(worldseed)+seeddiff)
minetest.clear_objects()
^ clear all objects in the environments
minetest.line_of_sight(pos1,pos2,stepsize) ->true/false
^ checkif there is a direct line of sight between pos1 and pos2
^ pos1 First position
^ pos2 Second position
^ stepsize smaller gives more accurate results but requires more computing
time. Default is 1.
minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)
^ -> table containing path
^ returns a table of 3d points representing a path from pos1 to pos2 or nil
^ pos1: start position
^ pos2: end position
^ searchdistance: number of blocks to search in each direction
^ max_jump: maximum height difference to consider walkable
^ max_drop: maximum height difference to consider droppable
^ algorithm: A*_noprefetch(default), A*, Dijkstra
minetest.spawn_tree (pos, {treedef})
^ spawns L-System tree at given pos with definition in treedef table
Inventory: Inventory:
minetest.get_inventory(location) -> InvRef minetest.get_inventory(location) -> InvRef
^ location = eg. {type="player", name="celeron55"} ^ location = eg. {type="player", name="celeron55"}
@ -1196,7 +1257,11 @@ minetest.deserialize(string) -> table
Global objects: Global objects:
minetest.env - EnvRef of the server environment and world. minetest.env - EnvRef of the server environment and world.
^ Using this you can access nodes and entities ^ Any function in the minetest namespace can be called using the syntax
minetest.env:somefunction(somearguments)
instead of
minetest.somefunction(somearguments)
^ Deprecated, but support is not to be dropped soon
Global tables: Global tables:
minetest.registered_items minetest.registered_items
@ -1225,129 +1290,9 @@ minetest.digprop_glasslike(toughness)
Class reference Class reference
---------------- ----------------
EnvRef: basically ServerEnvironment and ServerMap combined.
methods:
- set_node(pos, node)
- add_node(pos, node): alias set_node(pos, node)
^ Set node at position (node = {name="foo", param1=0, param2=0})
- remove_node(pos)
^ Equivalent to set_node(pos, "air")
- get_node(pos)
^ Returns {name="ignore", ...} for unloaded area
- get_node_or_nil(pos)
^ Returns nil for unloaded area
- get_node_light(pos, timeofday) -> 0...15 or nil
^ timeofday: nil = current time, 0 = night, 0.5 = day
- place_node(pos, node)
^ Place node with the same effects that a player would cause
- dig_node(pos)
^ Dig node with the same effects that a player would cause
- punch_node(pos)
^ Punch node with the same effects that a player would cause
- get_meta(pos) -- Get a NodeMetaRef at that position
- get_node_timer(pos) -- Get NodeTimerRef
- add_entity(pos, name): Spawn Lua-defined entity at position
^ Returns ObjectRef, or nil if failed
- add_item(pos, item): Spawn item
^ Returns ObjectRef, or nil if failed
- get_player_by_name(name) -- Get an ObjectRef to a player
- get_objects_inside_radius(pos, radius)
- set_timeofday(val): val: 0...1; 0 = midnight, 0.5 = midday
- get_timeofday()
- find_node_near(pos, radius, nodenames) -> pos or nil
^ nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
- find_nodes_in_area(minp, maxp, nodenames) -> list of positions
^ nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
- get_perlin(seeddiff, octaves, persistence, scale)
^ Return world-specific perlin noise (int(worldseed)+seeddiff)
- clear_objects()
^ clear all objects in the environments
- line_of_sight(pos1,pos2,stepsize) ->true/false
^ checkif there is a direct line of sight between pos1 and pos2
^ pos1 First position
^ pos2 Second position
^ stepsize smaller gives more accurate results but requires more computing
time. Default is 1.
-find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm) -> table containing path
^ returns a table of 3d points representing a path from pos1 to pos2 or nil
^ pos1: start position
^ pos2: end position
^ searchdistance: number of blocks to search in each direction
^ max_jump: maximum height difference to consider walkable
^ max_drop: maximum height difference to consider droppable
^ algorithm: A*_noprefetch(default), A*, Dijkstra
- spawn_tree (pos, {treedef})
^ spawns L-System tree at given pos with definition in treedef table
treedef={
axiom, - string initial tree axiom
rules_a, - string rules set A
rules_b, - string rules set B
rules_c, - string rules set C
rules_d, - string rules set D
trunk, - string trunk node name
leaves, - string leaves node name
leaves2, - string secondary leaves node name
leaves2_chance,- num chance (0-100) to replace leaves with leaves2
angle, - num angle in deg
iterations, - num max # of iterations, usually 2 -5
random_level, - num factor to lower nr of iterations, usually 0 - 3
trunk_type, - string single/double/crossed) type of trunk: 1 node, 2x2 nodes or 3x3 in cross shape
thin_branches, - boolean true -> use thin (1 node) branches
fruit, - string fruit node name
fruit_chance, - num chance (0-100) to replace leaves with fruit node
seed, - num random seed
}
Key for Special L-System Symbols used in Axioms
G - move forward one unit with the pen up
F - move forward one unit with the pen down drawing trunks and branches
f - move forward one unit with the pen down drawing leaves (100% chance)
T - move forward one unit with the pen down drawing trunks only
R - move forward one unit with the pen down placing fruit
A - replace with rules set A
B - replace with rules set B
C - replace with rules set C
D - replace with rules set D
a - replace with rules set A, chance 90%
b - replace with rules set B, chance 80%
c - replace with rules set C, chance 70%
d - replace with rules set D, chance 60%
+ - yaw the turtle right by angle parameter
- - yaw the turtle left by angle parameter
& - pitch the turtle down by angle parameter
^ - pitch the turtle up by angle parameter
/ - roll the turtle to the right by angle parameter
* - roll the turtle to the left by angle parameter
[ - save in stack current state info
] - recover from stack state info
Example usage: spawn small apple tree
apple_tree={
axiom="FFFFFAFFBF",
rules_a="[&&&FFFFF&&FFFF][&&&++++FFFFF&&FFFF][&&&----FFFFF&&FFFF]",
rules_b="[&&&++FFFFF&&FFFF][&&&--FFFFF&&FFFF][&&&------FFFFF&&FFFF]",
trunk="default:tree",
leaves="default:leaves",
angle=30,
iterations=2,
random_level=0,
trunk_type="single",
thin_branches=true,
fruit_chance=10,
fruit="default:apple"
}
minetest.env:spawn_tree(pos,apple_tree)
Deprecated:
- add_rat(pos): Add C++ rat object (no-op)
- add_firefly(pos): Add C++ firefly object (no-op)
NodeMetaRef: Node metadata - reference extra data and functionality stored NodeMetaRef: Node metadata - reference extra data and functionality stored
in a node in a node
- Can be gotten via minetest.env:get_nodemeta(pos) - Can be gotten via minetest.get_nodemeta(pos)
methods: methods:
- set_string(name, value) - set_string(name, value)
- get_string(name) - get_string(name)
@ -1361,7 +1306,7 @@ methods:
^ See "Node Metadata" ^ See "Node Metadata"
NodeTimerRef: Node Timers - a high resolution persistent per-node timer NodeTimerRef: Node Timers - a high resolution persistent per-node timer
- Can be gotten via minetest.env:get_node_timer(pos) - Can be gotten via minetest.get_node_timer(pos)
methods: methods:
- set(timeout,elapsed) - set(timeout,elapsed)
^ set a timer's state ^ set a timer's state
@ -1454,6 +1399,8 @@ Player-only: (no-op for other objects)
^ flags: (is visible) hotbar, healthbar, crosshair, wielditem ^ flags: (is visible) hotbar, healthbar, crosshair, wielditem
^ pass a table containing a true/false value of each flag to be set or unset ^ pass a table containing a true/false value of each flag to be set or unset
^ if a flag is nil, the flag is not modified ^ if a flag is nil, the flag is not modified
- hud_set_hotbar_itemcount(count): sets number of items in builtin hotbar
^ count: number of items, must be between 1 and 23
InvRef: Reference to an inventory InvRef: Reference to an inventory
methods: methods:
@ -1516,7 +1463,7 @@ methods:
PerlinNoise: A perlin noise generator PerlinNoise: A perlin noise generator
- Can be created via PerlinNoise(seed, octaves, persistence, scale) - Can be created via PerlinNoise(seed, octaves, persistence, scale)
- Also minetest.env:get_perlin(seeddiff, octaves, persistence, scale) - Also minetest.get_perlin(seeddiff, octaves, persistence, scale)
methods: methods:
- get2d(pos) -> 2d noise value at pos={x=,y=} - get2d(pos) -> 2d noise value at pos={x=,y=}
- get3d(pos) -> 3d noise value at pos={x=,y=,z=} - get3d(pos) -> 3d noise value at pos={x=,y=,z=}
@ -1546,6 +1493,68 @@ Registered entities
^ Should return a string that will be passed to on_activate when ^ Should return a string that will be passed to on_activate when
the object is instantiated the next time. the object is instantiated the next time.
L-system trees
---------------
treedef={
axiom, - string initial tree axiom
rules_a, - string rules set A
rules_b, - string rules set B
rules_c, - string rules set C
rules_d, - string rules set D
trunk, - string trunk node name
leaves, - string leaves node name
leaves2, - string secondary leaves node name
leaves2_chance,- num chance (0-100) to replace leaves with leaves2
angle, - num angle in deg
iterations, - num max # of iterations, usually 2 -5
random_level, - num factor to lower nr of iterations, usually 0 - 3
trunk_type, - string single/double/crossed) type of trunk: 1 node, 2x2 nodes or 3x3 in cross shape
thin_branches, - boolean true -> use thin (1 node) branches
fruit, - string fruit node name
fruit_chance, - num chance (0-100) to replace leaves with fruit node
seed, - num random seed
}
Key for Special L-System Symbols used in Axioms
G - move forward one unit with the pen up
F - move forward one unit with the pen down drawing trunks and branches
f - move forward one unit with the pen down drawing leaves (100% chance)
T - move forward one unit with the pen down drawing trunks only
R - move forward one unit with the pen down placing fruit
A - replace with rules set A
B - replace with rules set B
C - replace with rules set C
D - replace with rules set D
a - replace with rules set A, chance 90%
b - replace with rules set B, chance 80%
c - replace with rules set C, chance 70%
d - replace with rules set D, chance 60%
+ - yaw the turtle right by angle parameter
- - yaw the turtle left by angle parameter
& - pitch the turtle down by angle parameter
^ - pitch the turtle up by angle parameter
/ - roll the turtle to the right by angle parameter
* - roll the turtle to the left by angle parameter
[ - save in stack current state info
] - recover from stack state info
Example usage: spawn small apple tree
apple_tree={
axiom="FFFFFAFFBF",
rules_a="[&&&FFFFF&&FFFF][&&&++++FFFFF&&FFFF][&&&----FFFFF&&FFFF]",
rules_b="[&&&++FFFFF&&FFFF][&&&--FFFFF&&FFFF][&&&------FFFFF&&FFFF]",
trunk="default:tree",
leaves="default:leaves",
angle=30,
iterations=2,
random_level=0,
trunk_type="single",
thin_branches=true,
fruit_chance=10,
fruit="default:apple"
}
minetest.spawn_tree(pos,apple_tree)
Definition tables Definition tables
------------------ ------------------
@ -1715,13 +1724,13 @@ Node definition (register_node)
after_place_node = func(pos, placer, itemstack), after_place_node = func(pos, placer, itemstack),
^ Called after constructing node when node was placed using ^ Called after constructing node when node was placed using
minetest.item_place_node / minetest.env:place_node minetest.item_place_node / minetest.place_node
^ If return true no item is taken from itemstack ^ If return true no item is taken from itemstack
^ default: nil ^ default: nil
after_dig_node = func(pos, oldnode, oldmetadata, digger), after_dig_node = func(pos, oldnode, oldmetadata, digger),
^ oldmetadata is in table format ^ oldmetadata is in table format
^ Called after destructing node when node was dug using ^ Called after destructing node when node was dug using
minetest.node_dig / minetest.env:dig_node minetest.node_dig / minetest.dig_node
^ default: nil ^ default: nil
can_dig = function(pos,player) can_dig = function(pos,player)
^ returns true if node can be dug, or false if not ^ returns true if node can be dug, or false if not
@ -1740,7 +1749,7 @@ Node definition (register_node)
on_timer = function(pos,elapsed), on_timer = function(pos,elapsed),
^ default: nil ^ default: nil
^ called by NodeTimers, see EnvRef and NodeTimerRef ^ called by NodeTimers, see minetest.get_node_timer and NodeTimerRef
^ elapsed is the total time passed since the timer was started ^ elapsed is the total time passed since the timer was started
^ return true to run the timer for another cycle with the same timeout value ^ return true to run the timer for another cycle with the same timeout value

@ -41,13 +41,13 @@ function bucket.register_liquid(source, flowing, itemname, inventory_image)
return return
end end
-- Check if pointing to a liquid -- Check if pointing to a liquid
n = minetest.env:get_node(pointed_thing.under) n = minetest.get_node(pointed_thing.under)
if bucket.liquids[n.name] == nil then if bucket.liquids[n.name] == nil then
-- Not a liquid -- Not a liquid
minetest.env:add_node(pointed_thing.above, {name=source}) minetest.add_node(pointed_thing.above, {name=source})
elseif n.name ~= source then elseif n.name ~= source then
-- It's a liquid -- It's a liquid
minetest.env:add_node(pointed_thing.under, {name=source}) minetest.add_node(pointed_thing.under, {name=source})
end end
return {name="bucket:bucket_empty"} return {name="bucket:bucket_empty"}
end end
@ -65,10 +65,10 @@ minetest.register_craftitem("bucket:bucket_empty", {
return return
end end
-- Check if pointing to a liquid source -- Check if pointing to a liquid source
n = minetest.env:get_node(pointed_thing.under) n = minetest.get_node(pointed_thing.under)
liquiddef = bucket.liquids[n.name] liquiddef = bucket.liquids[n.name]
if liquiddef ~= nil and liquiddef.source == n.name and liquiddef.itemname ~= nil then if liquiddef ~= nil and liquiddef.source == n.name and liquiddef.itemname ~= nil then
minetest.env:add_node(pointed_thing.under, {name="air"}) minetest.add_node(pointed_thing.under, {name="air"})
return {name=liquiddef.itemname} return {name=liquiddef.itemname}
end end
end, end,

@ -741,7 +741,7 @@ minetest.register_node("default:dirt_with_grass", {
description = "Dirt with grass", description = "Dirt with grass",
tiles ={"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"}, tiles ={"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
is_ground_content = true, is_ground_content = true,
groups = {crumbly=3}, groups = {crumbly=3, soil=1},
drop = 'default:dirt', drop = 'default:dirt',
sounds = default.node_sound_dirt_defaults({ sounds = default.node_sound_dirt_defaults({
footstep = {name="default_grass_footstep", gain=0.4}, footstep = {name="default_grass_footstep", gain=0.4},
@ -752,7 +752,7 @@ minetest.register_node("default:dirt_with_grass_footsteps", {
description = "Dirt with grass and footsteps", description = "Dirt with grass and footsteps",
tiles ={"default_grass_footsteps.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"}, tiles ={"default_grass_footsteps.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
is_ground_content = true, is_ground_content = true,
groups = {crumbly=3}, groups = {crumbly=3, soil=1},
drop = 'default:dirt', drop = 'default:dirt',
sounds = default.node_sound_dirt_defaults({ sounds = default.node_sound_dirt_defaults({
footstep = {name="default_grass_footstep", gain=0.4}, footstep = {name="default_grass_footstep", gain=0.4},
@ -763,7 +763,7 @@ minetest.register_node("default:dirt", {
description = "Dirt", description = "Dirt",
tiles ={"default_dirt.png"}, tiles ={"default_dirt.png"},
is_ground_content = true, is_ground_content = true,
groups = {crumbly=3}, groups = {crumbly=3, soil=1},
sounds = default.node_sound_dirt_defaults(), sounds = default.node_sound_dirt_defaults(),
}) })
@ -1133,14 +1133,14 @@ minetest.register_node("default:sign_wall", {
legacy_wallmounted = true, legacy_wallmounted = true,
sounds = default.node_sound_defaults(), sounds = default.node_sound_defaults(),
on_construct = function(pos) on_construct = function(pos)
--local n = minetest.env:get_node(pos) --local n = minetest.get_node(pos)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("formspec", "field[text;;${text}]") meta:set_string("formspec", "field[text;;${text}]")
meta:set_string("infotext", "\"\"") meta:set_string("infotext", "\"\"")
end, end,
on_receive_fields = function(pos, formname, fields, sender) on_receive_fields = function(pos, formname, fields, sender)
--print("Sign at "..minetest.pos_to_string(pos).." got "..dump(fields)) --print("Sign at "..minetest.pos_to_string(pos).." got "..dump(fields))
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
fields.text = fields.text or "" fields.text = fields.text or ""
print((sender:get_player_name() or "").." wrote \""..fields.text.. print((sender:get_player_name() or "").." wrote \""..fields.text..
"\" to sign at "..minetest.pos_to_string(pos)) "\" to sign at "..minetest.pos_to_string(pos))
@ -1158,7 +1158,7 @@ minetest.register_node("default:chest", {
legacy_facedir_simple = true, legacy_facedir_simple = true,
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
on_construct = function(pos) on_construct = function(pos)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("formspec", meta:set_string("formspec",
"size[8,9]".. "size[8,9]"..
"list[current_name;main;0,0;8,4;]".. "list[current_name;main;0,0;8,4;]"..
@ -1168,7 +1168,7 @@ minetest.register_node("default:chest", {
inv:set_size("main", 8*4) inv:set_size("main", 8*4)
end, end,
can_dig = function(pos,player) can_dig = function(pos,player)
local meta = minetest.env:get_meta(pos); local meta = minetest.get_meta(pos);
local inv = meta:get_inventory() local inv = meta:get_inventory()
return inv:is_empty("main") return inv:is_empty("main")
end, end,
@ -1190,13 +1190,13 @@ minetest.register_node("default:chest_locked", {
legacy_facedir_simple = true, legacy_facedir_simple = true,
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer) after_place_node = function(pos, placer)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name() or "") meta:set_string("owner", placer:get_player_name() or "")
meta:set_string("infotext", "Locked Chest (owned by ".. meta:set_string("infotext", "Locked Chest (owned by "..
meta:get_string("owner")..")") meta:get_string("owner")..")")
end, end,
on_construct = function(pos) on_construct = function(pos)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("formspec", meta:set_string("formspec",
"size[8,9]".. "size[8,9]"..
"list[current_name;main;0,0;8,4;]".. "list[current_name;main;0,0;8,4;]"..
@ -1207,12 +1207,12 @@ minetest.register_node("default:chest_locked", {
inv:set_size("main", 8*4) inv:set_size("main", 8*4)
end, end,
can_dig = function(pos,player) can_dig = function(pos,player)
local meta = minetest.env:get_meta(pos); local meta = minetest.get_meta(pos);
local inv = meta:get_inventory() local inv = meta:get_inventory()
return inv:is_empty("main") return inv:is_empty("main")
end, end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
if not has_locked_chest_privilege(meta, player) then if not has_locked_chest_privilege(meta, player) then
minetest.log("action", player:get_player_name().. minetest.log("action", player:get_player_name()..
" tried to access a locked chest belonging to ".. " tried to access a locked chest belonging to "..
@ -1223,7 +1223,7 @@ minetest.register_node("default:chest_locked", {
return count return count
end, end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player) allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
if not has_locked_chest_privilege(meta, player) then if not has_locked_chest_privilege(meta, player) then
minetest.log("action", player:get_player_name().. minetest.log("action", player:get_player_name()..
" tried to access a locked chest belonging to ".. " tried to access a locked chest belonging to "..
@ -1234,7 +1234,7 @@ minetest.register_node("default:chest_locked", {
return stack:get_count() return stack:get_count()
end, end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player) allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
if not has_locked_chest_privilege(meta, player) then if not has_locked_chest_privilege(meta, player) then
minetest.log("action", player:get_player_name().. minetest.log("action", player:get_player_name()..
" tried to access a locked chest belonging to ".. " tried to access a locked chest belonging to "..
@ -1275,7 +1275,7 @@ minetest.register_node("default:furnace", {
legacy_facedir_simple = true, legacy_facedir_simple = true,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
on_construct = function(pos) on_construct = function(pos)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("formspec", default.furnace_inactive_formspec) meta:set_string("formspec", default.furnace_inactive_formspec)
meta:set_string("infotext", "Furnace") meta:set_string("infotext", "Furnace")
local inv = meta:get_inventory() local inv = meta:get_inventory()
@ -1284,7 +1284,7 @@ minetest.register_node("default:furnace", {
inv:set_size("dst", 4) inv:set_size("dst", 4)
end, end,
can_dig = function(pos,player) can_dig = function(pos,player)
local meta = minetest.env:get_meta(pos); local meta = minetest.get_meta(pos);
local inv = meta:get_inventory() local inv = meta:get_inventory()
if not inv:is_empty("fuel") then if not inv:is_empty("fuel") then
return false return false
@ -1308,7 +1308,7 @@ minetest.register_node("default:furnace_active", {
legacy_facedir_simple = true, legacy_facedir_simple = true,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
on_construct = function(pos) on_construct = function(pos)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("formspec", default.furnace_inactive_formspec) meta:set_string("formspec", default.furnace_inactive_formspec)
meta:set_string("infotext", "Furnace"); meta:set_string("infotext", "Furnace");
local inv = meta:get_inventory() local inv = meta:get_inventory()
@ -1317,7 +1317,7 @@ minetest.register_node("default:furnace_active", {
inv:set_size("dst", 4) inv:set_size("dst", 4)
end, end,
can_dig = function(pos,player) can_dig = function(pos,player)
local meta = minetest.env:get_meta(pos); local meta = minetest.get_meta(pos);
local inv = meta:get_inventory() local inv = meta:get_inventory()
if not inv:is_empty("fuel") then if not inv:is_empty("fuel") then
return false return false
@ -1331,16 +1331,16 @@ minetest.register_node("default:furnace_active", {
}) })
function hacky_swap_node(pos,name) function hacky_swap_node(pos,name)
local node = minetest.env:get_node(pos) local node = minetest.get_node(pos)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
local meta0 = meta:to_table() local meta0 = meta:to_table()
if node.name == name then if node.name == name then
return return
end end
node.name = name node.name = name
local meta0 = meta:to_table() local meta0 = meta:to_table()
minetest.env:set_node(pos,node) minetest.set_node(pos,node)
meta = minetest.env:get_meta(pos) meta = minetest.get_meta(pos)
meta:from_table(meta0) meta:from_table(meta0)
end end
@ -1349,7 +1349,7 @@ minetest.register_abm({
interval = 1.0, interval = 1.0,
chance = 1, chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider) action = function(pos, node, active_object_count, active_object_count_wider)
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
for i, name in ipairs({ for i, name in ipairs({
"fuel_totaltime", "fuel_totaltime",
"fuel_time", "fuel_time",

@ -104,17 +104,17 @@ minetest.register_on_generated(function(minp, maxp, seed)
for divz=0+1,divs-1-1 do for divz=0+1,divs-1-1 do
local cx = minp.x + math.floor((divx+0.5)*divlen) local cx = minp.x + math.floor((divx+0.5)*divlen)
local cz = minp.z + math.floor((divz+0.5)*divlen) local cz = minp.z + math.floor((divz+0.5)*divlen)
if minetest.env:get_node({x=cx,y=1,z=cz}).name == "default:water_source" and if minetest.get_node({x=cx,y=1,z=cz}).name == "default:water_source" and
minetest.env:get_node({x=cx,y=0,z=cz}).name == "default:sand" then minetest.get_node({x=cx,y=0,z=cz}).name == "default:sand" then
local is_shallow = true local is_shallow = true
local num_water_around = 0 local num_water_around = 0
if minetest.env:get_node({x=cx-divlen*2,y=1,z=cz+0}).name == "default:water_source" then if minetest.get_node({x=cx-divlen*2,y=1,z=cz+0}).name == "default:water_source" then
num_water_around = num_water_around + 1 end num_water_around = num_water_around + 1 end
if minetest.env:get_node({x=cx+divlen*2,y=1,z=cz+0}).name == "default:water_source" then if minetest.get_node({x=cx+divlen*2,y=1,z=cz+0}).name == "default:water_source" then
num_water_around = num_water_around + 1 end num_water_around = num_water_around + 1 end
if minetest.env:get_node({x=cx+0,y=1,z=cz-divlen*2}).name == "default:water_source" then if minetest.get_node({x=cx+0,y=1,z=cz-divlen*2}).name == "default:water_source" then
num_water_around = num_water_around + 1 end num_water_around = num_water_around + 1 end
if minetest.env:get_node({x=cx+0,y=1,z=cz+divlen*2}).name == "default:water_source" then if minetest.get_node({x=cx+0,y=1,z=cz+divlen*2}).name == "default:water_source" then
num_water_around = num_water_around + 1 end num_water_around = num_water_around + 1 end
if num_water_around >= 2 then if num_water_around >= 2 then
is_shallow = false is_shallow = false
@ -122,8 +122,8 @@ minetest.register_on_generated(function(minp, maxp, seed)
if is_shallow then if is_shallow then
for x1=-divlen,divlen do for x1=-divlen,divlen do
for z1=-divlen,divlen do for z1=-divlen,divlen do
if minetest.env:get_node({x=cx+x1,y=0,z=cz+z1}).name == "default:sand" then if minetest.get_node({x=cx+x1,y=0,z=cz+z1}).name == "default:sand" then
minetest.env:set_node({x=cx+x1,y=0,z=cz+z1}, {name="default:clay"}) minetest.set_node({x=cx+x1,y=0,z=cz+z1}, {name="default:clay"})
end end
end end
end end

@ -66,7 +66,7 @@ test_sound()
function on_step(dtime) function on_step(dtime)
-- print("experimental on_step") -- print("experimental on_step")
--[[ --[[
objs = minetest.env:get_objects_inside_radius({x=0,y=0,z=0}, 10) objs = minetest.get_objects_inside_radius({x=0,y=0,z=0}, 10)
for k, obj in pairs(objs) do for k, obj in pairs(objs) do
name = obj:get_player_name() name = obj:get_player_name()
if name then if name then
@ -86,17 +86,17 @@ function on_step(dtime)
experimental.t1 = experimental.t1 + dtime experimental.t1 = experimental.t1 + dtime
if experimental.t1 >= 2 then if experimental.t1 >= 2 then
experimental.t1 = experimental.t1 - 2 experimental.t1 = experimental.t1 - 2
minetest.log("time of day is "..minetest.env:get_timeofday()) minetest.log("time of day is "..minetest.get_timeofday())
if experimental.day then if experimental.day then
minetest.log("forcing day->night") minetest.log("forcing day->night")
experimental.day = false experimental.day = false
minetest.env:set_timeofday(0.0) minetest.set_timeofday(0.0)
else else
minetest.log("forcing night->day") minetest.log("forcing night->day")
experimental.day = true experimental.day = true
minetest.env:set_timeofday(0.5) minetest.set_timeofday(0.5)
end end
minetest.log("time of day is "..minetest.env:get_timeofday()) minetest.log("time of day is "..minetest.get_timeofday())
end end
--]] --]]
end end
@ -133,8 +133,8 @@ minetest.register_node("experimental:tnt", {
minetest.register_on_punchnode(function(p, node) minetest.register_on_punchnode(function(p, node)
if node.name == "experimental:tnt" then if node.name == "experimental:tnt" then
minetest.env:remove_node(p) minetest.remove_node(p)
minetest.env:add_entity(p, "experimental:tnt") minetest.add_entity(p, "experimental:tnt")
nodeupdate(p) nodeupdate(p)
end end
end) end)
@ -262,7 +262,7 @@ minetest.register_on_chat_message(function(name, message)
minetest.chat_send_player(name, "you don't have permission to interact") minetest.chat_send_player(name, "you don't have permission to interact")
return true -- Handled chat message return true -- Handled chat message
end end
local player = minetest.env:get_player_by_name(name) local player = minetest.get_player_by_name(name)
if player == nil then if player == nil then
print("Unable to spawn entity, player is nil") print("Unable to spawn entity, player is nil")
return true -- Handled chat message return true -- Handled chat message
@ -270,7 +270,7 @@ minetest.register_on_chat_message(function(name, message)
local entityname = "experimental:dummyball" local entityname = "experimental:dummyball"
local p = player:getpos() local p = player:getpos()
p.y = p.y + 1 p.y = p.y + 1
minetest.env:add_entity(p, entityname) minetest.add_entity(p, entityname)
minetest.chat_send_player(name, '"'..entityname minetest.chat_send_player(name, '"'..entityname
..'" spawned.'); ..'" spawned.');
return true -- Handled chat message return true -- Handled chat message
@ -323,7 +323,7 @@ end)
minetest.register_on_generated(function(minp, maxp) minetest.register_on_generated(function(minp, maxp)
--print("on_generated: minp="..dump(minp).." maxp="..dump(maxp)) --print("on_generated: minp="..dump(minp).." maxp="..dump(maxp))
--cp = {x=(minp.x+maxp.x)/2, y=(minp.y+maxp.y)/2, z=(minp.z+maxp.z)/2} --cp = {x=(minp.x+maxp.x)/2, y=(minp.y+maxp.y)/2, z=(minp.z+maxp.z)/2}
--minetest.env:add_node(cp, {name="sand"}) --minetest.add_node(cp, {name="sand"})
end) end)
-- Example setting get -- Example setting get
@ -353,7 +353,7 @@ end)
action = function(pos, node, active_object_count, active_object_count_wider) action = function(pos, node, active_object_count, active_object_count_wider)
print("TNT ABM action") print("TNT ABM action")
pos.y = pos.y + 1 pos.y = pos.y + 1
minetest.env:add_node(pos, {name="papyrus"}) minetest.add_node(pos, {name="papyrus"})
end, end,
})]] })]]
@ -364,7 +364,7 @@ end)
chance = 1, chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider) action = function(pos, node, active_object_count, active_object_count_wider)
print("ABM: Sign text changed") print("ABM: Sign text changed")
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_text("foo") meta:set_text("foo")
end, end,
})]] })]]
@ -395,7 +395,7 @@ minetest.register_abm({
end end
pos.y = pos.y + 1 pos.y = pos.y + 1
n = minetest.env:get_node(pos) n = minetest.get_node(pos)
print(dump(n)) print(dump(n))
if n.name ~= "air" then if n.name ~= "air" then
return return
@ -404,7 +404,7 @@ minetest.register_abm({
pos.y = pos.y + 2 pos.y = pos.y + 2
ncpos = pos ncpos = pos
nctime = os.clock() nctime = os.clock()
minetest.env:add_node(ncpos, {name="nyancat"}) minetest.add_node(ncpos, {name="nyancat"})
end end
}) })
@ -431,12 +431,12 @@ minetest.register_abm({
p2 = {x = p1.x + s1[2], y = p1.y, z = p1.z + s1[3]} p2 = {x = p1.x + s1[2], y = p1.y, z = p1.z + s1[3]}
table.insert(ncold, 1, p0) table.insert(ncold, 1, p0)
while #ncold >= 10 do while #ncold >= 10 do
minetest.env:add_node(ncold[#ncold], {name="air"}) minetest.add_node(ncold[#ncold], {name="air"})
table.remove(ncold, #ncold) table.remove(ncold, #ncold)
end end
minetest.env:add_node(p0, {name="nyancat_rainbow"}) minetest.add_node(p0, {name="nyancat_rainbow"})
minetest.env:add_node(p1, {name="nyancat", param1=s0[4]}) minetest.add_node(p1, {name="nyancat", param1=s0[4]})
minetest.env:add_node(p2, {name="air"}) minetest.add_node(p2, {name="air"})
ncpos = p1 ncpos = p1
end end
end, end,
@ -448,20 +448,20 @@ minetest.register_node("experimental:tester_node_1", {
groups = {oddly_breakable_by_hand=2}, groups = {oddly_breakable_by_hand=2},
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
-- This was known to cause a bug in minetest.item_place_node() when used -- This was known to cause a bug in minetest.item_place_node() when used
-- via minetest.env:place_node(), causing a placer with no position -- via minetest.place_node(), causing a placer with no position
paramtype2 = "facedir", paramtype2 = "facedir",
on_construct = function(pos) on_construct = function(pos)
experimental.print_to_everything("experimental:tester_node_1:on_construct("..minetest.pos_to_string(pos)..")") experimental.print_to_everything("experimental:tester_node_1:on_construct("..minetest.pos_to_string(pos)..")")
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("mine", "test") meta:set_string("mine", "test")
local timer = minetest.env:get_node_timer(pos) local timer = minetest.get_node_timer(pos)
timer:start(4, 3) timer:start(4, 3)
end, end,
after_place_node = function(pos, placer) after_place_node = function(pos, placer)
experimental.print_to_everything("experimental:tester_node_1:after_place_node("..minetest.pos_to_string(pos)..")") experimental.print_to_everything("experimental:tester_node_1:after_place_node("..minetest.pos_to_string(pos)..")")
local meta = minetest.env:get_meta(pos) local meta = minetest.get_meta(pos)
if meta:get_string("mine") == "test" then if meta:get_string("mine") == "test" then
experimental.print_to_everything("correct metadata found") experimental.print_to_everything("correct metadata found")
else else
@ -493,14 +493,14 @@ minetest.register_craftitem("experimental:tester_tool_1", {
on_use = function(itemstack, user, pointed_thing) on_use = function(itemstack, user, pointed_thing)
--print(dump(pointed_thing)) --print(dump(pointed_thing))
if pointed_thing.type == "node" then if pointed_thing.type == "node" then
if minetest.env:get_node(pointed_thing.under).name == "experimental:tester_node_1" then if minetest.get_node(pointed_thing.under).name == "experimental:tester_node_1" then
local p = pointed_thing.under local p = pointed_thing.under
minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p)) minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p))
minetest.env:dig_node(p) minetest.dig_node(p)
else else
local p = pointed_thing.above local p = pointed_thing.above
minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p)) minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p))
minetest.env:place_node(p, {name="experimental:tester_node_1"}) minetest.place_node(p, {name="experimental:tester_node_1"})
end end
end end
end, end,
@ -556,7 +556,7 @@ minetest.register_chatcommand("test1", {
params = "", params = "",
description = "Test 1: Modify player's inventory view", description = "Test 1: Modify player's inventory view",
func = function(name, param) func = function(name, param)
local player = minetest.env:get_player_by_name(name) local player = minetest.get_player_by_name(name)
if not player then if not player then
return return
end end

@ -79,14 +79,12 @@ minetest.register_craftitem(":rat", {
description = "Rat", description = "Rat",
inventory_image = "rat.png", inventory_image = "rat.png",
on_drop = function(item, dropper, pos) on_drop = function(item, dropper, pos)
minetest.env:add_rat(pos)
item:take_item() item:take_item()
return item return item
end, end,
on_place = function(item, dropped, pointed) on_place = function(item, dropped, pointed)
pos = minetest.get_pointed_thing_position(pointed, true) pos = minetest.get_pointed_thing_position(pointed, true)
if pos ~= nil then if pos ~= nil then
minetest.env:add_rat(pos)
item:take_item() item:take_item()
return item return item
end end
@ -103,14 +101,12 @@ minetest.register_craftitem(":firefly", {
description = "Firefly", description = "Firefly",
inventory_image = "firefly.png", inventory_image = "firefly.png",
on_drop = function(item, dropper, pos) on_drop = function(item, dropper, pos)
minetest.env:add_firefly(pos)
item:take_item() item:take_item()
return item return item
end, end,
on_place = function(item, dropped, pointed) on_place = function(item, dropped, pointed)
pos = minetest.get_pointed_thing_position(pointed, true) pos = minetest.get_pointed_thing_position(pointed, true)
if pos ~= nil then if pos ~= nil then
minetest.env:add_firefly(pos)
item:take_item() item:take_item()
return item return item
end end

@ -12,7 +12,7 @@
# #
# NOTE: This file might not be up-to-date, refer to the # NOTE: This file might not be up-to-date, refer to the
# defaultsettings.cpp file for an up-to-date list: # defaultsettings.cpp file for an up-to-date list:
# https://bitbucket.org/celeron55/minetest/src/tip/src/defaultsettings.cpp # https://github.com/minetest/minetest/blob/master/src/defaultsettings.cpp
# #
# A vim command to convert most of defaultsettings.cpp to conf file format: # A vim command to convert most of defaultsettings.cpp to conf file format:
# :'<,'>s/\tsettings->setDefault("\([^"]*\)", "\([^"]*\)");.*/#\1 = \2/g # :'<,'>s/\tsettings->setDefault("\([^"]*\)", "\([^"]*\)");.*/#\1 = \2/g

@ -1 +0,0 @@
You can install Minetest mods by copying (and extracting) them into this folder.

4
mods/mods_here.txt Normal file

@ -0,0 +1,4 @@
You can install Minetest mods by copying (and extracting) them into this folder.
To enable them, go to the configure world window in the main menu or write
load_mod_<modname> = true
in world.mt in the world directory.

@ -51,7 +51,7 @@ msgstr ""
msgid "" msgid ""
"\n" "\n"
"Check debug.txt for details." "Check debug.txt for details."
msgstr "Деталі у файлі debug.txt." msgstr "\nДеталі у файлі debug.txt."
#: src/guiConfigureWorld.cpp:123 #: src/guiConfigureWorld.cpp:123
msgid "" msgid ""

@ -206,6 +206,9 @@ configure_file(
"${PROJECT_BINARY_DIR}/cmake_config.h" "${PROJECT_BINARY_DIR}/cmake_config.h"
) )
add_subdirectory(script)
add_subdirectory(util)
set(common_SRCS set(common_SRCS
rollback_interface.cpp rollback_interface.cpp
rollback.cpp rollback.cpp
@ -222,22 +225,6 @@ 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
script.cpp
log.cpp log.cpp
content_sao.cpp content_sao.cpp
emerge.cpp emerge.cpp
@ -283,12 +270,8 @@ set(common_SRCS
staticobject.cpp staticobject.cpp
serverlist.cpp serverlist.cpp
pathfinder.cpp pathfinder.cpp
util/serialize.cpp ${SCRIPT_SRCS}
util/directiontables.cpp ${UTIL_SRCS}
util/numeric.cpp
util/pointedthing.cpp
util/string.cpp
util/timetaker.cpp
) )
# This gives us the icon # This gives us the icon
@ -365,6 +348,7 @@ set(minetestserver_SRCS
include_directories( include_directories(
${PROJECT_BINARY_DIR} ${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}
${IRRLICHT_INCLUDE_DIR} ${IRRLICHT_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}
${CMAKE_BUILD_TYPE} ${CMAKE_BUILD_TYPE}
@ -375,6 +359,7 @@ include_directories(
${SQLITE3_INCLUDE_DIR} ${SQLITE3_INCLUDE_DIR}
${LUA_INCLUDE_DIR} ${LUA_INCLUDE_DIR}
${JSON_INCLUDE_DIR} ${JSON_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/script
) )
if(USE_FREETYPE) if(USE_FREETYPE)

@ -71,7 +71,12 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
m_digging_anim(0), m_digging_anim(0),
m_digging_button(-1), m_digging_button(-1),
m_dummymesh(createCubeMesh(v3f(1,1,1))) m_dummymesh(createCubeMesh(v3f(1,1,1))),
m_wield_change_timer(0.125),
m_wield_mesh_next(NULL),
m_previous_playeritem(-1),
m_previous_itemname("")
{ {
//dstream<<__FUNCTION_NAME<<std::endl; //dstream<<__FUNCTION_NAME<<std::endl;
@ -142,6 +147,22 @@ void Camera::step(f32 dtime)
m_view_bobbing_fall = -1; // Mark the effect as finished m_view_bobbing_fall = -1; // Mark the effect as finished
} }
bool was_under_zero = m_wield_change_timer < 0;
if(m_wield_change_timer < 0.125)
m_wield_change_timer += dtime;
if(m_wield_change_timer > 0.125)
m_wield_change_timer = 0.125;
if(m_wield_change_timer >= 0 && was_under_zero) {
if(m_wield_mesh_next) {
m_wieldnode->setMesh(m_wield_mesh_next);
m_wieldnode->setVisible(true);
} else {
m_wieldnode->setVisible(false);
}
m_wield_mesh_next = NULL;
}
if (m_view_bobbing_state != 0) if (m_view_bobbing_state != 0)
{ {
//f32 offset = dtime * m_view_bobbing_speed * 0.035; //f32 offset = dtime * m_view_bobbing_speed * 0.035;
@ -342,8 +363,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize,
m_fov_y = fov_degrees * M_PI / 180.0; m_fov_y = fov_degrees * M_PI / 180.0;
// Increase vertical FOV on lower aspect ratios (<16:10) // Increase vertical FOV on lower aspect ratios (<16:10)
m_fov_y *= MYMAX(1.0, MYMIN(1.4, sqrt(16./10. / m_aspect))); m_fov_y *= MYMAX(1.0, MYMIN(1.4, sqrt(16./10. / m_aspect)));
// WTF is this? It can't be right m_fov_x = 2 * atan(m_aspect * tan(0.5 * m_fov_y));
m_fov_x = 2 * atan(0.5 * m_aspect * tan(m_fov_y));
m_cameranode->setAspectRatio(m_aspect); m_cameranode->setAspectRatio(m_aspect);
m_cameranode->setFOV(m_fov_y); m_cameranode->setFOV(m_fov_y);
@ -352,6 +372,10 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize,
v3f wield_position = v3f(55, -35, 65); v3f wield_position = v3f(55, -35, 65);
//v3f wield_rotation = v3f(-100, 120, -100); //v3f wield_rotation = v3f(-100, 120, -100);
v3f wield_rotation = v3f(-100, 120, -100); v3f wield_rotation = v3f(-100, 120, -100);
if(m_wield_change_timer < 0)
wield_position.Y -= 40 + m_wield_change_timer*320;
else
wield_position.Y -= 40 - m_wield_change_timer*320;
if(m_digging_anim < 0.05 || m_digging_anim > 0.5){ if(m_digging_anim < 0.05 || m_digging_anim > 0.5){
f32 frac = 1.0; f32 frac = 1.0;
if(m_digging_anim > 0.5) if(m_digging_anim > 0.5)
@ -560,18 +584,34 @@ void Camera::setDigging(s32 button)
m_digging_button = button; m_digging_button = button;
} }
void Camera::wield(const ItemStack &item) void Camera::wield(const ItemStack &item, u16 playeritem)
{ {
IItemDefManager *idef = m_gamedef->idef(); IItemDefManager *idef = m_gamedef->idef();
scene::IMesh *wield_mesh = idef->getWieldMesh(item.getDefinition(idef).name, m_gamedef); std::string itemname = item.getDefinition(idef).name;
if(wield_mesh) m_wield_mesh_next = idef->getWieldMesh(itemname, m_gamedef);
{ if(playeritem != m_previous_playeritem &&
m_wieldnode->setMesh(wield_mesh); !(m_previous_itemname == "" && itemname == "")) {
m_wieldnode->setVisible(true); m_previous_playeritem = playeritem;
} m_previous_itemname = itemname;
else if(m_wield_change_timer >= 0.125)
{ m_wield_change_timer = -0.125;
m_wieldnode->setVisible(false); else if(m_wield_change_timer > 0) {
m_wield_change_timer = -m_wield_change_timer;
}
} else {
if(m_wield_mesh_next) {
m_wieldnode->setMesh(m_wield_mesh_next);
m_wieldnode->setVisible(true);
} else {
m_wieldnode->setVisible(false);
}
m_wield_mesh_next = NULL;
if(m_previous_itemname != itemname) {
m_previous_itemname = itemname;
m_wield_change_timer = 0;
}
else
m_wield_change_timer = 0.125;
} }
} }

@ -117,7 +117,7 @@ public:
void setDigging(s32 button); void setDigging(s32 button);
// Replace the wielded item mesh // Replace the wielded item mesh
void wield(const ItemStack &item); void wield(const ItemStack &item, u16 playeritem);
// Draw the wielded tool. // Draw the wielded tool.
// This has to happen *after* the main scene is drawn. // This has to happen *after* the main scene is drawn.
@ -178,6 +178,12 @@ private:
//dummymesh for camera //dummymesh for camera
irr::scene::IAnimatedMesh* m_dummymesh; irr::scene::IAnimatedMesh* m_dummymesh;
// Animation when changing wielded item
f32 m_wield_change_timer;
scene::IMesh *m_wield_mesh_next;
u16 m_previous_playeritem;
std::string m_previous_itemname;
}; };
#endif #endif

@ -350,6 +350,11 @@ Client::~Client()
m_mesh_update_thread.setRun(false); m_mesh_update_thread.setRun(false);
while(m_mesh_update_thread.IsRunning()) while(m_mesh_update_thread.IsRunning())
sleep_ms(100); sleep_ms(100);
while(!m_mesh_update_thread.m_queue_out.empty()) {
MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
delete r.mesh;
}
delete m_inventory_from_server; delete m_inventory_from_server;
@ -757,6 +762,8 @@ void Client::step(float dtime)
// Replace with the new mesh // Replace with the new mesh
block->mesh = r.mesh; block->mesh = r.mesh;
} else {
delete r.mesh;
} }
if(r.ack_block_to_server) if(r.ack_block_to_server)
{ {
@ -1980,7 +1987,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
event.spawn_particle.expirationtime = expirationtime; event.spawn_particle.expirationtime = expirationtime;
event.spawn_particle.size = size; event.spawn_particle.size = size;
event.add_particlespawner.collisiondetection = event.spawn_particle.collisiondetection =
collisiondetection; collisiondetection;
event.spawn_particle.texture = new std::string(texture); event.spawn_particle.texture = new std::string(texture);
@ -2129,6 +2136,23 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
player->hud_flags &= ~mask; player->hud_flags &= ~mask;
player->hud_flags |= flags; player->hud_flags |= flags;
} }
else if(command == TOCLIENT_HUD_SET_PARAM)
{
std::string datastring((char *)&data[2], datasize - 2);
std::istringstream is(datastring, std::ios_base::binary);
Player *player = m_env.getLocalPlayer();
assert(player != NULL);
u16 param = readU16(is);
std::string value = deSerializeString(is);
if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4){
s32 hotbar_itemcount = readS32((u8*) value.c_str());
if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
player->hud_hotbar_itemcount = hotbar_itemcount;
}
}
else else
{ {
infostream<<"Client: Ignoring unknown command " infostream<<"Client: Ignoring unknown command "

@ -480,6 +480,14 @@ enum ToClientCommand
u32 flags u32 flags
u32 mask u32 mask
*/ */
TOCLIENT_HUD_SET_PARAM = 0x4d,
/*
u16 command
u16 param
u16 len
u8[len] value
*/
}; };
enum ToServerCommand enum ToServerCommand

@ -298,7 +298,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
f32 distance = speed_f.getLength(); f32 distance = speed_f.getLength();
std::vector<DistanceSortedActiveObject> clientobjects; std::vector<DistanceSortedActiveObject> clientobjects;
c_env->getActiveObjects(pos_f,distance * 1.5,clientobjects); c_env->getActiveObjects(pos_f,distance * 1.5,clientobjects);
for (int i=0; i < clientobjects.size(); i++) for (size_t i=0; i < clientobjects.size(); i++)
{ {
if ((self == 0) || (self != clientobjects[i].obj)) { if ((self == 0) || (self != clientobjects[i].obj)) {
objects.push_back((ActiveObject*)clientobjects[i].obj); objects.push_back((ActiveObject*)clientobjects[i].obj);

@ -99,14 +99,10 @@ class MakeTreesFromSaplingsABM : public ActiveBlockModifier
{ {
private: private:
content_t c_junglesapling; content_t c_junglesapling;
content_t c_dirt;
content_t c_dirt_with_grass;
public: public:
MakeTreesFromSaplingsABM(ServerEnvironment *env, INodeDefManager *nodemgr) { MakeTreesFromSaplingsABM(ServerEnvironment *env, INodeDefManager *nodemgr) {
c_junglesapling = nodemgr->getId("junglesapling"); 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()
@ -127,8 +123,7 @@ public:
ServerMap *map = &env->getServerMap(); ServerMap *map = &env->getServerMap();
MapNode n_below = map->getNodeNoEx(p - v3s16(0, 1, 0)); MapNode n_below = map->getNodeNoEx(p - v3s16(0, 1, 0));
if (n_below.getContent() != c_dirt && if (!((ItemGroupList) ndef->get(n_below).groups)["soil"])
n_below.getContent() != c_dirt_with_grass)
return; return;
bool is_jungle_tree = n.getContent() == c_junglesapling; bool is_jungle_tree = n.getContent() == c_junglesapling;
@ -196,17 +191,58 @@ public:
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
{ {
ServerMap *map = &env->getServerMap(); ServerMap *map = &env->getServerMap();
if (map->transforming_liquid_size() < 500) if (map->transforming_liquid_size() > 500)
map->transforming_liquid_add(p); return;
map->transforming_liquid_add(p);
//if ((*map).m_transforming_liquid.size() < 500) (*map).m_transforming_liquid.push_back(p); //if ((*map).m_transforming_liquid.size() < 500) (*map).m_transforming_liquid.push_back(p);
} }
}; };
class LiquidDropABM : public ActiveBlockModifier
{
private:
std::set<std::string> contents;
public:
LiquidDropABM(ServerEnvironment *env, INodeDefManager *nodemgr)
{
std::set<content_t> liquids;
nodemgr->getIds("group:liquid", liquids);
for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
contents.insert(nodemgr->get(*k).liquid_alternative_source);
}
virtual std::set<std::string> getTriggerContents()
{ return contents; }
virtual std::set<std::string> getRequiredNeighbors()
{
std::set<std::string> neighbors;
neighbors.insert("mapgen_air");
return neighbors;
}
virtual float getTriggerInterval()
{ return 20.0; }
virtual u32 getTriggerChance()
{ return 10; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
{
ServerMap *map = &env->getServerMap();
if (map->transforming_liquid_size() > 500)
return;
//todo: look around except top
MapNode n_below = map->getNodeNoEx(p - v3s16(0, 1, 0));
if (n_below.getContent() != CONTENT_AIR)
return;
map->transforming_liquid_add(p);
}
};
void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef) 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, nodedef)); 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));
env->addActiveBlockModifier(new LiquidDropABM(env, nodedef));
}
} }

@ -1188,34 +1188,81 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
MapNode n_minus_z_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y+1, z-1)); MapNode n_minus_z_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y+1, z-1));
MapNode n_plus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z+1)); MapNode n_plus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z+1));
MapNode n_minus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z-1)); MapNode n_minus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z-1));
content_t thiscontent = n.getContent(); content_t thiscontent = n.getContent();
if(n_minus_x.getContent() == thiscontent) std::string groupname = "connect_to_raillike"; // name of the group that enables connecting to raillike nodes of different kind
bool self_connect_to_raillike = ((ItemGroupList) nodedef->get(n).groups)[groupname] != 0;
if ((nodedef->get(n_minus_x).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_minus_x).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_minus_x.getContent() == thiscontent)
is_rail_x[0] = true; is_rail_x[0] = true;
if (n_minus_x_minus_y.getContent() == thiscontent)
if ((nodedef->get(n_minus_x_minus_y).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_minus_x_minus_y).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_minus_x_minus_y.getContent() == thiscontent)
is_rail_x_minus_y[0] = true; is_rail_x_minus_y[0] = true;
if(n_minus_x_plus_y.getContent() == thiscontent)
if ((nodedef->get(n_minus_x_plus_y).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_minus_x_plus_y).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_minus_x_plus_y.getContent() == thiscontent)
is_rail_x_plus_y[0] = true; is_rail_x_plus_y[0] = true;
if(n_plus_x.getContent() == thiscontent) if ((nodedef->get(n_plus_x).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_plus_x).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_plus_x.getContent() == thiscontent)
is_rail_x[1] = true; is_rail_x[1] = true;
if (n_plus_x_minus_y.getContent() == thiscontent)
if ((nodedef->get(n_plus_x_minus_y).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_plus_x_minus_y).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_plus_x_minus_y.getContent() == thiscontent)
is_rail_x_minus_y[1] = true; is_rail_x_minus_y[1] = true;
if(n_plus_x_plus_y.getContent() == thiscontent)
if ((nodedef->get(n_plus_x_plus_y).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_plus_x_plus_y).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_plus_x_plus_y.getContent() == thiscontent)
is_rail_x_plus_y[1] = true; is_rail_x_plus_y[1] = true;
if(n_minus_z.getContent() == thiscontent) if ((nodedef->get(n_minus_z).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_minus_z).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_minus_z.getContent() == thiscontent)
is_rail_z[0] = true; is_rail_z[0] = true;
if (n_minus_z_minus_y.getContent() == thiscontent)
if ((nodedef->get(n_minus_z_minus_y).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_minus_z_minus_y).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_minus_z_minus_y.getContent() == thiscontent)
is_rail_z_minus_y[0] = true; is_rail_z_minus_y[0] = true;
if(n_minus_z_plus_y.getContent() == thiscontent)
if ((nodedef->get(n_minus_z_plus_y).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_minus_z_plus_y).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_minus_z_plus_y.getContent() == thiscontent)
is_rail_z_plus_y[0] = true; is_rail_z_plus_y[0] = true;
if(n_plus_z.getContent() == thiscontent) if ((nodedef->get(n_plus_z).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_plus_z).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_plus_z.getContent() == thiscontent)
is_rail_z[1] = true; is_rail_z[1] = true;
if (n_plus_z_minus_y.getContent() == thiscontent)
if ((nodedef->get(n_plus_z_minus_y).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_plus_z_minus_y).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_plus_z_minus_y.getContent() == thiscontent)
is_rail_z_minus_y[1] = true; is_rail_z_minus_y[1] = true;
if(n_plus_z_plus_y.getContent() == thiscontent)
if ((nodedef->get(n_plus_z_plus_y).drawtype == NDT_RAILLIKE
&& ((ItemGroupList) nodedef->get(n_plus_z_plus_y).groups)[groupname] != 0
&& self_connect_to_raillike)
|| n_plus_z_plus_y.getContent() == thiscontent)
is_rail_z_plus_y[1] = true; is_rail_z_plus_y[1] = true;
bool is_rail_x_all[] = {false, false}; bool is_rail_x_all[] = {false, false};
@ -1255,7 +1302,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
if(is_rail_x_all[0] && is_rail_x_all[1]) if(is_rail_x_all[0] && is_rail_x_all[1])
angle = 90; angle = 90;
if(is_rail_z_all[0] && is_rail_z_all[1]){ if(is_rail_z_all[0] && is_rail_z_all[1]){
if (n_minus_z_plus_y.getContent() == thiscontent) angle = 180; if (is_rail_z_plus_y[0])
angle = 180;
} }
else if(is_rail_x_all[0] && is_rail_z_all[0]) else if(is_rail_x_all[0] && is_rail_z_all[0])
angle = 270; angle = 270;

@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tool.h" // For ToolCapabilities #include "tool.h" // For ToolCapabilities
#include "gamedef.h" #include "gamedef.h"
#include "player.h" #include "player.h"
#include "scriptapi.h" #include "cpp_api/scriptapi.h"
#include "genericobject.h" #include "genericobject.h"
#include "util/serialize.h" #include "util/serialize.h"
@ -387,8 +387,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
LuaEntitySAO::~LuaEntitySAO() LuaEntitySAO::~LuaEntitySAO()
{ {
if(m_registered){ if(m_registered){
lua_State *L = m_env->getLua(); ENV_TO_SA(m_env)->luaentity_Remove(m_id);
scriptapi_luaentity_rm(L, m_id);
} }
} }
@ -397,16 +396,15 @@ void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
ServerActiveObject::addedToEnvironment(dtime_s); ServerActiveObject::addedToEnvironment(dtime_s);
// Create entity from name // Create entity from name
lua_State *L = m_env->getLua(); m_registered = ENV_TO_SA(m_env)->luaentity_Add(m_id, m_init_name.c_str());
m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str());
if(m_registered){ if(m_registered){
// Get properties // Get properties
scriptapi_luaentity_get_properties(L, m_id, &m_prop); ENV_TO_SA(m_env)->luaentity_GetProperties(m_id, &m_prop);
// Initialize HP from properties // Initialize HP from properties
m_hp = m_prop.hp_max; m_hp = m_prop.hp_max;
// Activate entity, supplying serialized state // Activate entity, supplying serialized state
scriptapi_luaentity_activate(L, m_id, m_init_state.c_str(), dtime_s); ENV_TO_SA(m_env)->luaentity_Activate(m_id, m_init_state.c_str(), dtime_s);
} }
} }
@ -515,8 +513,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
} }
if(m_registered){ if(m_registered){
lua_State *L = m_env->getLua(); ENV_TO_SA(m_env)->luaentity_Step(m_id, dtime);
scriptapi_luaentity_step(L, m_id, dtime);
} }
if(send_recommended == false) if(send_recommended == false)
@ -626,8 +623,7 @@ std::string LuaEntitySAO::getStaticData()
os<<serializeString(m_init_name); os<<serializeString(m_init_name);
// state // state
if(m_registered){ if(m_registered){
lua_State *L = m_env->getLua(); std::string state = ENV_TO_SA(m_env)->luaentity_GetStaticdata(m_id);
std::string state = scriptapi_luaentity_get_staticdata(L, m_id);
os<<serializeLongString(state); os<<serializeLongString(state);
} else { } else {
os<<serializeLongString(m_init_state); os<<serializeLongString(m_init_state);
@ -673,8 +669,14 @@ int LuaEntitySAO::punch(v3f dir,
{ {
setHP(getHP() - result.damage); setHP(getHP() - result.damage);
std::string punchername = "nil";
if ( puncher != 0 )
punchername = puncher->getDescription();
actionstream<<getDescription()<<" punched by " actionstream<<getDescription()<<" punched by "
<<puncher->getDescription()<<", damage "<<result.damage <<punchername<<", damage "<<result.damage
<<" hp, health now "<<getHP()<<" hp"<<std::endl; <<" hp, health now "<<getHP()<<" hp"<<std::endl;
{ {
@ -688,8 +690,7 @@ int LuaEntitySAO::punch(v3f dir,
m_removed = true; m_removed = true;
} }
lua_State *L = m_env->getLua(); ENV_TO_SA(m_env)->luaentity_Punch(m_id, puncher,
scriptapi_luaentity_punch(L, m_id, puncher,
time_from_last_punch, toolcap, dir); time_from_last_punch, toolcap, dir);
return result.wear; return result.wear;
@ -702,8 +703,7 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
// It's best that attachments cannot be clicked // It's best that attachments cannot be clicked
if(isAttached()) if(isAttached())
return; return;
lua_State *L = m_env->getLua(); ENV_TO_SA(m_env)->luaentity_Rightclick(m_id, clicker);
scriptapi_luaentity_rightclick(L, m_id, clicker);
} }
void LuaEntitySAO::setPos(v3f pos) void LuaEntitySAO::setPos(v3f pos)
@ -1307,8 +1307,13 @@ int PlayerSAO::punch(v3f dir,
HitParams hitparams = getHitParams(m_armor_groups, toolcap, HitParams hitparams = getHitParams(m_armor_groups, toolcap,
time_from_last_punch); time_from_last_punch);
std::string punchername = "nil";
if ( puncher != 0 )
punchername = puncher->getDescription();
actionstream<<"Player "<<m_player->getName()<<" punched by " actionstream<<"Player "<<m_player->getName()<<" punched by "
<<puncher->getDescription()<<", damage "<<hitparams.hp <<punchername<<", damage "<<hitparams.hp
<<" HP"<<std::endl; <<" HP"<<std::endl;
setHP(getHP() - hitparams.hp); setHP(getHP() - hitparams.hp);

@ -32,8 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapblock.h" #include "mapblock.h"
#include "serverobject.h" #include "serverobject.h"
#include "settings.h" #include "settings.h"
#include "script.h" #include "cpp_api/scriptapi.h"
#include "scriptapi.h"
#include "profiler.h" #include "profiler.h"
#include "log.h" #include "log.h"
#include "nodedef.h" #include "nodedef.h"
@ -349,7 +348,7 @@ bool EmergeThread::getBlockOrStartGen(v3s16 p, MapBlock **b,
void *EmergeThread::Thread() { void *EmergeThread::Thread() {
ThreadStarted(); ThreadStarted();
log_register_thread("EmergeThread" + id); log_register_thread("EmergeThread" + itos(id));
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
BEGIN_DEBUG_EXCEPTION_HANDLER BEGIN_DEBUG_EXCEPTION_HANDLER
@ -418,7 +417,7 @@ void *EmergeThread::Thread() {
ign(&m_server->m_ignore_map_edit_events_area, ign(&m_server->m_ignore_map_edit_events_area,
VoxelArea(minp, maxp)); VoxelArea(minp, maxp));
{ // takes about 90ms with -O1 on an e3-1230v2 { // takes about 90ms with -O1 on an e3-1230v2
scriptapi_environment_on_generated(m_server->m_lua, SERVER_TO_SA(m_server)->environment_OnGenerated(
minp, maxp, emerge->getBlockSeed(minp)); minp, maxp, emerge->getBlockSeed(minp));
} }

@ -31,8 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
infostream << "EmergeThread: " x << std::endl; } infostream << "EmergeThread: " x << std::endl; }
class Mapgen; class Mapgen;
class MapgenParams; struct MapgenParams;
class MapgenFactory; struct MapgenFactory;
class Biome; class Biome;
class BiomeDefManager; class BiomeDefManager;
class EmergeThread; class EmergeThread;

@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" #include "settings.h"
#include "log.h" #include "log.h"
#include "profiler.h" #include "profiler.h"
#include "scriptapi.h" #include "cpp_api/scriptapi.h"
#include "nodedef.h" #include "nodedef.h"
#include "nodemetadata.h" #include "nodemetadata.h"
#include "main.h" // For g_settings, g_profiler #include "main.h" // For g_settings, g_profiler
@ -320,10 +320,10 @@ void ActiveBlockList::update(std::list<v3s16> &active_positions,
ServerEnvironment ServerEnvironment
*/ */
ServerEnvironment::ServerEnvironment(ServerMap *map, lua_State *L, ServerEnvironment::ServerEnvironment(ServerMap *map, ScriptApi *scriptIface,
IGameDef *gamedef, IBackgroundBlockEmerger *emerger): IGameDef *gamedef, IBackgroundBlockEmerger *emerger):
m_map(map), m_map(map),
m_lua(L), m_script(scriptIface),
m_gamedef(gamedef), m_gamedef(gamedef),
m_emerger(emerger), m_emerger(emerger),
m_random_spawn_timer(3), m_random_spawn_timer(3),
@ -826,7 +826,7 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
i != elapsed_timers.end(); i++){ i != elapsed_timers.end(); i++){
n = block->getNodeNoEx(i->first); n = block->getNodeNoEx(i->first);
v3s16 p = i->first + block->getPosRelative(); v3s16 p = i->first + block->getPosRelative();
if(scriptapi_node_on_timer(m_lua,p,n,i->second.elapsed)) if(m_script->node_on_timer(p,n,i->second.elapsed))
block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0)); block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
} }
} }
@ -847,17 +847,17 @@ bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
MapNode n_old = m_map->getNodeNoEx(p); MapNode n_old = m_map->getNodeNoEx(p);
// Call destructor // Call destructor
if(ndef->get(n_old).has_on_destruct) if(ndef->get(n_old).has_on_destruct)
scriptapi_node_on_destruct(m_lua, p, n_old); m_script->node_on_destruct(p, n_old);
// Replace node // Replace node
bool succeeded = m_map->addNodeWithEvent(p, n); bool succeeded = m_map->addNodeWithEvent(p, n);
if(!succeeded) if(!succeeded)
return false; return false;
// Call post-destructor // Call post-destructor
if(ndef->get(n_old).has_after_destruct) if(ndef->get(n_old).has_after_destruct)
scriptapi_node_after_destruct(m_lua, p, n_old); m_script->node_after_destruct(p, n_old);
// Call constructor // Call constructor
if(ndef->get(n).has_on_construct) if(ndef->get(n).has_on_construct)
scriptapi_node_on_construct(m_lua, p, n); m_script->node_on_construct(p, n);
return true; return true;
} }
@ -867,7 +867,7 @@ bool ServerEnvironment::removeNode(v3s16 p)
MapNode n_old = m_map->getNodeNoEx(p); MapNode n_old = m_map->getNodeNoEx(p);
// Call destructor // Call destructor
if(ndef->get(n_old).has_on_destruct) if(ndef->get(n_old).has_on_destruct)
scriptapi_node_on_destruct(m_lua, p, n_old); m_script->node_on_destruct(p, n_old);
// Replace with air // Replace with air
// This is slightly optimized compared to addNodeWithEvent(air) // This is slightly optimized compared to addNodeWithEvent(air)
bool succeeded = m_map->removeNodeWithEvent(p); bool succeeded = m_map->removeNodeWithEvent(p);
@ -875,7 +875,7 @@ bool ServerEnvironment::removeNode(v3s16 p)
return false; return false;
// Call post-destructor // Call post-destructor
if(ndef->get(n_old).has_after_destruct) if(ndef->get(n_old).has_after_destruct)
scriptapi_node_after_destruct(m_lua, p, n_old); m_script->node_after_destruct(p, n_old);
// Air doesn't require constructor // Air doesn't require constructor
return true; return true;
} }
@ -910,7 +910,6 @@ void ServerEnvironment::clearAllObjects()
if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER) if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
continue; continue;
u16 id = i->first; u16 id = i->first;
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){
MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block); MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
@ -931,7 +930,7 @@ void ServerEnvironment::clearAllObjects()
// Tell the object about removal // Tell the object about removal
obj->removingFromEnvironment(); obj->removingFromEnvironment();
// Deregister in scripting api // Deregister in scripting api
scriptapi_rm_object_reference(m_lua, obj); m_script->removeObjectReference(obj);
// Delete active object // Delete active object
if(obj->environmentDeletes()) if(obj->environmentDeletes())
@ -1031,8 +1030,6 @@ void ServerEnvironment::step(float dtime)
// Ignore disconnected players // Ignore disconnected players
if(player->peer_id == 0) if(player->peer_id == 0)
continue; continue;
v3f playerpos = player->getPosition();
// Move // Move
player->move(dtime, *m_map, 100*BS); player->move(dtime, *m_map, 100*BS);
@ -1162,7 +1159,7 @@ void ServerEnvironment::step(float dtime)
i != elapsed_timers.end(); i++){ i != elapsed_timers.end(); i++){
n = block->getNodeNoEx(i->first); n = block->getNodeNoEx(i->first);
p = i->first + block->getPosRelative(); p = i->first + block->getPosRelative();
if(scriptapi_node_on_timer(m_lua,p,n,i->second.elapsed)) if(m_script->node_on_timer(p,n,i->second.elapsed))
block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0)); block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
} }
} }
@ -1216,7 +1213,7 @@ void ServerEnvironment::step(float dtime)
/* /*
Step script environment (run global on_step()) Step script environment (run global on_step())
*/ */
scriptapi_environment_step(m_lua, dtime); m_script->environment_Step(dtime);
/* /*
Step active objects Step active objects
@ -1510,7 +1507,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
<<std::endl; <<std::endl;
// Register reference in scripting api (must be done before post-init) // Register reference in scripting api (must be done before post-init)
scriptapi_add_object_reference(m_lua, object); m_script->addObjectReference(object);
// Post-initialize object // Post-initialize object
object->addedToEnvironment(dtime_s); object->addedToEnvironment(dtime_s);
@ -1598,7 +1595,7 @@ void ServerEnvironment::removeRemovedObjects()
// Tell the object about removal // Tell the object about removal
obj->removingFromEnvironment(); obj->removingFromEnvironment();
// Deregister in scripting api // Deregister in scripting api
scriptapi_rm_object_reference(m_lua, obj); m_script->removeObjectReference(obj);
// Delete // Delete
if(obj->environmentDeletes()) if(obj->environmentDeletes())
@ -1904,7 +1901,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
// Tell the object about removal // Tell the object about removal
obj->removingFromEnvironment(); obj->removingFromEnvironment();
// Deregister in scripting api // Deregister in scripting api
scriptapi_rm_object_reference(m_lua, obj); m_script->removeObjectReference(obj);
// Delete active object // Delete active object
if(obj->environmentDeletes()) if(obj->environmentDeletes())
@ -2072,8 +2069,6 @@ void ClientEnvironment::step(float dtime)
*/ */
{ {
v3f lplayerpos = lplayer->getPosition();
// Apply physics // Apply physics
if(free_move == false && is_climbing == false) if(free_move == false && is_climbing == false)
{ {
@ -2174,7 +2169,7 @@ void ClientEnvironment::step(float dtime)
v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS); v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
MapNode n2 = m_map->getNodeNoEx(p2); MapNode n2 = m_map->getNodeNoEx(p2);
v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS); v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
MapNode n3 = m_map->getNodeNoEx(p2); MapNode n3 = m_map->getNodeNoEx(p3);
u32 damage_per_second = 0; u32 damage_per_second = 0;
damage_per_second = MYMAX(damage_per_second, damage_per_second = MYMAX(damage_per_second,
@ -2197,7 +2192,6 @@ void ClientEnvironment::step(float dtime)
i != m_players.end(); ++i) i != m_players.end(); ++i)
{ {
Player *player = *i; Player *player = *i;
v3f playerpos = player->getPosition();
/* /*
Handle non-local players Handle non-local players

@ -50,6 +50,7 @@ class IGameDef;
class Map; class Map;
class ServerMap; class ServerMap;
class ClientMap; class ClientMap;
class ScriptApi;
class Environment class Environment
{ {
@ -190,7 +191,7 @@ public:
class ServerEnvironment : public Environment class ServerEnvironment : public Environment
{ {
public: public:
ServerEnvironment(ServerMap *map, lua_State *L, IGameDef *gamedef, ServerEnvironment(ServerMap *map, ScriptApi *iface, IGameDef *gamedef,
IBackgroundBlockEmerger *emerger); IBackgroundBlockEmerger *emerger);
~ServerEnvironment(); ~ServerEnvironment();
@ -198,8 +199,9 @@ public:
ServerMap & getServerMap(); ServerMap & getServerMap();
lua_State* getLua() //TODO find way to remove this fct!
{ return m_lua; } ScriptApi* getScriptIface()
{ return m_script; }
IGameDef *getGameDef() IGameDef *getGameDef()
{ return m_gamedef; } { return m_gamedef; }
@ -348,7 +350,7 @@ private:
// The map // The map
ServerMap *m_map; ServerMap *m_map;
// Lua state // Lua state
lua_State *m_lua; ScriptApi* m_script;
// Game definition // Game definition
IGameDef *m_gamedef; IGameDef *m_gamedef;
// Background block emerger (the server, in practice) // Background block emerger (the server, in practice)

@ -66,6 +66,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sound_openal.h" #include "sound_openal.h"
#endif #endif
#include "event_manager.h" #include "event_manager.h"
#include <iomanip>
#include <list> #include <list>
#include "util/directiontables.h" #include "util/directiontables.h"
@ -134,6 +135,10 @@ struct TextDestPlayerInventory : public TextDest
m_client->sendInventoryFields(m_formname, fields); m_client->sendInventoryFields(m_formname, fields);
} }
void setFormName(std::string formname) {
m_formname = formname;
}
Client *m_client; Client *m_client;
std::string m_formname; std::string m_formname;
}; };
@ -847,7 +852,7 @@ void nodePlacementPrediction(Client &client,
<<") - Name not known"<<std::endl; <<") - Name not known"<<std::endl;
return; return;
} }
// Predict param2 // Predict param2 for facedir and wallmounted nodes
u8 param2 = 0; u8 param2 = 0;
if(nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED){ if(nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED){
v3s16 dir = nodepos - neighbourpos; v3s16 dir = nodepos - neighbourpos;
@ -859,8 +864,33 @@ void nodePlacementPrediction(Client &client,
param2 = dir.Z < 0 ? 5 : 4; param2 = dir.Z < 0 ? 5 : 4;
} }
} }
// TODO: Facedir prediction if(nodedef->get(id).param_type_2 == CPT2_FACEDIR){
// TODO: If predicted node is in attached_node group, check attachment v3s16 dir = nodepos - floatToInt(client.getEnv().getLocalPlayer()->getPosition(), BS);
if(abs(dir.X) > abs(dir.Z)){
param2 = dir.X < 0 ? 3 : 1;
} else {
param2 = dir.Z < 0 ? 2 : 0;
}
}
assert(param2 >= 0 && param2 <= 5);
//Check attachment if node is in group attached_node
if(((ItemGroupList) nodedef->get(id).groups)["attached_node"] != 0){
static v3s16 wallmounted_dirs[8] = {
v3s16(0,1,0),
v3s16(0,-1,0),
v3s16(1,0,0),
v3s16(-1,0,0),
v3s16(0,0,1),
v3s16(0,0,-1),
};
v3s16 pp;
if(nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED)
pp = p + wallmounted_dirs[param2];
else
pp = p + v3s16(0,-1,0);
if(!nodedef->get(map.getNode(pp)).walkable)
return;
}
// Add node to client map // Add node to client map
MapNode n(id, 0, param2); MapNode n(id, 0, param2);
try{ try{
@ -895,6 +925,7 @@ void the_game(
) )
{ {
FormspecFormSource* current_formspec = 0; FormspecFormSource* current_formspec = 0;
TextDestPlayerInventory* current_textdest = 0;
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager(); scene::ISceneManager* smgr = device->getSceneManager();
@ -1042,7 +1073,7 @@ void the_game(
u32 lasttime = device->getTimer()->getTime(); u32 lasttime = device->getTimer()->getTime();
while(device->run()) while(device->run())
{ {
f32 dtime=0; // in seconds f32 dtime = 0.033; // in seconds
if (cloud_menu_background) { if (cloud_menu_background) {
u32 time = device->getTimer()->getTime(); u32 time = device->getTimer()->getTime();
if(time > lasttime) if(time > lasttime)
@ -1136,7 +1167,7 @@ void the_game(
u32 lasttime = device->getTimer()->getTime(); u32 lasttime = device->getTimer()->getTime();
while(device->run()) while(device->run())
{ {
f32 dtime=0; // in seconds f32 dtime = 0.033; // in seconds
if (cloud_menu_background) { if (cloud_menu_background) {
u32 time = device->getTimer()->getTime(); u32 time = device->getTimer()->getTime();
if(time > lasttime) if(time > lasttime)
@ -1962,7 +1993,7 @@ void the_game(
{ {
s32 wheel = input->getMouseWheel(); s32 wheel = input->getMouseWheel();
u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1, u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,
hud.hotbar_itemcount-1); player->hud_hotbar_itemcount-1);
if(wheel < 0) if(wheel < 0)
{ {
@ -1986,7 +2017,7 @@ void the_game(
const KeyPress *kp = NumberKey + (i + 1) % 10; const KeyPress *kp = NumberKey + (i + 1) % 10;
if(input->wasKeyDown(*kp)) if(input->wasKeyDown(*kp))
{ {
if(i < PLAYER_INVENTORY_SIZE && i < hud.hotbar_itemcount) if(i < PLAYER_INVENTORY_SIZE && i < player->hud_hotbar_itemcount)
{ {
new_playeritem = i; new_playeritem = i;
@ -2211,19 +2242,23 @@ void the_game(
if (current_formspec == 0) if (current_formspec == 0)
{ {
/* Create menu */ /* Create menu */
/* Note: FormspecFormSource and TextDestPlayerInventory
* are deleted by guiFormSpecMenu */
current_formspec = new FormspecFormSource(*(event.show_formspec.formspec),&current_formspec); current_formspec = new FormspecFormSource(*(event.show_formspec.formspec),&current_formspec);
current_textdest = new TextDestPlayerInventory(&client,*(event.show_formspec.formname));
GUIFormSpecMenu *menu = GUIFormSpecMenu *menu =
new GUIFormSpecMenu(device, guiroot, -1, new GUIFormSpecMenu(device, guiroot, -1,
&g_menumgr, &g_menumgr,
&client, gamedef); &client, gamedef);
menu->setFormSource(current_formspec); menu->setFormSource(current_formspec);
menu->setTextDest(new TextDestPlayerInventory(&client,*(event.show_formspec.formname))); menu->setTextDest(current_textdest);
menu->drop(); menu->drop();
} }
else else
{ {
assert(current_textdest != 0);
/* update menu */ /* update menu */
current_textdest->setFormName(*(event.show_formspec.formname));
current_formspec->setForm(*(event.show_formspec.formspec)); current_formspec->setForm(*(event.show_formspec.formspec));
} }
delete(event.show_formspec.formspec); delete(event.show_formspec.formspec);
@ -2927,21 +2962,20 @@ void the_game(
static float endscenetime_avg = 0; static float endscenetime_avg = 0;
endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;*/ endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;*/
char temptext[300]; std::ostringstream os(std::ios_base::binary);
snprintf(temptext, 300, "%s (" os<<std::fixed
"R: range_all=%i" <<program_name_and_version
")" <<" (R: range_all="<<draw_control.range_all<<")"
" drawtime=%.0f, dtime_jitter = % .1f %%" <<std::setprecision(0)
", v_range = %.1f, RTT = %.3f", <<" drawtime = "<<drawtime_avg
program_name_and_version, <<std::setprecision(1)
draw_control.range_all, <<", dtime_jitter = "
drawtime_avg, <<(dtime_jitter1_max_fraction * 100.0)<<" %"
dtime_jitter1_max_fraction * 100.0, <<std::setprecision(1)
draw_control.wanted_range, <<", v_range = "<<draw_control.wanted_range
client.getRTT() <<std::setprecision(3)
); <<", RTT = "<<client.getRTT();
guitext->setText(narrow_to_wide(os.str()).c_str());
guitext->setText(narrow_to_wide(temptext).c_str());
guitext->setVisible(true); guitext->setVisible(true);
} }
else if(show_hud || show_chat) else if(show_hud || show_chat)
@ -2956,17 +2990,15 @@ void the_game(
if(show_debug) if(show_debug)
{ {
char temptext[300]; std::ostringstream os(std::ios_base::binary);
snprintf(temptext, 300, os<<std::setprecision(1)<<std::fixed
"(% .1f, % .1f, % .1f)" <<"(" <<(player_position.X/BS)
" (yaw = %.1f) (seed = %llu)", <<", "<<(player_position.Y/BS)
player_position.X/BS, <<", "<<(player_position.Z/BS)
player_position.Y/BS, <<") (yaw="<<(wrapDegrees_0_360(camera_yaw))
player_position.Z/BS, <<") (seed = "<<((unsigned long long)client.getMapSeed())
wrapDegrees_0_360(camera_yaw), <<")";
(unsigned long long)client.getMapSeed()); guitext2->setText(narrow_to_wide(os.str()).c_str());
guitext2->setText(narrow_to_wide(temptext).c_str());
guitext2->setVisible(true); guitext2->setVisible(true);
} }
else else
@ -3084,7 +3116,7 @@ void the_game(
ItemStack item; ItemStack item;
if(mlist != NULL) if(mlist != NULL)
item = mlist->getItem(client.getPlayerItem()); item = mlist->getItem(client.getPlayerItem());
camera.wield(item); camera.wield(item, client.getPlayerItem());
} }
/* /*

@ -121,7 +121,9 @@ GUIChatConsole::GUIChatConsole(
GUIChatConsole::~GUIChatConsole() GUIChatConsole::~GUIChatConsole()
{ {
delete m_font; #if USE_FREETYPE
m_font->drop();
#endif
} }
void GUIChatConsole::openConsole(f32 height) void GUIChatConsole::openConsole(f32 height)

@ -116,40 +116,18 @@ GUIConfigureWorld::GUIConfigureWorld(gui::IGUIEnvironment* env,
// mod_names // mod_names
if(!mod.is_modpack && if(!mod.is_modpack &&
mod_names.count(modname) == 0) mod_names.count(modname) == 0)
m_new_mod_names.insert(modname); m_settings.setBool("load_mod_"+modname, false);
} }
if(!m_new_mod_names.empty())
{
wchar_t* text = wgettext("Warning: Some mods are not configured yet.\n"
"They will be enabled by default when you save the configuration. ");
GUIMessageMenu *menu =
new GUIMessageMenu(Environment, Parent, -1, m_menumgr, text);
menu->drop();
delete[] text;
}
// find missing mods (mentioned in world.mt, but not installed) // find missing mods (mentioned in world.mt, but not installed)
std::set<std::string> missing_mods;
for(std::set<std::string>::iterator it = mod_names.begin(); for(std::set<std::string>::iterator it = mod_names.begin();
it != mod_names.end(); ++it) it != mod_names.end(); ++it)
{ {
std::string modname = *it; std::string modname = *it;
if(m_addonmods.count(modname) == 0) if(m_addonmods.count(modname) == 0)
missing_mods.insert(modname); m_settings.remove("load_mod_"+modname);
} }
if(!missing_mods.empty()) std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt";
{ m_settings.updateConfigFile(worldmtfile.c_str());
wchar_t* text = wgettext("Warning: Some configured mods are missing.\n"
"Their setting will be removed when you save the configuration. ");
GUIMessageMenu *menu =
new GUIMessageMenu(Environment, Parent, -1, m_menumgr, text);
delete[] text;
for(std::set<std::string>::iterator it = missing_mods.begin();
it != missing_mods.end(); ++it)
m_settings.remove("load_mod_"+(*it));
menu->drop();
}
} }
void GUIConfigureWorld::drawMenu() void GUIConfigureWorld::drawMenu()
@ -187,8 +165,6 @@ void GUIConfigureWorld::regenerateGui(v2u32 screensize)
DesiredRect = rect; DesiredRect = rect;
recalculateAbsolutePosition(false); recalculateAbsolutePosition(false);
v2s32 size = rect.getSize();
v2s32 topleft = v2s32(10, 10); v2s32 topleft = v2s32(10, 10);
/* /*
@ -388,11 +364,6 @@ bool GUIConfigureWorld::OnEvent(const SEvent& event)
return true; return true;
} }
case GUI_ID_SAVE: { case GUI_ID_SAVE: {
for(std::set<std::string>::iterator it = m_new_mod_names.begin();
it!= m_new_mod_names.end(); ++it)
{
m_settings.setBool("load_mod_"+(*it),true);
}
std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt"; std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt";
m_settings.updateConfigFile(worldmtfile.c_str()); m_settings.updateConfigFile(worldmtfile.c_str());
@ -558,22 +529,14 @@ void GUIConfigureWorld::buildTreeView(std::map<std::string, ModSpec> mods,
buildTreeView(mod.modpack_content, new_node); buildTreeView(mod.modpack_content, new_node);
else else
{ {
// set icon for node: ? for new mods, x for disabled mods, // set icon for node: x for disabled mods, checkmark for enabled mods
// checkmark for enabled mods bool mod_enabled = false;
if(m_new_mod_names.count(modname) > 0) if(m_settings.exists("load_mod_"+modname))
{ mod_enabled = m_settings.getBool("load_mod_"+modname);
new_node->setIcon(QUESTIONMARK_STR); if(mod_enabled)
} new_node->setIcon(CHECKMARK_STR);
else else
{ new_node->setIcon(CROSS_STR);
bool mod_enabled = true;
if(m_settings.exists("load_mod_"+modname))
mod_enabled = m_settings.getBool("load_mod_"+modname);
if(mod_enabled)
new_node->setIcon(CHECKMARK_STR);
else
new_node->setIcon(CROSS_STR);
}
} }
} }
} }
@ -690,7 +653,6 @@ void GUIConfigureWorld::enableMod(std::string modname)
m_nodes.find(modname); m_nodes.find(modname);
if(it != m_nodes.end()) if(it != m_nodes.end())
(*it).second->setIcon(CHECKMARK_STR); (*it).second->setIcon(CHECKMARK_STR);
m_new_mod_names.erase(modname);
//also enable all dependencies //also enable all dependencies
for(std::set<std::string>::iterator it=mspec.depends.begin(); for(std::set<std::string>::iterator it=mspec.depends.begin();
it != mspec.depends.end(); ++it) it != mspec.depends.end(); ++it)
@ -715,7 +677,6 @@ void GUIConfigureWorld::disableMod(std::string modname)
m_nodes.find(modname); m_nodes.find(modname);
if(it != m_nodes.end()) if(it != m_nodes.end())
(*it).second->setIcon(CROSS_STR); (*it).second->setIcon(CROSS_STR);
m_new_mod_names.erase(modname);
//also disable all mods that depend on this one //also disable all mods that depend on this one
std::pair<std::multimap<std::string, std::string>::iterator, std::pair<std::multimap<std::string, std::string>::iterator,
std::multimap<std::string, std::string>::iterator > rdep = std::multimap<std::string, std::string>::iterator > rdep =

@ -69,9 +69,6 @@ private:
// the settings in the world.mt file // the settings in the world.mt file
Settings m_settings; Settings m_settings;
// mods that are installed but not mentioned in world.mt file
std::set<std::string> m_new_mod_names;
// maps modnames to nodes in m_treeview // maps modnames to nodes in m_treeview
std::map<std::string,gui::IGUITreeViewNode*> m_nodes; std::map<std::string,gui::IGUITreeViewNode*> m_nodes;

@ -112,8 +112,6 @@ void GUICreateWorld::regenerateGui(v2u32 screensize)
DesiredRect = rect; DesiredRect = rect;
recalculateAbsolutePosition(false); recalculateAbsolutePosition(false);
v2s32 size = rect.getSize();
v2s32 topleft = v2s32(10+80, 10+70); v2s32 topleft = v2s32(10+80, 10+70);
/* /*
@ -137,6 +135,9 @@ void GUICreateWorld::regenerateGui(v2u32 screensize)
evt.EventType = EET_KEY_INPUT_EVENT; evt.EventType = EET_KEY_INPUT_EVENT;
evt.KeyInput.Key = KEY_END; evt.KeyInput.Key = KEY_END;
evt.KeyInput.PressedDown = true; evt.KeyInput.PressedDown = true;
evt.KeyInput.Char = 0;
evt.KeyInput.Control = 0;
evt.KeyInput.Shift = 0;
e->OnEvent(evt); e->OnEvent(evt);
} }
{ {

@ -418,9 +418,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_UPPERLEFT); e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_UPPERLEFT);
} else { } else {
irr::SEvent evt; irr::SEvent evt;
evt.KeyInput.Key = KEY_END;
evt.EventType = EET_KEY_INPUT_EVENT; evt.EventType = EET_KEY_INPUT_EVENT;
evt.KeyInput.Key = KEY_END;
evt.KeyInput.PressedDown = true; evt.KeyInput.PressedDown = true;
evt.KeyInput.Char = 0;
evt.KeyInput.Control = 0;
evt.KeyInput.Shift = 0;
e->OnEvent(evt); e->OnEvent(evt);
} }

@ -54,11 +54,11 @@ const wchar_t *contrib_core_strs[] = {
L"Lisa Milne (darkrose) <lisa@ltmnet.com>", L"Lisa Milne (darkrose) <lisa@ltmnet.com>",
L"Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>", L"Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>",
L"proller <proler@gmail.com>", L"proller <proler@gmail.com>",
L"sfan5 <sfan5@live.de>" L"sfan5 <sfan5@live.de>",
L"kahrl <kahrl@gmx.net>"
}; };
const wchar_t *contrib_active_strs[] = { const wchar_t *contrib_active_strs[] = {
L"kahrl <kahrl@gmx.net>",
L"sapier <sapier@gmx.net>", L"sapier <sapier@gmx.net>",
L"Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>", L"Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>",
L"Jurgen Doser (doserj) <jurgen.doser@gmail.com>", L"Jurgen Doser (doserj) <jurgen.doser@gmail.com>",

@ -95,7 +95,6 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
v2s32 size = rect.getSize(); v2s32 size = rect.getSize();
v2s32 topleft_client(40, 0); v2s32 topleft_client(40, 0);
v2s32 size_client = size - v2s32(40, 0);
/* /*
Add stuff Add stuff

@ -121,6 +121,9 @@ void GUITextInputMenu::regenerateGui(v2u32 screensize)
evt.EventType = EET_KEY_INPUT_EVENT; evt.EventType = EET_KEY_INPUT_EVENT;
evt.KeyInput.Key = KEY_END; evt.KeyInput.Key = KEY_END;
evt.KeyInput.PressedDown = true; evt.KeyInput.PressedDown = true;
evt.KeyInput.Char = 0;
evt.KeyInput.Control = 0;
evt.KeyInput.Shift = 0;
e->OnEvent(evt); e->OnEvent(evt);
} }
changeCtype(""); changeCtype("");

@ -96,7 +96,6 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
v2s32 size = rect.getSize(); v2s32 size = rect.getSize();
v2s32 topleft_client(40, 0); v2s32 topleft_client(40, 0);
v2s32 size_client = size - v2s32(40, 0);
int volume=(int)(g_settings->getFloat("sound_volume")*100); int volume=(int)(g_settings->getFloat("sound_volume")*100);
/* /*
Add stuff Add stuff

@ -43,7 +43,6 @@ Hud::Hud(video::IVideoDriver *driver, gui::IGUIEnvironment* guienv,
screensize = v2u32(0, 0); screensize = v2u32(0, 0);
displaycenter = v2s32(0, 0); displaycenter = v2s32(0, 0);
hotbar_imagesize = 48; hotbar_imagesize = 48;
hotbar_itemcount = 8;
tsrc = gamedef->getTextureSource(); tsrc = gamedef->getTextureSource();
@ -286,6 +285,7 @@ void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem) {
return; return;
} }
s32 hotbar_itemcount = player->hud_hotbar_itemcount;
s32 padding = hotbar_imagesize / 12; s32 padding = hotbar_imagesize / 12;
s32 width = hotbar_itemcount * (hotbar_imagesize + padding * 2); s32 width = hotbar_itemcount * (hotbar_imagesize + padding * 2);
v2s32 pos = centerlowerpos - v2s32(width / 2, hotbar_imagesize + padding * 2); v2s32 pos = centerlowerpos - v2s32(width / 2, hotbar_imagesize + padding * 2);

@ -36,6 +36,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define HUD_FLAG_CROSSHAIR_VISIBLE (1 << 2) #define HUD_FLAG_CROSSHAIR_VISIBLE (1 << 2)
#define HUD_FLAG_WIELDITEM_VISIBLE (1 << 3) #define HUD_FLAG_WIELDITEM_VISIBLE (1 << 3)
#define HUD_PARAM_HOTBAR_ITEMCOUNT 1
#define HUD_HOTBAR_ITEMCOUNT_DEFAULT 8
#define HUD_HOTBAR_ITEMCOUNT_MAX 23
class Player; class Player;
enum HudElementType { enum HudElementType {
@ -46,7 +51,7 @@ enum HudElementType {
}; };
enum HudElementStat { enum HudElementStat {
HUD_STAT_POS, HUD_STAT_POS = 0,
HUD_STAT_NAME, HUD_STAT_NAME,
HUD_STAT_SCALE, HUD_STAT_SCALE,
HUD_STAT_TEXT, HUD_STAT_TEXT,
@ -102,7 +107,6 @@ public:
v2u32 screensize; v2u32 screensize;
v2s32 displaycenter; v2s32 displaycenter;
s32 hotbar_imagesize; s32 hotbar_imagesize;
s32 hotbar_itemcount;
video::SColor crosshair_argb; video::SColor crosshair_argb;
video::SColor selectionbox_argb; video::SColor selectionbox_argb;

@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventorymanager.h" #include "inventorymanager.h"
#include "log.h" #include "log.h"
#include "environment.h" #include "environment.h"
#include "scriptapi.h" #include "cpp_api/scriptapi.h"
#include "serverobject.h" #include "serverobject.h"
#include "main.h" // for g_settings #include "main.h" // for g_settings
#include "settings.h" #include "settings.h"
@ -226,9 +226,8 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
to_inv.type == InventoryLocation::DETACHED && to_inv.type == InventoryLocation::DETACHED &&
from_inv.name == to_inv.name) from_inv.name == to_inv.name)
{ {
lua_State *L = player->getEnv()->getLua(); src_can_take_count = PLAYER_TO_SA(player)->detached_inventory_AllowMove(
src_can_take_count = scriptapi_detached_inventory_allow_move( from_inv.name, from_list, from_i,
L, from_inv.name, from_list, from_i,
to_list, to_i, try_take_count, player); to_list, to_i, try_take_count, player);
dst_can_put_count = src_can_take_count; dst_can_put_count = src_can_take_count;
} }
@ -237,20 +236,18 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
// Destination is detached // Destination is detached
if(to_inv.type == InventoryLocation::DETACHED) if(to_inv.type == InventoryLocation::DETACHED)
{ {
lua_State *L = player->getEnv()->getLua();
ItemStack src_item = list_from->getItem(from_i); ItemStack src_item = list_from->getItem(from_i);
src_item.count = try_take_count; src_item.count = try_take_count;
dst_can_put_count = scriptapi_detached_inventory_allow_put( dst_can_put_count = PLAYER_TO_SA(player)->detached_inventory_AllowPut(
L, to_inv.name, to_list, to_i, src_item, player); to_inv.name, to_list, to_i, src_item, player);
} }
// Source is detached // Source is detached
if(from_inv.type == InventoryLocation::DETACHED) if(from_inv.type == InventoryLocation::DETACHED)
{ {
lua_State *L = player->getEnv()->getLua();
ItemStack src_item = list_from->getItem(from_i); ItemStack src_item = list_from->getItem(from_i);
src_item.count = try_take_count; src_item.count = try_take_count;
src_can_take_count = scriptapi_detached_inventory_allow_take( src_can_take_count = PLAYER_TO_SA(player)->detached_inventory_AllowTake(
L, from_inv.name, from_list, from_i, src_item, player); from_inv.name, from_list, from_i, src_item, player);
} }
} }
@ -262,9 +259,8 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
to_inv.type == InventoryLocation::NODEMETA && to_inv.type == InventoryLocation::NODEMETA &&
from_inv.p == to_inv.p) from_inv.p == to_inv.p)
{ {
lua_State *L = player->getEnv()->getLua(); src_can_take_count = PLAYER_TO_SA(player)->nodemeta_inventory_AllowMove(
src_can_take_count = scriptapi_nodemeta_inventory_allow_move( from_inv.p, from_list, from_i,
L, from_inv.p, from_list, from_i,
to_list, to_i, try_take_count, player); to_list, to_i, try_take_count, player);
dst_can_put_count = src_can_take_count; dst_can_put_count = src_can_take_count;
} }
@ -273,20 +269,18 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
// Destination is nodemeta // Destination is nodemeta
if(to_inv.type == InventoryLocation::NODEMETA) if(to_inv.type == InventoryLocation::NODEMETA)
{ {
lua_State *L = player->getEnv()->getLua();
ItemStack src_item = list_from->getItem(from_i); ItemStack src_item = list_from->getItem(from_i);
src_item.count = try_take_count; src_item.count = try_take_count;
dst_can_put_count = scriptapi_nodemeta_inventory_allow_put( dst_can_put_count = PLAYER_TO_SA(player)->nodemeta_inventory_AllowPut(
L, to_inv.p, to_list, to_i, src_item, player); to_inv.p, to_list, to_i, src_item, player);
} }
// Source is nodemeta // Source is nodemeta
if(from_inv.type == InventoryLocation::NODEMETA) if(from_inv.type == InventoryLocation::NODEMETA)
{ {
lua_State *L = player->getEnv()->getLua();
ItemStack src_item = list_from->getItem(from_i); ItemStack src_item = list_from->getItem(from_i);
src_item.count = try_take_count; src_item.count = try_take_count;
src_can_take_count = scriptapi_nodemeta_inventory_allow_take( src_can_take_count = PLAYER_TO_SA(player)->nodemeta_inventory_AllowTake(
L, from_inv.p, from_list, from_i, src_item, player); from_inv.p, from_list, from_i, src_item, player);
} }
} }
@ -412,9 +406,8 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
to_inv.type == InventoryLocation::DETACHED && to_inv.type == InventoryLocation::DETACHED &&
from_inv.name == to_inv.name) from_inv.name == to_inv.name)
{ {
lua_State *L = player->getEnv()->getLua(); PLAYER_TO_SA(player)->detached_inventory_OnMove(
scriptapi_detached_inventory_on_move( from_inv.name, from_list, from_i,
L, from_inv.name, from_list, from_i,
to_list, to_i, count, player); to_list, to_i, count, player);
} }
else else
@ -422,16 +415,14 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
// Destination is detached // Destination is detached
if(to_inv.type == InventoryLocation::DETACHED) if(to_inv.type == InventoryLocation::DETACHED)
{ {
lua_State *L = player->getEnv()->getLua(); PLAYER_TO_SA(player)->detached_inventory_OnPut(
scriptapi_detached_inventory_on_put( to_inv.name, to_list, to_i, src_item, player);
L, to_inv.name, to_list, to_i, src_item, player);
} }
// Source is detached // Source is detached
if(from_inv.type == InventoryLocation::DETACHED) if(from_inv.type == InventoryLocation::DETACHED)
{ {
lua_State *L = player->getEnv()->getLua(); PLAYER_TO_SA(player)->detached_inventory_OnTake(
scriptapi_detached_inventory_on_take( from_inv.name, from_list, from_i, src_item, player);
L, from_inv.name, from_list, from_i, src_item, player);
} }
} }
@ -442,25 +433,22 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
to_inv.type == InventoryLocation::NODEMETA && to_inv.type == InventoryLocation::NODEMETA &&
from_inv.p == to_inv.p) from_inv.p == to_inv.p)
{ {
lua_State *L = player->getEnv()->getLua(); PLAYER_TO_SA(player)->nodemeta_inventory_OnMove(
scriptapi_nodemeta_inventory_on_move( from_inv.p, from_list, from_i,
L, from_inv.p, from_list, from_i,
to_list, to_i, count, player); to_list, to_i, count, player);
} }
else{ else{
// Destination is nodemeta // Destination is nodemeta
if(to_inv.type == InventoryLocation::NODEMETA) if(to_inv.type == InventoryLocation::NODEMETA)
{ {
lua_State *L = player->getEnv()->getLua(); PLAYER_TO_SA(player)->nodemeta_inventory_OnPut(
scriptapi_nodemeta_inventory_on_put( to_inv.p, to_list, to_i, src_item, player);
L, to_inv.p, to_list, to_i, src_item, player);
} }
// Source is nodemeta // Source is nodemeta
else if(from_inv.type == InventoryLocation::NODEMETA) else if(from_inv.type == InventoryLocation::NODEMETA)
{ {
lua_State *L = player->getEnv()->getLua(); PLAYER_TO_SA(player)->nodemeta_inventory_OnTake(
scriptapi_nodemeta_inventory_on_take( from_inv.p, from_list, from_i, src_item, player);
L, from_inv.p, from_list, from_i, src_item, player);
} }
} }
@ -563,21 +551,19 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
// Source is detached // Source is detached
if(from_inv.type == InventoryLocation::DETACHED) if(from_inv.type == InventoryLocation::DETACHED)
{ {
lua_State *L = player->getEnv()->getLua();
ItemStack src_item = list_from->getItem(from_i); ItemStack src_item = list_from->getItem(from_i);
src_item.count = take_count; src_item.count = take_count;
src_can_take_count = scriptapi_detached_inventory_allow_take( src_can_take_count = PLAYER_TO_SA(player)->detached_inventory_AllowTake(
L, from_inv.name, from_list, from_i, src_item, player); from_inv.name, from_list, from_i, src_item, player);
} }
// Source is nodemeta // Source is nodemeta
if(from_inv.type == InventoryLocation::NODEMETA) if(from_inv.type == InventoryLocation::NODEMETA)
{ {
lua_State *L = player->getEnv()->getLua();
ItemStack src_item = list_from->getItem(from_i); ItemStack src_item = list_from->getItem(from_i);
src_item.count = take_count; src_item.count = take_count;
src_can_take_count = scriptapi_nodemeta_inventory_allow_take( src_can_take_count = PLAYER_TO_SA(player)->nodemeta_inventory_AllowTake(
L, from_inv.p, from_list, from_i, src_item, player); from_inv.p, from_list, from_i, src_item, player);
} }
if(src_can_take_count != -1 && src_can_take_count < take_count) if(src_can_take_count != -1 && src_can_take_count < take_count)
@ -590,7 +576,7 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
// Drop the item // Drop the item
ItemStack item1 = list_from->getItem(from_i); ItemStack item1 = list_from->getItem(from_i);
item1.count = take_count; item1.count = take_count;
if(scriptapi_item_on_drop(player->getEnv()->getLua(), item1, player, if(PLAYER_TO_SA(player)->item_OnDrop(item1, player,
player->getBasePosition() + v3f(0,1,0))) player->getBasePosition() + v3f(0,1,0)))
{ {
actually_dropped_count = take_count - item1.count; actually_dropped_count = take_count - item1.count;
@ -627,17 +613,15 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
// Source is detached // Source is detached
if(from_inv.type == InventoryLocation::DETACHED) if(from_inv.type == InventoryLocation::DETACHED)
{ {
lua_State *L = player->getEnv()->getLua(); PLAYER_TO_SA(player)->detached_inventory_OnTake(
scriptapi_detached_inventory_on_take( from_inv.name, from_list, from_i, src_item, player);
L, from_inv.name, from_list, from_i, src_item, player);
} }
// Source is nodemeta // Source is nodemeta
if(from_inv.type == InventoryLocation::NODEMETA) if(from_inv.type == InventoryLocation::NODEMETA)
{ {
lua_State *L = player->getEnv()->getLua(); PLAYER_TO_SA(player)->nodemeta_inventory_OnTake(
scriptapi_nodemeta_inventory_on_take( from_inv.p, from_list, from_i, src_item, player);
L, from_inv.p, from_list, from_i, src_item, player);
} }
/* /*

@ -57,6 +57,7 @@ public:
int Lock(); int Lock();
int Unlock(); int Unlock();
bool IsInitialized() { return initialized; } bool IsInitialized() { return initialized; }
private: private:
#if (defined(WIN32) || defined(_WIN32_WCE)) #if (defined(WIN32) || defined(_WIN32_WCE))
#ifdef JMUTEX_CRITICALSECTION #ifdef JMUTEX_CRITICALSECTION
@ -66,6 +67,14 @@ private:
#endif // JMUTEX_CRITICALSECTION #endif // JMUTEX_CRITICALSECTION
#else // pthread mutex #else // pthread mutex
pthread_mutex_t mutex; pthread_mutex_t mutex;
bool IsLocked() {
if (pthread_mutex_trylock(&mutex)) {
pthread_mutex_unlock(&mutex);
return true;
}
return false;
}
#endif // WIN32 #endif // WIN32
bool initialized; bool initialized;
}; };

@ -73,6 +73,7 @@ void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
if(isAttached) if(isAttached)
{ {
setPosition(overridePosition); setPosition(overridePosition);
m_sneak_node_exists = false;
return; return;
} }
@ -85,6 +86,7 @@ void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
{ {
position += m_speed * dtime; position += m_speed * dtime;
setPosition(position); setPosition(position);
m_sneak_node_exists = false;
return; return;
} }

@ -1845,7 +1845,9 @@ int main(int argc, char *argv[])
MenuMusicFetcher soundfetcher; MenuMusicFetcher soundfetcher;
ISoundManager *sound = NULL; ISoundManager *sound = NULL;
#if USE_SOUND
sound = createOpenALSoundManager(&soundfetcher); sound = createOpenALSoundManager(&soundfetcher);
#endif
if(!sound) if(!sound)
sound = &dummySoundManager; sound = &dummySoundManager;
SimpleSoundSpec spec; SimpleSoundSpec spec;
@ -1940,6 +1942,9 @@ int main(int argc, char *argv[])
sound = NULL; sound = NULL;
} }
// Save controls status
menu->readInput(&menudata);
infostream<<"Dropping main menu"<<std::endl; infostream<<"Dropping main menu"<<std::endl;
menu->drop(); menu->drop();
@ -2145,7 +2150,9 @@ int main(int argc, char *argv[])
*/ */
device->drop(); device->drop();
delete font; #if USE_FREETYPE
font->drop();
#endif
#endif // !SERVER #endif // !SERVER

@ -288,10 +288,10 @@ void Map::unspreadLight(enum LightBank bank,
continue; continue;
// Calculate relative position in block // Calculate relative position in block
v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE; //v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
// Get node straight from the block // Get node straight from the block
MapNode n = block->getNode(relpos); //MapNode n = block->getNode(relpos);
u8 oldlight = j->second; u8 oldlight = j->second;
@ -937,7 +937,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
*/ */
v3s16 toppos = p + v3s16(0,1,0); v3s16 toppos = p + v3s16(0,1,0);
v3s16 bottompos = p + v3s16(0,-1,0); //v3s16 bottompos = p + v3s16(0,-1,0);
bool node_under_sunlight = true; bool node_under_sunlight = true;
std::set<v3s16> light_sources; std::set<v3s16> light_sources;
@ -1246,7 +1246,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
// Get the brightest neighbour node and propagate light from it // Get the brightest neighbour node and propagate light from it
v3s16 n2p = getBrightestNeighbour(bank, p); v3s16 n2p = getBrightestNeighbour(bank, p);
try{ try{
MapNode n2 = getNode(n2p); //MapNode n2 = getNode(n2p);
lightNeighbors(bank, n2p, modified_blocks); lightNeighbors(bank, n2p, modified_blocks);
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
@ -1755,7 +1755,7 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
} }
//relax up //relax up
if (relax && p0.Y <= water_level && liquid_levels[D_TOP] == 0 && if (relax && ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) && liquid_levels[D_TOP] == 0 &&
liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE &&
total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level- total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level-
(can_liquid_same_level - relax) && (can_liquid_same_level - relax) &&
@ -2831,7 +2831,7 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
sector = new ServerMapSector(this, p2d, m_gamedef); sector = new ServerMapSector(this, p2d, m_gamedef);
// Sector position on map in nodes // Sector position on map in nodes
v2s16 nodepos2d = p2d * MAP_BLOCKSIZE; //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
/* /*
Insert to container Insert to container

@ -71,6 +71,12 @@ Ore *createOre(OreType type) {
} }
Ore::~Ore() {
delete np;
delete noise;
}
void Ore::resolveNodeNames(INodeDefManager *ndef) { void Ore::resolveNodeNames(INodeDefManager *ndef) {
if (ore == CONTENT_IGNORE) { if (ore == CONTENT_IGNORE) {
ore = ndef->getId(ore_name); ore = ndef->getId(ore_name);
@ -347,23 +353,18 @@ bool MapgenV6Params::readParams(Settings *settings) {
freq_desert = settings->getFloat("mgv6_freq_desert"); freq_desert = settings->getFloat("mgv6_freq_desert");
freq_beach = settings->getFloat("mgv6_freq_beach"); freq_beach = settings->getFloat("mgv6_freq_beach");
np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base"); bool success =
np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher"); settings->getNoiseParams("mgv6_np_terrain_base", np_terrain_base) &&
np_steepness = settings->getNoiseParams("mgv6_np_steepness"); settings->getNoiseParams("mgv6_np_terrain_higher", np_terrain_higher) &&
np_height_select = settings->getNoiseParams("mgv6_np_height_select"); settings->getNoiseParams("mgv6_np_steepness", np_steepness) &&
np_mud = settings->getNoiseParams("mgv6_np_mud"); settings->getNoiseParams("mgv6_np_height_select", np_height_select) &&
np_beach = settings->getNoiseParams("mgv6_np_beach"); settings->getNoiseParams("mgv6_np_mud", np_mud) &&
np_biome = settings->getNoiseParams("mgv6_np_biome"); settings->getNoiseParams("mgv6_np_beach", np_beach) &&
np_cave = settings->getNoiseParams("mgv6_np_cave"); settings->getNoiseParams("mgv6_np_biome", np_biome) &&
np_humidity = settings->getNoiseParams("mgv6_np_humidity"); settings->getNoiseParams("mgv6_np_cave", np_cave) &&
np_trees = settings->getNoiseParams("mgv6_np_trees"); settings->getNoiseParams("mgv6_np_humidity", np_humidity) &&
np_apple_trees = settings->getNoiseParams("mgv6_np_apple_trees"); settings->getNoiseParams("mgv6_np_trees", np_trees) &&
settings->getNoiseParams("mgv6_np_apple_trees", np_apple_trees);
bool success =
np_terrain_base && np_terrain_higher && np_steepness &&
np_height_select && np_trees && np_mud &&
np_beach && np_biome && np_cave &&
np_humidity && np_apple_trees;
return success; return success;
} }
@ -387,16 +388,13 @@ void MapgenV6Params::writeParams(Settings *settings) {
bool MapgenV7Params::readParams(Settings *settings) { bool MapgenV7Params::readParams(Settings *settings) {
np_terrain_base = settings->getNoiseParams("mgv7_np_terrain_base"); bool success =
np_terrain_alt = settings->getNoiseParams("mgv7_np_terrain_alt"); settings->getNoiseParams("mgv7_np_terrain_base", np_terrain_base) &&
np_terrain_mod = settings->getNoiseParams("mgv7_np_terrain_mod"); settings->getNoiseParams("mgv7_np_terrain_alt", np_terrain_alt) &&
np_terrain_persist = settings->getNoiseParams("mgv7_np_terrain_persist"); settings->getNoiseParams("mgv7_np_terrain_mod", np_terrain_mod) &&
np_height_select = settings->getNoiseParams("mgv7_np_height_select"); settings->getNoiseParams("mgv7_np_terrain_persist", np_terrain_persist) &&
np_ridge = settings->getNoiseParams("mgv7_np_ridge"); settings->getNoiseParams("mgv7_np_height_select", np_height_select) &&
settings->getNoiseParams("mgv7_np_ridge", np_ridge);
bool success =
np_terrain_base && np_terrain_alt && np_terrain_mod &&
np_terrain_persist && np_height_select && np_ridge;
return success; return success;
} }

@ -74,7 +74,8 @@ struct MapgenParams {
} }
virtual bool readParams(Settings *settings) = 0; virtual bool readParams(Settings *settings) = 0;
virtual void writeParams(Settings *settings) {}; virtual void writeParams(Settings *settings) = 0;
virtual ~MapgenParams() {}
}; };
class Mapgen { class Mapgen {
@ -86,6 +87,8 @@ public:
ManualMapVoxelManipulator *vm; ManualMapVoxelManipulator *vm;
INodeDefManager *ndef; INodeDefManager *ndef;
virtual ~Mapgen() {}
void updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax); void updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax);
void setLighting(v3s16 nmin, v3s16 nmax, u8 light); void setLighting(v3s16 nmin, v3s16 nmax, u8 light);
void lightSpread(VoxelArea &a, v3s16 p, u8 light); void lightSpread(VoxelArea &a, v3s16 p, u8 light);
@ -105,6 +108,7 @@ struct MapgenFactory {
virtual Mapgen *createMapgen(int mgid, MapgenParams *params, virtual Mapgen *createMapgen(int mgid, MapgenParams *params,
EmergeManager *emerge) = 0; EmergeManager *emerge) = 0;
virtual MapgenParams *createMapgenParams() = 0; virtual MapgenParams *createMapgenParams() = 0;
virtual ~MapgenFactory() {}
}; };
enum OreType { enum OreType {
@ -140,6 +144,8 @@ public:
noise = NULL; noise = NULL;
} }
virtual ~Ore();
void resolveNodeNames(INodeDefManager *ndef); void resolveNodeNames(INodeDefManager *ndef);
void placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); void placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
virtual void generate(ManualMapVoxelManipulator *vm, int seed, virtual void generate(ManualMapVoxelManipulator *vm, int seed,
@ -147,11 +153,13 @@ public:
}; };
class OreScatter : public Ore { class OreScatter : public Ore {
~OreScatter() {}
virtual void generate(ManualMapVoxelManipulator *vm, int seed, virtual void generate(ManualMapVoxelManipulator *vm, int seed,
u32 blockseed, v3s16 nmin, v3s16 nmax); u32 blockseed, v3s16 nmin, v3s16 nmax);
}; };
class OreSheet : public Ore { class OreSheet : public Ore {
~OreSheet() {}
virtual void generate(ManualMapVoxelManipulator *vm, int seed, virtual void generate(ManualMapVoxelManipulator *vm, int seed,
u32 blockseed, v3s16 nmin, v3s16 nmax); u32 blockseed, v3s16 nmin, v3s16 nmax);
}; };

@ -84,17 +84,14 @@ void NoiseIndev::transformNoiseMapFarScale(float xx, float yy, float zz) {
MapgenIndev::MapgenIndev(int mapgenid, MapgenIndevParams *params, EmergeManager *emerge) MapgenIndev::MapgenIndev(int mapgenid, MapgenIndevParams *params, EmergeManager *emerge)
: MapgenV6(mapgenid, params, emerge) : MapgenV6(mapgenid, params, emerge)
{ {
noiseindev_terrain_base = new NoiseIndev(params->npindev_terrain_base, seed, csize.X, csize.Z); 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_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); 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); noiseindev_mud = new NoiseIndev(&params->npindev_mud, seed, csize.X, csize.Z);
// noise_trees = new Noise(params->np_trees, seed, csize.X, csize.Y); noiseindev_float_islands1 = new NoiseIndev(&params->npindev_float_islands1, seed, csize.X, csize.Y, csize.Z);
noiseindev_mud = new NoiseIndev(params->npindev_mud, seed, csize.X, csize.Z); noiseindev_float_islands2 = new NoiseIndev(&params->npindev_float_islands2, seed, csize.X, csize.Y, csize.Z);
// noise_beach = new Noise(params->np_beach, seed, csize.X, csize.Y); noiseindev_float_islands3 = new NoiseIndev(&params->npindev_float_islands3, seed, csize.X, csize.Z);
noiseindev_float_islands1 = new NoiseIndev(params->npindev_float_islands1, seed, csize.X, csize.Y, csize.Z); noiseindev_biome = new NoiseIndev(&params->npindev_biome, seed, csize.X, 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() { MapgenIndev::~MapgenIndev() {
@ -170,46 +167,41 @@ void MapgenIndev::calculateNoise() {
} }
bool MapgenIndevParams::readParams(Settings *settings) { bool MapgenIndevParams::readParams(Settings *settings) {
freq_desert = settings->getFloat("mgv6_freq_desert"); freq_desert = settings->getFloat("mgv6_freq_desert");
freq_beach = settings->getFloat("mgv6_freq_beach"); freq_beach = settings->getFloat("mgv6_freq_beach");
npindev_terrain_base = settings->getNoiseIndevParams("mgindev_np_terrain_base"); bool success =
npindev_terrain_higher = settings->getNoiseIndevParams("mgindev_np_terrain_higher"); settings->getNoiseIndevParams("mgindev_np_terrain_base", npindev_terrain_base) &&
npindev_steepness = settings->getNoiseIndevParams("mgindev_np_steepness"); settings->getNoiseIndevParams("mgindev_np_terrain_higher", npindev_terrain_higher) &&
np_height_select = settings->getNoiseParams("mgv6_np_height_select"); settings->getNoiseIndevParams("mgindev_np_steepness", npindev_steepness) &&
np_trees = settings->getNoiseParams("mgv6_np_trees"); settings->getNoiseParams("mgv6_np_height_select", np_height_select) &&
npindev_mud = settings->getNoiseIndevParams("mgindev_np_mud"); settings->getNoiseParams("mgv6_np_trees", np_trees) &&
np_beach = settings->getNoiseParams("mgv6_np_beach"); settings->getNoiseIndevParams("mgindev_np_mud", npindev_mud) &&
npindev_biome = settings->getNoiseIndevParams("mgindev_np_biome"); settings->getNoiseParams("mgv6_np_beach", np_beach) &&
np_cave = settings->getNoiseParams("mgv6_np_cave"); settings->getNoiseIndevParams("mgindev_np_biome", npindev_biome) &&
npindev_float_islands1 = settings->getNoiseIndevParams("mgindev_np_float_islands1"); settings->getNoiseParams("mgv6_np_cave", np_cave) &&
npindev_float_islands2 = settings->getNoiseIndevParams("mgindev_np_float_islands2"); settings->getNoiseIndevParams("mgindev_np_float_islands1", npindev_float_islands1) &&
npindev_float_islands3 = settings->getNoiseIndevParams("mgindev_np_float_islands3"); settings->getNoiseIndevParams("mgindev_np_float_islands2", npindev_float_islands2) &&
settings->getNoiseIndevParams("mgindev_np_float_islands3", npindev_float_islands3);
bool success = return 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) { void MapgenIndevParams::writeParams(Settings *settings) {
settings->setFloat("mgv6_freq_desert", freq_desert); settings->setFloat("mgv6_freq_desert", freq_desert);
settings->setFloat("mgv6_freq_beach", freq_beach); settings->setFloat("mgv6_freq_beach", freq_beach);
settings->setNoiseIndevParams("mgindev_np_terrain_base", npindev_terrain_base); settings->setNoiseIndevParams("mgindev_np_terrain_base", npindev_terrain_base);
settings->setNoiseIndevParams("mgindev_np_terrain_higher", npindev_terrain_higher); settings->setNoiseIndevParams("mgindev_np_terrain_higher", npindev_terrain_higher);
settings->setNoiseIndevParams("mgindev_np_steepness", npindev_steepness); settings->setNoiseIndevParams("mgindev_np_steepness", npindev_steepness);
settings->setNoiseParams("mgv6_np_height_select", np_height_select); settings->setNoiseParams("mgv6_np_height_select", np_height_select);
settings->setNoiseParams("mgv6_np_trees", np_trees); settings->setNoiseParams("mgv6_np_trees", np_trees);
settings->setNoiseIndevParams("mgindev_np_mud", npindev_mud); settings->setNoiseIndevParams("mgindev_np_mud", npindev_mud);
settings->setNoiseParams("mgv6_np_beach", np_beach); settings->setNoiseParams("mgv6_np_beach", np_beach);
settings->setNoiseIndevParams("mgindev_np_biome", npindev_biome); settings->setNoiseIndevParams("mgindev_np_biome", npindev_biome);
settings->setNoiseParams("mgv6_np_cave", np_cave); settings->setNoiseParams("mgv6_np_cave", np_cave);
settings->setNoiseIndevParams("mgindev_np_float_islands1", npindev_float_islands1); settings->setNoiseIndevParams("mgindev_np_float_islands1", npindev_float_islands1);
settings->setNoiseIndevParams("mgindev_np_float_islands2", npindev_float_islands2); settings->setNoiseIndevParams("mgindev_np_float_islands2", npindev_float_islands2);
settings->setNoiseIndevParams("mgindev_np_float_islands3", npindev_float_islands3); settings->setNoiseIndevParams("mgindev_np_float_islands3", npindev_float_islands3);
} }

@ -32,30 +32,33 @@ struct NoiseIndevParams : public NoiseParams {
float farscale; float farscale;
float farspread; float farspread;
NoiseIndevParams(){} NoiseIndevParams() {}
NoiseIndevParams(float offset_, float scale_, v3f spread_, int seed_, int octaves_, float persist_, float farscale_ = 1, float farspread_ = 1) NoiseIndevParams(float offset_, float scale_, v3f spread_,
int seed_, int octaves_, float persist_,
float farscale_ = 1, float farspread_ = 1)
{ {
offset = offset_; offset = offset_;
scale = scale_; scale = scale_;
spread = spread_; spread = spread_;
seed = seed_; seed = seed_;
octaves = octaves_; octaves = octaves_;
persist = persist_; persist = persist_;
farscale = farscale_; farscale = farscale_;
farspread = farspread_; farspread = farspread_;
} }
~NoiseIndevParams() {}
}; };
#define getNoiseIndevParams(x) getStruct<NoiseIndevParams>((x), "f,f,v3,s32,s32,f,f,f") #define getNoiseIndevParams(x, y) getStruct((x), "f,f,v3,s32,s32,f,f,f", &(y), sizeof(y))
#define setNoiseIndevParams(x, y) setStruct((x), "f,f,v3,s32,s32,f,f,f", (y)) #define setNoiseIndevParams(x, y) setStruct((x), "f,f,v3,s32,s32,f,f,f", &(y))
class NoiseIndev : public Noise { class NoiseIndev : public Noise {
public: public:
NoiseIndevParams *npindev; NoiseIndevParams *npindev;
//NoiseIndev() {}; virtual ~NoiseIndev() {};
NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy); NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy);
NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy, int sz); NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy, int sz);
void init(NoiseIndevParams *np, int seed, int sx, int sy, int sz); void init(NoiseIndevParams *np, int seed, int sx, int sy, int sz);
@ -77,34 +80,34 @@ extern NoiseIndevParams nparams_indev_def_float_islands;
*/ */
struct MapgenIndevParams : public MapgenV6Params { struct MapgenIndevParams : public MapgenV6Params {
NoiseIndevParams *npindev_terrain_base; NoiseIndevParams npindev_terrain_base;
NoiseIndevParams *npindev_terrain_higher; NoiseIndevParams npindev_terrain_higher;
NoiseIndevParams *npindev_steepness; NoiseIndevParams npindev_steepness;
//NoiseParams *np_height_select; //NoiseParams *np_height_select;
//NoiseParams *np_trees; //NoiseParams *np_trees;
NoiseIndevParams *npindev_mud; NoiseIndevParams npindev_mud;
//NoiseParams *np_beach; //NoiseParams *np_beach;
NoiseIndevParams *npindev_biome; NoiseIndevParams npindev_biome;
//NoiseParams *np_cave; //NoiseParams *np_cave;
NoiseIndevParams *npindev_float_islands1; NoiseIndevParams npindev_float_islands1;
NoiseIndevParams *npindev_float_islands2; NoiseIndevParams npindev_float_islands2;
NoiseIndevParams *npindev_float_islands3; NoiseIndevParams npindev_float_islands3;
MapgenIndevParams() { MapgenIndevParams() {
//freq_desert = 0.45; //freq_desert = 0.45;
//freq_beach = 0.15; //freq_beach = 0.15;
npindev_terrain_base = &nparams_indev_def; //&nparams_indev_def_terrain_base; npindev_terrain_base = nparams_indev_def; //&nparams_indev_def_terrain_base;
npindev_terrain_higher = &nparams_indev_def; //&nparams_indev_def_terrain_higher; npindev_terrain_higher = nparams_indev_def; //&nparams_indev_def_terrain_higher;
npindev_steepness = &nparams_indev_def; //&nparams_indev_def_steepness; npindev_steepness = nparams_indev_def; //&nparams_indev_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_trees = &nparams_v6_def_trees;
npindev_mud = &nparams_indev_def; //&nparams_indev_def_mud; npindev_mud = nparams_indev_def; //&nparams_indev_def_mud;
//np_beach = &nparams_v6_def_beach; //np_beach = &nparams_v6_def_beach;
npindev_biome = &nparams_indev_def; //&nparams_indev_def_biome; npindev_biome = nparams_indev_def; //&nparams_indev_def_biome;
//np_cave = &nparams_v6_def_cave; //np_cave = &nparams_v6_def_cave;
npindev_float_islands1 = &nparams_indev_def; //&nparams_indev_def_float_islands; npindev_float_islands1 = nparams_indev_def; //&nparams_indev_def_float_islands;
npindev_float_islands2 = &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; npindev_float_islands3 = nparams_indev_def; //&nparams_indev_def_float_islands;
} }

@ -24,8 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct MapgenSinglenodeParams : public MapgenParams { struct MapgenSinglenodeParams : public MapgenParams {
MapgenSinglenodeParams() { MapgenSinglenodeParams() {}
} ~MapgenSinglenodeParams() {}
bool readParams(Settings *settings); bool readParams(Settings *settings);
void writeParams(Settings *settings); void writeParams(Settings *settings);

@ -80,18 +80,18 @@ MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge)
this->ystride = csize.X; //////fix this this->ystride = csize.X; //////fix this
np_cave = params->np_cave; np_cave = &params->np_cave;
np_humidity = params->np_humidity; np_humidity = &params->np_humidity;
np_trees = params->np_trees; np_trees = &params->np_trees;
np_apple_trees = params->np_apple_trees; np_apple_trees = &params->np_apple_trees;
noise_terrain_base = new Noise(params->np_terrain_base, seed, csize.X, csize.Y); noise_terrain_base = new Noise(&params->np_terrain_base, seed, csize.X, csize.Y);
noise_terrain_higher = new Noise(params->np_terrain_higher, seed, csize.X, csize.Y); noise_terrain_higher = new Noise(&params->np_terrain_higher, seed, csize.X, csize.Y);
noise_steepness = new Noise(params->np_steepness, seed, csize.X, csize.Y); noise_steepness = new Noise(&params->np_steepness, seed, csize.X, csize.Y);
noise_height_select = new Noise(params->np_height_select, seed, csize.X, csize.Y); noise_height_select = new Noise(&params->np_height_select, seed, csize.X, csize.Y);
noise_mud = new Noise(params->np_mud, seed, csize.X, csize.Y); noise_mud = new Noise(&params->np_mud, seed, csize.X, csize.Y);
noise_beach = new Noise(params->np_beach, seed, csize.X, csize.Y); noise_beach = new Noise(&params->np_beach, seed, csize.X, csize.Y);
noise_biome = new Noise(params->np_biome, seed, csize.X, csize.Y); noise_biome = new Noise(&params->np_biome, seed, csize.X, csize.Y);
} }
@ -375,8 +375,6 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
v3s16 blockpos = data->blockpos_requested; v3s16 blockpos = data->blockpos_requested;
v3s16 blockpos_min = data->blockpos_min; v3s16 blockpos_min = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max; v3s16 blockpos_max = data->blockpos_max;
v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
// Area of central chunk // Area of central chunk
node_min = blockpos_min*MAP_BLOCKSIZE; node_min = blockpos_min*MAP_BLOCKSIZE;

@ -45,35 +45,36 @@ extern NoiseParams nparams_v6_def_apple_trees;
struct MapgenV6Params : public MapgenParams { struct MapgenV6Params : public MapgenParams {
float freq_desert; float freq_desert;
float freq_beach; float freq_beach;
NoiseParams *np_terrain_base; NoiseParams np_terrain_base;
NoiseParams *np_terrain_higher; NoiseParams np_terrain_higher;
NoiseParams *np_steepness; NoiseParams np_steepness;
NoiseParams *np_height_select; NoiseParams np_height_select;
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_humidity;
NoiseParams *np_trees; NoiseParams np_trees;
NoiseParams *np_apple_trees; NoiseParams np_apple_trees;
MapgenV6Params() { MapgenV6Params() {
freq_desert = 0.45; freq_desert = 0.45;
freq_beach = 0.15; freq_beach = 0.15;
np_terrain_base = &nparams_v6_def_terrain_base; np_terrain_base = nparams_v6_def_terrain_base;
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_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_humidity = nparams_v6_def_humidity;
np_trees = &nparams_v6_def_trees; np_trees = nparams_v6_def_trees;
np_apple_trees = &nparams_v6_def_apple_trees; np_apple_trees = nparams_v6_def_apple_trees;
} }
~MapgenV6Params() {}
bool readParams(Settings *settings); bool readParams(Settings *settings);
void writeParams(Settings *settings); void writeParams(Settings *settings);
}; };

@ -85,12 +85,12 @@ MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge)
this->ridge_heightmap = new s16[csize.X * csize.Z]; this->ridge_heightmap = new s16[csize.X * csize.Z];
// Terrain noise // Terrain noise
noise_terrain_base = new Noise(params->np_terrain_base, seed, csize.X, csize.Z); noise_terrain_base = new Noise(&params->np_terrain_base, seed, csize.X, csize.Z);
noise_terrain_alt = new Noise(params->np_terrain_alt, seed, csize.X, csize.Z); noise_terrain_alt = new Noise(&params->np_terrain_alt, seed, csize.X, csize.Z);
noise_terrain_mod = new Noise(params->np_terrain_mod, seed, csize.X, csize.Z); noise_terrain_mod = new Noise(&params->np_terrain_mod, seed, csize.X, csize.Z);
noise_terrain_persist = new Noise(params->np_terrain_persist, seed, csize.X, csize.Z); noise_terrain_persist = new Noise(&params->np_terrain_persist, seed, csize.X, csize.Z);
noise_height_select = new Noise(params->np_height_select, seed, csize.X, csize.Z); noise_height_select = new Noise(&params->np_height_select, seed, csize.X, csize.Z);
noise_ridge = new Noise(params->np_ridge, seed, csize.X, csize.Y, csize.Z); noise_ridge = new Noise(&params->np_ridge, seed, csize.X, csize.Y, csize.Z);
// Biome noise // Biome noise
noise_heat = new Noise(bmgr->np_heat, seed, csize.X, csize.Z); noise_heat = new Noise(bmgr->np_heat, seed, csize.X, csize.Z);
@ -152,8 +152,6 @@ void MapgenV7::makeChunk(BlockMakeData *data) {
v3s16 blockpos_min = data->blockpos_min; v3s16 blockpos_min = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max; v3s16 blockpos_max = data->blockpos_max;
v3s16 blockpos_full_min = blockpos_min - v3s16(1, 1, 1);
v3s16 blockpos_full_max = blockpos_max + v3s16(1, 1, 1);
node_min = blockpos_min * MAP_BLOCKSIZE; node_min = blockpos_min * MAP_BLOCKSIZE;
node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1); node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE; full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;

@ -30,22 +30,24 @@ extern NoiseParams nparams_v7_def_height_select;
extern NoiseParams nparams_v7_def_ridge; extern NoiseParams nparams_v7_def_ridge;
struct MapgenV7Params : public MapgenParams { struct MapgenV7Params : public MapgenParams {
NoiseParams *np_terrain_base; NoiseParams np_terrain_base;
NoiseParams *np_terrain_alt; NoiseParams np_terrain_alt;
NoiseParams *np_terrain_mod; NoiseParams np_terrain_mod;
NoiseParams *np_terrain_persist; NoiseParams np_terrain_persist;
NoiseParams *np_height_select; NoiseParams np_height_select;
NoiseParams *np_ridge; NoiseParams np_ridge;
MapgenV7Params() { MapgenV7Params() {
np_terrain_base = &nparams_v7_def_terrain_base; np_terrain_base = nparams_v7_def_terrain_base;
np_terrain_alt = &nparams_v7_def_terrain_alt; np_terrain_alt = nparams_v7_def_terrain_alt;
np_terrain_mod = &nparams_v7_def_terrain_mod; np_terrain_mod = nparams_v7_def_terrain_mod;
np_terrain_persist = &nparams_v7_def_terrain_persist; np_terrain_persist = nparams_v7_def_terrain_persist;
np_height_select = &nparams_v7_def_height_select; np_height_select = nparams_v7_def_height_select;
np_ridge = &nparams_v7_def_ridge; np_ridge = nparams_v7_def_ridge;
} }
~MapgenV7Params() {}
bool readParams(Settings *settings); bool readParams(Settings *settings);
void writeParams(Settings *settings); void writeParams(Settings *settings);
}; };

@ -220,7 +220,7 @@ ModConfiguration::ModConfiguration(std::string worldpath)
Settings worldmt_settings; Settings worldmt_settings;
worldmt_settings.readConfigFile(worldmt.c_str()); worldmt_settings.readConfigFile(worldmt.c_str());
std::vector<std::string> names = worldmt_settings.getNames(); std::vector<std::string> names = worldmt_settings.getNames();
std::set<std::string> exclude_mod_names; std::set<std::string> include_mod_names;
for(std::vector<std::string>::iterator it = names.begin(); for(std::vector<std::string>::iterator it = names.begin();
it != names.end(); ++it) it != names.end(); ++it)
{ {
@ -229,14 +229,13 @@ ModConfiguration::ModConfiguration(std::string worldpath)
// explicitely excluded. if mod is not mentioned at all, it is // explicitely excluded. if mod is not mentioned at all, it is
// enabled. So by default, all installed mods are enabled. // enabled. So by default, all installed mods are enabled.
if (name.compare(0,9,"load_mod_") == 0 && if (name.compare(0,9,"load_mod_") == 0 &&
!worldmt_settings.getBool(name)) worldmt_settings.getBool(name))
{ {
exclude_mod_names.insert(name.substr(9)); include_mod_names.insert(name.substr(9));
} }
} }
// Collect all mods in gamespec.addon_mods_paths, // Collect all mods that are also in include_mod_names
// excluding those in the set exclude_mod_names
std::vector<ModSpec> addon_mods; std::vector<ModSpec> addon_mods;
for(std::set<std::string>::const_iterator it_path = gamespec.addon_mods_paths.begin(); for(std::set<std::string>::const_iterator it_path = gamespec.addon_mods_paths.begin();
it_path != gamespec.addon_mods_paths.end(); ++it_path) it_path != gamespec.addon_mods_paths.end(); ++it_path)
@ -246,10 +245,13 @@ ModConfiguration::ModConfiguration(std::string worldpath)
it != addon_mods_in_path.end(); ++it) it != addon_mods_in_path.end(); ++it)
{ {
ModSpec& mod = *it; ModSpec& mod = *it;
if(exclude_mod_names.count(mod.name) == 0) if(include_mod_names.count(mod.name) != 0)
addon_mods.push_back(mod); addon_mods.push_back(mod);
else
worldmt_settings.setBool("load_mod_" + mod.name, false);
} }
} }
worldmt_settings.updateConfigFile(worldmt.c_str());
addMods(addon_mods); addMods(addon_mods);
@ -307,7 +309,7 @@ void ModConfiguration::addMods(std::vector<ModSpec> new_mods)
// BAD CASE: name conflict in different levels. // BAD CASE: name conflict in different levels.
u32 oldindex = existing_mods[mod.name]; u32 oldindex = existing_mods[mod.name];
const ModSpec &oldmod = m_unsatisfied_mods[oldindex]; const ModSpec &oldmod = m_unsatisfied_mods[oldindex];
errorstream<<"WARNING: Mod name conflict detected: \"" actionstream<<"WARNING: Mod name conflict detected: \""
<<mod.name<<"\""<<std::endl <<mod.name<<"\""<<std::endl
<<"Will not load: "<<oldmod.path<<std::endl <<"Will not load: "<<oldmod.path<<std::endl
<<"Overridden by: "<<mod.path<<std::endl; <<"Overridden by: "<<mod.path<<std::endl;

@ -72,8 +72,8 @@ struct NoiseParams {
// Convenience macros for getting/setting NoiseParams in Settings // Convenience macros for getting/setting NoiseParams in Settings
#define getNoiseParams(x) getStruct<NoiseParams>((x), "f,f,v3,s32,s32,f") #define getNoiseParams(x, y) getStruct((x), "f,f,v3,s32,s32,f", &(y), sizeof(y))
#define setNoiseParams(x, y) setStruct((x), "f,f,v3,s32,s32,f", (y)) #define setNoiseParams(x, y) setStruct((x), "f,f,v3,s32,s32,f", &(y))
class Noise { class Noise {
public: public:
@ -88,7 +88,7 @@ public:
Noise(NoiseParams *np, int seed, int sx, int sy); Noise(NoiseParams *np, int seed, int sx, int sy);
Noise(NoiseParams *np, int seed, int sx, int sy, int sz); Noise(NoiseParams *np, int seed, int sx, int sy, int sz);
~Noise(); virtual ~Noise();
virtual 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);

@ -81,6 +81,8 @@ Player::Player(IGameDef *gamedef):
hud_flags = HUD_FLAG_HOTBAR_VISIBLE | HUD_FLAG_HEALTHBAR_VISIBLE | hud_flags = HUD_FLAG_HOTBAR_VISIBLE | HUD_FLAG_HEALTHBAR_VISIBLE |
HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE; HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE;
hud_hotbar_itemcount = HUD_HOTBAR_ITEMCOUNT_DEFAULT;
} }
Player::~Player() Player::~Player()

@ -87,7 +87,7 @@ class Map;
class IGameDef; class IGameDef;
struct CollisionInfo; struct CollisionInfo;
class PlayerSAO; class PlayerSAO;
class HudElement; struct HudElement;
class Player class Player
{ {
@ -250,6 +250,7 @@ public:
std::vector<HudElement *> hud; std::vector<HudElement *> hud;
u32 hud_flags; u32 hud_flags;
s32 hud_hotbar_itemcount;
protected: protected:
IGameDef *m_gamedef; IGameDef *m_gamedef;

@ -1,126 +0,0 @@
/*
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 "script.h"
#include <cstdarg>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include "log.h"
#include <iostream>
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
LuaError::LuaError(lua_State *L, const std::string &s)
{
m_s = "LuaError: ";
m_s += s + "\n";
m_s += script_get_backtrace(L);
}
std::string script_get_backtrace(lua_State *L)
{
std::string s;
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if(lua_istable(L, -1)){
lua_getfield(L, -1, "traceback");
if(lua_isfunction(L, -1)){
lua_call(L, 0, 1);
if(lua_isstring(L, -1)){
s += lua_tostring(L, -1);
}
lua_pop(L, 1);
}
else{
lua_pop(L, 1);
}
}
lua_pop(L, 1);
return s;
}
void script_error(lua_State *L, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
char buf[10000];
vsnprintf(buf, 10000, fmt, argp);
va_end(argp);
//errorstream<<"SCRIPT ERROR: "<<buf;
throw LuaError(L, buf);
}
int luaErrorHandler(lua_State *L) {
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1);
lua_pushinteger(L, 2);
lua_call(L, 2, 1);
return 1;
}
bool script_load(lua_State *L, const char *path)
{
verbosestream<<"Loading and running script from "<<path<<std::endl;
lua_pushcfunction(L, luaErrorHandler);
int errorhandler = lua_gettop(L);
int ret = luaL_loadfile(L, path) || lua_pcall(L, 0, 0, errorhandler);
if(ret){
errorstream<<"========== ERROR FROM LUA ==========="<<std::endl;
errorstream<<"Failed to load and run script from "<<std::endl;
errorstream<<path<<":"<<std::endl;
errorstream<<std::endl;
errorstream<<lua_tostring(L, -1)<<std::endl;
errorstream<<std::endl;
errorstream<<"=======END OF ERROR FROM LUA ========"<<std::endl;
lua_pop(L, 1); // Pop error message from stack
lua_pop(L, 1); // Pop the error handler from stack
return false;
}
lua_pop(L, 1); // Pop the error handler from stack
return true;
}
lua_State* script_init()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
return L;
}
void script_deinit(lua_State *L)
{
lua_close(L);
}

@ -0,0 +1,9 @@
add_subdirectory(common)
add_subdirectory(cpp_api)
add_subdirectory(lua_api)
set(SCRIPT_SRCS
${SCRIPT_COMMON_SRCS}
${SCRIPT_CPP_API_SRCS}
${SCRIPT_LUA_API_SRCS}
PARENT_SCOPE)

@ -0,0 +1,6 @@
set(SCRIPT_COMMON_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/c_content.cpp
${CMAKE_CURRENT_SOURCE_DIR}/c_converter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/c_types.cpp
${CMAKE_CURRENT_SOURCE_DIR}/c_internal.cpp
PARENT_SCOPE)

@ -0,0 +1,923 @@
/*
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 "common/c_content.h"
#include "common/c_converter.h"
#include "common/c_types.h"
#include "nodedef.h"
#include "itemdef.h"
#include "object_properties.h"
#include "cpp_api/s_node.h"
#include "lua_api/l_object.h"
#include "lua_api/l_item.h"
#include "common/c_internal.h"
#include "server.h"
#include "log.h"
#include "tool.h"
#include "server.h"
struct EnumString es_TileAnimationType[] =
{
{TAT_NONE, "none"},
{TAT_VERTICAL_FRAMES, "vertical_frames"},
{0, NULL},
};
/******************************************************************************/
ItemDefinition read_item_definition(lua_State* L,int index,
ItemDefinition default_def)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
// Read the item definition
ItemDefinition def = default_def;
def.type = (ItemType)getenumfield(L, index, "type",
es_ItemType, ITEM_NONE);
getstringfield(L, index, "name", def.name);
getstringfield(L, index, "description", def.description);
getstringfield(L, index, "inventory_image", def.inventory_image);
getstringfield(L, index, "wield_image", def.wield_image);
lua_getfield(L, index, "wield_scale");
if(lua_istable(L, -1)){
def.wield_scale = check_v3f(L, -1);
}
lua_pop(L, 1);
def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
if(def.stack_max == 0)
def.stack_max = 1;
lua_getfield(L, index, "on_use");
def.usable = lua_isfunction(L, -1);
lua_pop(L, 1);
getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
warn_if_field_exists(L, index, "tool_digging_properties",
"deprecated: use tool_capabilities");
lua_getfield(L, index, "tool_capabilities");
if(lua_istable(L, -1)){
def.tool_capabilities = new ToolCapabilities(
read_tool_capabilities(L, -1));
}
// If name is "" (hand), ensure there are ToolCapabilities
// because it will be looked up there whenever any other item has
// no ToolCapabilities
if(def.name == "" && def.tool_capabilities == NULL){
def.tool_capabilities = new ToolCapabilities();
}
lua_getfield(L, index, "groups");
read_groups(L, -1, def.groups);
lua_pop(L, 1);
lua_getfield(L, index, "sounds");
if(lua_istable(L, -1)){
lua_getfield(L, -1, "place");
read_soundspec(L, -1, def.sound_place);
lua_pop(L, 1);
}
lua_pop(L, 1);
// Client shall immediately place this node when player places the item.
// Server will update the precise end result a moment later.
// "" = no prediction
getstringfield(L, index, "node_placement_prediction",
def.node_placement_prediction);
return def;
}
/******************************************************************************/
void read_object_properties(lua_State *L, int index,
ObjectProperties *prop)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
if(!lua_istable(L, index))
return;
prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
getboolfield(L, -1, "physical", prop->physical);
getfloatfield(L, -1, "weight", prop->weight);
lua_getfield(L, -1, "collisionbox");
if(lua_istable(L, -1))
prop->collisionbox = read_aabb3f(L, -1, 1.0);
lua_pop(L, 1);
getstringfield(L, -1, "visual", prop->visual);
getstringfield(L, -1, "mesh", prop->mesh);
lua_getfield(L, -1, "visual_size");
if(lua_istable(L, -1))
prop->visual_size = read_v2f(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "textures");
if(lua_istable(L, -1)){
prop->textures.clear();
int table = lua_gettop(L);
lua_pushnil(L);
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
if(lua_isstring(L, -1))
prop->textures.push_back(lua_tostring(L, -1));
else
prop->textures.push_back("");
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
}
lua_pop(L, 1);
lua_getfield(L, -1, "colors");
if(lua_istable(L, -1)){
prop->colors.clear();
int table = lua_gettop(L);
lua_pushnil(L);
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
if(lua_isstring(L, -1))
prop->colors.push_back(readARGB8(L, -1));
else
prop->colors.push_back(video::SColor(255, 255, 255, 255));
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
}
lua_pop(L, 1);
lua_getfield(L, -1, "spritediv");
if(lua_istable(L, -1))
prop->spritediv = read_v2s16(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "initial_sprite_basepos");
if(lua_istable(L, -1))
prop->initial_sprite_basepos = read_v2s16(L, -1);
lua_pop(L, 1);
getboolfield(L, -1, "is_visible", prop->is_visible);
getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
}
/******************************************************************************/
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 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",
ScriptApiNode::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);
bool usealpha = getboolfield_default(L, index,
"use_texture_alpha", false);
if (usealpha)
f.alpha = 0;
/* 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",
ScriptApiNode::es_ContentParamType, CPT_NONE);
f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
ScriptApiNode::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",
ScriptApiNode::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;
}
/******************************************************************************/
void read_server_sound_params(lua_State *L, int index,
ServerSoundParams &params)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
// Clear
params = ServerSoundParams();
if(lua_istable(L, index)){
getfloatfield(L, index, "gain", params.gain);
getstringfield(L, index, "to_player", params.to_player);
lua_getfield(L, index, "pos");
if(!lua_isnil(L, -1)){
v3f p = read_v3f(L, -1)*BS;
params.pos = p;
params.type = ServerSoundParams::SSP_POSITIONAL;
}
lua_pop(L, 1);
lua_getfield(L, index, "object");
if(!lua_isnil(L, -1)){
ObjectRef *ref = ObjectRef::checkobject(L, -1);
ServerActiveObject *sao = ObjectRef::getobject(ref);
if(sao){
params.object = sao->getId();
params.type = ServerSoundParams::SSP_OBJECT;
}
}
lua_pop(L, 1);
params.max_hear_distance = BS*getfloatfield_default(L, index,
"max_hear_distance", params.max_hear_distance/BS);
getboolfield(L, index, "loop", params.loop);
}
}
/******************************************************************************/
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);
}
}
/******************************************************************************/
NodeBox read_nodebox(lua_State *L, int index)
{
NodeBox nodebox;
if(lua_istable(L, -1)){
nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
ScriptApiNode::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;
}
/******************************************************************************/
MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
{
lua_getfield(L, index, "name");
const char *name = luaL_checkstring(L, -1);
lua_pop(L, 1);
u8 param1;
lua_getfield(L, index, "param1");
if(lua_isnil(L, -1))
param1 = 0;
else
param1 = lua_tonumber(L, -1);
lua_pop(L, 1);
u8 param2;
lua_getfield(L, index, "param2");
if(lua_isnil(L, -1))
param2 = 0;
else
param2 = lua_tonumber(L, -1);
lua_pop(L, 1);
return MapNode(ndef, name, param1, param2);
}
/******************************************************************************/
void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
{
lua_newtable(L);
lua_pushstring(L, ndef->get(n).name.c_str());
lua_setfield(L, -2, "name");
lua_pushnumber(L, n.getParam1());
lua_setfield(L, -2, "param1");
lua_pushnumber(L, n.getParam2());
lua_setfield(L, -2, "param2");
}
/******************************************************************************/
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)){
//TODO find way to access backtrace fct from here
// infostream<<script_get_backtrace(L)<<std::endl;
infostream<<"WARNING: field \""<<fieldname<<"\": "
<<message<<std::endl;
}
lua_pop(L, 1);
}
/******************************************************************************/
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;
}
/******************************************************************************/
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;
}
/******************************************************************************/
ItemStack read_item(lua_State* L, int index,Server* srv)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
if(lua_isnil(L, index))
{
return ItemStack();
}
else if(lua_isuserdata(L, index))
{
// Convert from LuaItemStack
LuaItemStack *o = LuaItemStack::checkobject(L, index);
return o->getItem();
}
else if(lua_isstring(L, index))
{
// Convert from itemstring
std::string itemstring = lua_tostring(L, index);
IItemDefManager *idef = srv->idef();
try
{
ItemStack item;
item.deSerialize(itemstring, idef);
return item;
}
catch(SerializationError &e)
{
infostream<<"WARNING: unable to create item from itemstring"
<<": "<<itemstring<<std::endl;
return ItemStack();
}
}
else if(lua_istable(L, index))
{
// Convert from table
IItemDefManager *idef = srv->idef();
std::string name = getstringfield_default(L, index, "name", "");
int count = getintfield_default(L, index, "count", 1);
int wear = getintfield_default(L, index, "wear", 0);
std::string metadata = getstringfield_default(L, index, "metadata", "");
return ItemStack(name, count, wear, metadata, idef);
}
else
{
throw LuaError(L, "Expecting itemstack, itemstring, table or nil");
}
}
/******************************************************************************/
void push_tool_capabilities(lua_State *L,
const ToolCapabilities &toolcap)
{
lua_newtable(L);
setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
setintfield(L, -1, "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_inventory_list(Inventory *inv, const char *name,
lua_State *L)
{
InventoryList *invlist = inv->getList(name);
if(invlist == NULL){
lua_pushnil(L);
return;
}
std::vector<ItemStack> items;
for(u32 i=0; i<invlist->getSize(); i++)
items.push_back(invlist->getItem(i));
push_items(L, items);
}
/******************************************************************************/
void read_inventory_list(Inventory *inv, const char *name,
lua_State *L, int tableindex, Server* srv,int forcesize)
{
if(tableindex < 0)
tableindex = lua_gettop(L) + 1 + tableindex;
// If nil, delete list
if(lua_isnil(L, tableindex)){
inv->deleteList(name);
return;
}
// Otherwise set list
std::vector<ItemStack> items = read_items(L, tableindex,srv);
int listsize = (forcesize != -1) ? forcesize : items.size();
InventoryList *invlist = inv->addList(name, listsize);
int index = 0;
for(std::vector<ItemStack>::const_iterator
i = items.begin(); i != items.end(); i++){
if(forcesize != -1 && index == forcesize)
break;
invlist->changeItem(index, *i);
index++;
}
while(forcesize != -1 && index < forcesize){
invlist->deleteItem(index);
index++;
}
}
/******************************************************************************/
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 push_dig_params(lua_State *L,const DigParams &params)
{
lua_newtable(L);
setboolfield(L, -1, "diggable", params.diggable);
setfloatfield(L, -1, "time", params.time);
setintfield(L, -1, "wear", params.wear);
}
/******************************************************************************/
void push_hit_params(lua_State *L,const HitParams &params)
{
lua_newtable(L);
setintfield(L, -1, "hp", params.hp);
setintfield(L, -1, "wear", params.wear);
}
/******************************************************************************/
u32 getflagsfield(lua_State *L, int table,
const char *fieldname, FlagDesc *flagdesc) {
std::string flagstring;
flagstring = getstringfield_default(L, table, fieldname, "");
return readFlagString(flagstring, flagdesc);
}
/******************************************************************************/
/* Lua Stored data! */
/******************************************************************************/
/******************************************************************************/
void read_groups(lua_State *L, int index,
std::map<std::string, int> &result)
{
if (!lua_istable(L,index))
return;
result.clear();
lua_pushnil(L);
if(index < 0)
index -= 1;
while(lua_next(L, index) != 0){
// key at index -2 and value at index -1
std::string name = luaL_checkstring(L, -2);
int rating = luaL_checkinteger(L, -1);
result[name] = rating;
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
}
/******************************************************************************/
void push_items(lua_State *L, const std::vector<ItemStack> &items)
{
// Get the table insert function
lua_getglobal(L, "table");
lua_getfield(L, -1, "insert");
int table_insert = lua_gettop(L);
// Create and fill table
lua_newtable(L);
int table = lua_gettop(L);
for(u32 i=0; i<items.size(); i++){
ItemStack item = items[i];
lua_pushvalue(L, table_insert);
lua_pushvalue(L, table);
LuaItemStack::create(L, item);
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
lua_remove(L, -2); // Remove table
lua_remove(L, -2); // Remove insert
}
/******************************************************************************/
std::vector<ItemStack> read_items(lua_State *L, int index,Server* srv)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
std::vector<ItemStack> items;
luaL_checktype(L, index, LUA_TTABLE);
lua_pushnil(L);
while(lua_next(L, index) != 0){
// key at index -2 and value at index -1
items.push_back(read_item(L, -1, srv));
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
return items;
}
/******************************************************************************/
void luaentity_get(lua_State *L, u16 id)
{
// Get minetest.luaentities[i]
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "luaentities");
luaL_checktype(L, -1, LUA_TTABLE);
lua_pushnumber(L, id);
lua_gettable(L, -2);
lua_remove(L, -2); // luaentities
lua_remove(L, -2); // minetest
}
/******************************************************************************/
NoiseParams *read_noiseparams(lua_State *L, int index)
{
if (index < 0)
index = lua_gettop(L) + 1 + index;
if (!lua_istable(L, index))
return NULL;
NoiseParams *np = new NoiseParams;
np->offset = getfloatfield_default(L, index, "offset", 0.0);
np->scale = getfloatfield_default(L, index, "scale", 0.0);
lua_getfield(L, index, "spread");
np->spread = read_v3f(L, -1);
lua_pop(L, 1);
np->seed = getintfield_default(L, index, "seed", 0);
np->octaves = getintfield_default(L, index, "octaves", 0);
np->persist = getfloatfield_default(L, index, "persist", 0.0);
return np;
}

@ -0,0 +1,146 @@
/*
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.
*/
/******************************************************************************/
/******************************************************************************/
/* WARNING!!!! do NOT add this header in any include file or any code file */
/* not being a script/modapi file!!!!!!!! */
/******************************************************************************/
/******************************************************************************/
#ifndef C_CONTENT_H_
#define C_CONTENT_H_
extern "C" {
#include <lua.h>
}
#include <iostream>
#include <map>
#include <vector>
#include "irrlichttypes_bloated.h"
#include "util/string.h"
class MapNode;
class INodeDefManager;
class PointedThing;
class ItemStack;
class ItemDefinition;
class ToolCapabilities;
class ObjectProperties;
class SimpleSoundSpec;
class ServerSoundParams;
class Inventory;
class NodeBox;
class ContentFeatures;
class TileDef;
class Server;
struct DigParams;
struct HitParams;
struct EnumString;
struct NoiseParams;
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);
void read_server_sound_params (lua_State *L, int index,
ServerSoundParams &params);
void push_dig_params (lua_State *L,const DigParams &params);
void push_hit_params (lua_State *L,const HitParams &params);
ItemStack read_item (lua_State *L, int index, Server* srv);
ToolCapabilities read_tool_capabilities (lua_State *L,
int table);
void push_tool_capabilities (lua_State *L,
const ToolCapabilities &prop);
ItemDefinition read_item_definition (lua_State *L,
int index,
ItemDefinition default_def);
void read_object_properties (lua_State *L,
int index,
ObjectProperties *prop);
//TODO fix parameter oreder!
void push_inventory_list (Inventory *inv,
const char *name,
lua_State *L);
void read_inventory_list (Inventory *inv,
const char *name,
lua_State *L,
int tableindex,
Server* srv,
int forcesize=-1);
MapNode readnode (lua_State *L,
int index,
INodeDefManager *ndef);
void pushnode (lua_State *L,
const MapNode &n,
INodeDefManager *ndef);
NodeBox read_nodebox (lua_State *L, int index);
void read_groups (lua_State *L,
int index,
std::map<std::string, int> &result);
//TODO rename to "read_enum_field"
int getenumfield (lua_State *L,
int table,
const char *fieldname,
const EnumString *spec,
int default_);
u32 getflagsfield (lua_State *L, int table,
const char *fieldname,
FlagDesc *flagdesc);
void push_items (lua_State *L,
const std::vector<ItemStack> &items);
std::vector<ItemStack> read_items (lua_State *L,
int index,
Server* srv);
void read_soundspec (lua_State *L,
int index,
SimpleSoundSpec &spec);
bool string_to_enum (const EnumString *spec,
int &result,
const std::string &str);
NoiseParams* read_noiseparams (lua_State *L, int index);
void luaentity_get (lua_State *L,u16 id);
extern struct EnumString es_TileAnimationType[];
#endif /* C_CONTENT_H_ */

@ -17,19 +17,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "scriptapi.h"
#include "scriptapi_types.h"
extern "C" { extern "C" {
#include <lauxlib.h> #include "lua.h"
#include "lauxlib.h"
} }
#include "util/numeric.h" #include "util/numeric.h"
#include "nodedef.h" #include "common/c_converter.h"
#include "constants.h"
/*
C struct <-> Lua table converter functions
*/
void push_v3f(lua_State *L, v3f p) void push_v3f(lua_State *L, v3f p)
{ {
@ -147,7 +142,7 @@ v3s16 check_v3s16(lua_State *L, int index)
video::SColor readARGB8(lua_State *L, int index) video::SColor readARGB8(lua_State *L, int index)
{ {
video::SColor color; video::SColor color(0);
luaL_checktype(L, index, LUA_TTABLE); luaL_checktype(L, index, LUA_TTABLE);
lua_getfield(L, index, "a"); lua_getfield(L, index, "a");
if(lua_isnumber(L, -1)) if(lua_isnumber(L, -1))
@ -345,44 +340,4 @@ void setboolfield(lua_State *L, int table,
lua_setfield(L, table, fieldname); lua_setfield(L, table, fieldname);
} }
u32 getflagsfield(lua_State *L, int table,
const char *fieldname, FlagDesc *flagdesc) {
std::string flagstring;
flagstring = getstringfield_default(L, table, fieldname, "");
return readFlagString(flagstring, flagdesc);
}
/* minetest specific types */
MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
{
lua_getfield(L, index, "name");
const char *name = luaL_checkstring(L, -1);
lua_pop(L, 1);
u8 param1;
lua_getfield(L, index, "param1");
if(lua_isnil(L, -1))
param1 = 0;
else
param1 = lua_tonumber(L, -1);
lua_pop(L, 1);
u8 param2;
lua_getfield(L, index, "param2");
if(lua_isnil(L, -1))
param2 = 0;
else
param2 = lua_tonumber(L, -1);
lua_pop(L, 1);
return MapNode(ndef, name, param1, param2);
}
void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
{
lua_newtable(L);
lua_pushstring(L, ndef->get(n).name.c_str());
lua_setfield(L, -2, "name");
lua_pushnumber(L, n.getParam1());
lua_setfield(L, -2, "param1");
lua_pushnumber(L, n.getParam2());
lua_setfield(L, -2, "param2");
}

@ -1,5 +1,5 @@
/* /*
Minetest-c55 Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -17,16 +17,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef LUA_TYPES_H_
#define LUA_TYPES_H_
#include <iostream> /******************************************************************************/
#include <map> /******************************************************************************/
/* WARNING!!!! do NOT add this header in any include file or any code file */
/* not being a script/modapi file!!!!!!!! */
/******************************************************************************/
/******************************************************************************/
#ifndef C_CONVERTER_H_
#define C_CONVERTER_H_
#include <vector> #include <vector>
#include <map>
#include "irrlichttypes_bloated.h" #include "irrlichttypes_bloated.h"
#include "porting.h" #include "common/c_types.h"
#include "map.h"
extern "C" { extern "C" {
#include <lua.h> #include <lua.h>
@ -51,8 +56,6 @@ bool getboolfield(lua_State *L, int table,
const char *fieldname, bool &result); const char *fieldname, bool &result);
bool getfloatfield(lua_State *L, int table, bool getfloatfield(lua_State *L, int table,
const char *fieldname, float &result); const char *fieldname, float &result);
u32 getflagsfield(lua_State *L, int table,
const char *fieldname, FlagDesc *flagdesc);
std::string checkstringfield(lua_State *L, int table, std::string checkstringfield(lua_State *L, int table,
const char *fieldname); const char *fieldname);
@ -65,26 +68,29 @@ void setboolfield(lua_State *L, int table,
const char *fieldname, bool value); const char *fieldname, bool value);
v3f checkFloatPos (lua_State *L, int index); v3f checkFloatPos (lua_State *L, int index);
v3f check_v3f (lua_State *L, int index); v3f check_v3f (lua_State *L, int index);
v3s16 check_v3s16 (lua_State *L, int index); v3s16 check_v3s16 (lua_State *L, int index);
v3f read_v3f (lua_State *L, int index); v3f read_v3f (lua_State *L, int index);
v2f read_v2f (lua_State *L, int index); v2f read_v2f (lua_State *L, int index);
v2s16 read_v2s16 (lua_State *L, int index); v2s16 read_v2s16 (lua_State *L, int index);
video::SColor readARGB8 (lua_State *L, int index); video::SColor readARGB8 (lua_State *L, int index);
aabb3f read_aabb3f (lua_State *L, int index, f32 scale); aabb3f read_aabb3f (lua_State *L, int index, f32 scale);
v3s16 read_v3s16 (lua_State *L, int index); v3s16 read_v3s16 (lua_State *L, int index);
std::vector<aabb3f> std::vector<aabb3f>
read_aabb3f_vector (lua_State *L, int index, f32 scale); read_aabb3f_vector (lua_State *L, int index, f32 scale);
void push_v3s16 (lua_State *L, v3s16 p); void push_v3s16 (lua_State *L, v3s16 p);
void pushFloatPos (lua_State *L, v3f p); void pushFloatPos (lua_State *L, v3f p);
void push_v3f (lua_State *L, v3f p); void push_v3f (lua_State *L, v3f p);
void push_v2f (lua_State *L, v2f p); void push_v2f (lua_State *L, v2f p);
MapNode readnode(lua_State *L, int index, INodeDefManager *ndef);
void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef);
#endif /* LUA_TYPES_H_ */ void warn_if_field_exists (lua_State *L,
int table,
const char *fieldname,
const std::string &message);
#endif /* C_CONVERTER_H_ */

@ -0,0 +1,65 @@
/*
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 "common/c_internal.h"
#include "server.h"
#include "cpp_api/scriptapi.h"
ScriptApi* get_scriptapi(lua_State *L)
{
// Get server from registry
lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi");
ScriptApi* sapi_ptr = (ScriptApi*) lua_touserdata(L, -1);
lua_pop(L, 1);
return sapi_ptr;
}
std::string script_get_backtrace(lua_State *L)
{
std::string s;
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if(lua_istable(L, -1)){
lua_getfield(L, -1, "traceback");
if(lua_isfunction(L, -1)){
lua_call(L, 0, 1);
if(lua_isstring(L, -1)){
s += lua_tostring(L, -1);
}
lua_pop(L, 1);
}
else{
lua_pop(L, 1);
}
}
lua_pop(L, 1);
return s;
}
void script_error(lua_State* L,const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
char buf[10000];
vsnprintf(buf, 10000, fmt, argp);
va_end(argp);
//errorstream<<"SCRIPT ERROR: "<<buf;
throw LuaError(L, buf);
}

@ -0,0 +1,60 @@
/*
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.
*/
/******************************************************************************/
/******************************************************************************/
/* WARNING!!!! do NOT add this header in any include file or any code file */
/* not being a modapi file!!!!!!!! */
/******************************************************************************/
/******************************************************************************/
#ifndef C_INTERNAL_H_
#define C_INTERNAL_H_
class Server;
class ScriptApi;
#include <iostream>
#include "lua_api/l_base.h"
extern "C" {
#include "lua.h"
}
#define luamethod(class, name) {#name, class::l_##name}
#define STACK_TO_SERVER(L) get_scriptapi(L)->getServer()
#define API_FCT(name) registerFunction(L,#name,l_##name,top)
#define REGISTER_LUA_REF(cln) \
class ModApi_##cln : public ModApiBase { \
public: \
ModApi_##cln() : ModApiBase() {}; \
bool Initialize(lua_State* L, int top) { \
cln::Register(L); \
return true; \
}; \
}; \
ModApi_##cln macro_generated_prototype__##cln;
ScriptApi* get_scriptapi (lua_State *L);
std::string script_get_backtrace (lua_State *L);
void script_error (lua_State *L, const char *fmt, ...);
#endif /* C_INTERNAL_H_ */

@ -1,5 +1,5 @@
/* /*
Minetest-c55 Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -17,21 +17,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef LUA_CONTENT_H_ #include <iostream>
#define LUA_CONTENT_H_
extern "C" { #include "common/c_types.h"
#include <lua.h> #include "common/c_internal.h"
#include "itemdef.h"
LuaError::LuaError(lua_State *L, const std::string &s)
{
m_s = "LuaError: ";
m_s += s + "\n";
m_s += script_get_backtrace(L);
} }
#include "nodedef.h" struct EnumString es_ItemType[] =
{
ContentFeatures read_content_features (lua_State *L, int index); {ITEM_NONE, "none"},
TileDef read_tiledef (lua_State *L, int index); {ITEM_NODE, "node"},
void read_soundspec (lua_State *L, int index, {ITEM_CRAFT, "craft"},
SimpleSoundSpec &spec); {ITEM_TOOL, "tool"},
NodeBox read_nodebox (lua_State *L, int index); {0, NULL},
};
extern struct EnumString es_TileAnimationType[];
#endif /* LUA_CONTENT_H_ */

@ -0,0 +1,90 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef C_TYPES_H_
#define C_TYPES_H_
extern "C" {
#include "lua.h"
}
#include <iostream>
struct EnumString
{
int num;
const char *str;
};
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
}
};
class ModNameStorer
{
private:
lua_State *L;
public:
ModNameStorer(lua_State *L_, const std::string modname):
L(L_)
{
// Store current modname in registry
lua_pushstring(L, modname.c_str());
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
}
~ModNameStorer()
{
// Clear current modname in registry
lua_pushnil(L);
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
}
};
class LuaError : public std::exception
{
public:
LuaError(lua_State *L, const std::string &s);
virtual ~LuaError() throw()
{}
virtual const char * what() const throw()
{
return m_s.c_str();
}
std::string m_s;
};
extern EnumString es_ItemType[];
#endif /* C_TYPES_H_ */

@ -0,0 +1,11 @@
set(SCRIPT_CPP_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/s_base.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_entity.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_env.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_inventory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_item.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_node.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_nodemeta.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_player.cpp
${CMAKE_CURRENT_SOURCE_DIR}/scriptapi.cpp
PARENT_SCOPE)

@ -0,0 +1,264 @@
/*
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 <stdio.h>
#include <cstdarg>
extern "C" {
#include "lua.h"
#include "lauxlib.h"
}
#include "cpp_api/s_base.h"
#include "lua_api/l_object.h"
#include "serverobject.h"
ScriptApiBase::ScriptApiBase() :
m_luastackmutex(),
#ifdef LOCK_DEBUG
m_locked(false),
#endif
m_luastack(0),
m_server(0),
m_environment(0)
{
}
void ScriptApiBase::realityCheck()
{
int top = lua_gettop(m_luastack);
if(top >= 30){
dstream<<"Stack is over 30:"<<std::endl;
stackDump(dstream);
scriptError("Stack is over 30 (reality check)");
}
}
void ScriptApiBase::scriptError(const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
char buf[10000];
vsnprintf(buf, 10000, fmt, argp);
va_end(argp);
//errorstream<<"SCRIPT ERROR: "<<buf;
throw LuaError(m_luastack, buf);
}
void ScriptApiBase::stackDump(std::ostream &o)
{
int i;
int top = lua_gettop(m_luastack);
for (i = 1; i <= top; i++) { /* repeat for each level */
int t = lua_type(m_luastack, i);
switch (t) {
case LUA_TSTRING: /* strings */
o<<"\""<<lua_tostring(m_luastack, i)<<"\"";
break;
case LUA_TBOOLEAN: /* booleans */
o<<(lua_toboolean(m_luastack, i) ? "true" : "false");
break;
case LUA_TNUMBER: /* numbers */ {
char buf[10];
snprintf(buf, 10, "%g", lua_tonumber(m_luastack, i));
o<<buf;
break; }
default: /* other values */
o<<lua_typename(m_luastack, t);
break;
}
o<<" ";
}
o<<std::endl;
}
// Push the list of callbacks (a lua table).
// Then push nargs arguments.
// Then call this function, which
// - runs the callbacks
// - removes the table and arguments from the lua stack
// - pushes the return value, computed depending on mode
void ScriptApiBase::runCallbacks(int nargs,RunCallbacksMode mode)
{
lua_State *L = getStack();
// Insert the return value into the lua stack, below the table
assert(lua_gettop(L) >= nargs + 1);
lua_pushnil(L);
lua_insert(L, -(nargs + 1) - 1);
// Stack now looks like this:
// ... <return value = nil> <table> <arg#1> <arg#2> ... <arg#n>
int rv = lua_gettop(L) - nargs - 1;
int table = rv + 1;
int arg = table + 1;
luaL_checktype(L, table, LUA_TTABLE);
// Foreach
lua_pushnil(L);
bool first_loop = true;
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TFUNCTION);
// Call function
for(int i = 0; i < nargs; i++)
lua_pushvalue(L, arg+i);
if(lua_pcall(L, nargs, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
// Move return value to designated space in stack
// Or pop it
if(first_loop){
// Result of first callback is always moved
lua_replace(L, rv);
first_loop = false;
} else {
// Otherwise, what happens depends on the mode
if(mode == RUN_CALLBACKS_MODE_FIRST)
lua_pop(L, 1);
else if(mode == RUN_CALLBACKS_MODE_LAST)
lua_replace(L, rv);
else if(mode == RUN_CALLBACKS_MODE_AND ||
mode == RUN_CALLBACKS_MODE_AND_SC){
if((bool)lua_toboolean(L, rv) == true &&
(bool)lua_toboolean(L, -1) == false)
lua_replace(L, rv);
else
lua_pop(L, 1);
}
else if(mode == RUN_CALLBACKS_MODE_OR ||
mode == RUN_CALLBACKS_MODE_OR_SC){
if((bool)lua_toboolean(L, rv) == false &&
(bool)lua_toboolean(L, -1) == true)
lua_replace(L, rv);
else
lua_pop(L, 1);
}
else
assert(0);
}
// Handle short circuit modes
if(mode == RUN_CALLBACKS_MODE_AND_SC &&
(bool)lua_toboolean(L, rv) == false)
break;
else if(mode == RUN_CALLBACKS_MODE_OR_SC &&
(bool)lua_toboolean(L, rv) == true)
break;
// value removed, keep key for next iteration
}
// Remove stuff from stack, leaving only the return value
lua_settop(L, rv);
// Fix return value in case no callbacks were called
if(first_loop){
if(mode == RUN_CALLBACKS_MODE_AND ||
mode == RUN_CALLBACKS_MODE_AND_SC){
lua_pop(L, 1);
lua_pushboolean(L, true);
}
else if(mode == RUN_CALLBACKS_MODE_OR ||
mode == RUN_CALLBACKS_MODE_OR_SC){
lua_pop(L, 1);
lua_pushboolean(L, false);
}
}
}
void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
{
SCRIPTAPI_PRECHECKHEADER
//infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
// Create object on stack
ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
int object = lua_gettop(L);
// Get minetest.object_refs table
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "object_refs");
luaL_checktype(L, -1, LUA_TTABLE);
int objectstable = lua_gettop(L);
// object_refs[id] = object
lua_pushnumber(L, cobj->getId()); // Push id
lua_pushvalue(L, object); // Copy object to top of stack
lua_settable(L, objectstable);
}
void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
{
SCRIPTAPI_PRECHECKHEADER
//infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
// Get minetest.object_refs table
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "object_refs");
luaL_checktype(L, -1, LUA_TTABLE);
int objectstable = lua_gettop(L);
// Get object_refs[id]
lua_pushnumber(L, cobj->getId()); // Push id
lua_gettable(L, objectstable);
// Set object reference to NULL
ObjectRef::set_null(L);
lua_pop(L, 1); // pop object
// Set object_refs[id] = nil
lua_pushnumber(L, cobj->getId()); // Push id
lua_pushnil(L);
lua_settable(L, objectstable);
}
// Creates a new anonymous reference if cobj=NULL or id=0
void ScriptApiBase::objectrefGetOrCreate(
ServerActiveObject *cobj)
{
lua_State *L = getStack();
if(cobj == NULL || cobj->getId() == 0){
ObjectRef::create(L, cobj);
} else {
objectrefGet(cobj->getId());
}
}
void ScriptApiBase::objectrefGet(u16 id)
{
lua_State *L = getStack();
// Get minetest.object_refs[i]
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "object_refs");
luaL_checktype(L, -1, LUA_TTABLE);
lua_pushnumber(L, id);
lua_gettable(L, -2);
lua_remove(L, -2); // object_refs
lua_remove(L, -2); // minetest
}

167
src/script/cpp_api/s_base.h Normal file

@ -0,0 +1,167 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef S_BASE_H_
#define S_BASE_H_
#include <iostream>
#include "irrlichttypes.h"
#include "jmutex.h"
#include "jmutexautolock.h"
#include "common/c_types.h"
#include "debug.h"
#define LOCK_DEBUG
class Server;
class Environment;
class ServerActiveObject;
class LuaABM;
class InvRef;
class ModApiBase;
class ModApiEnvMod;
class ObjectRef;
class NodeMetaRef;
/* 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.
};
class ScriptApiBase {
public:
/* object */
void addObjectReference(ServerActiveObject *cobj);
void removeObjectReference(ServerActiveObject *cobj);
ScriptApiBase();
protected:
friend class LuaABM;
friend class InvRef;
friend class ObjectRef;
friend class NodeMetaRef;
friend class ModApiBase;
friend class ModApiEnvMod;
inline lua_State* getStack()
{ return m_luastack; }
bool setStack(lua_State* stack) {
if (m_luastack == 0) {
m_luastack = stack;
return true;
}
return false;
}
void realityCheck();
void scriptError(const char *fmt, ...);
void stackDump(std::ostream &o);
void runCallbacks(int nargs,RunCallbacksMode mode);
inline Server* getServer() { return m_server; }
void setServer(Server* server) { m_server = server; }
Environment* getEnv() { return m_environment; }
void setEnv(Environment* env) { m_environment = env; }
void objectrefGetOrCreate(ServerActiveObject *cobj);
void objectrefGet(u16 id);
JMutex m_luastackmutex;
#ifdef LOCK_DEBUG
bool m_locked;
#endif
private:
lua_State* m_luastack;
Server* m_server;
Environment* m_environment;
};
#ifdef LOCK_DEBUG
class LockChecker {
public:
LockChecker(bool* variable) {
assert(*variable == false);
m_variable = variable;
*m_variable = true;
}
~LockChecker() {
*m_variable = false;
}
private:
bool* m_variable;
};
#define LOCK_CHECK LockChecker(&(this->m_locked))
#else
#define LOCK_CHECK while(0)
#endif
#define LUA_STACK_AUTOLOCK JMutexAutoLock(this->m_luastackmutex)
#define SCRIPTAPI_PRECHECKHEADER \
LUA_STACK_AUTOLOCK; \
LOCK_CHECK; \
realityCheck(); \
lua_State *L = getStack(); \
assert(lua_checkstack(L, 20)); \
StackUnroller stack_unroller(L);
#define PLAYER_TO_SA(p) p->getEnv()->getScriptIface()
#define ENV_TO_SA(env) env->getScriptIface()
#define SERVER_TO_SA(srv) srv->getScriptIface()
#endif /* S_BASE_H_ */

@ -17,43 +17,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "scriptapi.h" #include "cpp_api/s_entity.h"
#include "scriptapi_entity.h" #include "log.h"
#include "object_properties.h"
#include "common/c_converter.h"
#include "common/c_content.h"
extern "C" { extern "C" {
#include <lauxlib.h> #include "lauxlib.h"
} }
#include "log.h" bool ScriptApiEntity::luaentity_Add(u16 id, const char *name)
#include "script.h"
#include "scriptapi_types.h"
#include "scriptapi_object.h"
#include "scriptapi_common.h"
void luaentity_get(lua_State *L, u16 id)
{ {
// Get minetest.luaentities[i] SCRIPTAPI_PRECHECKHEADER
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "luaentities");
luaL_checktype(L, -1, LUA_TTABLE);
lua_pushnumber(L, id);
lua_gettable(L, -2);
lua_remove(L, -2); // luaentities
lua_remove(L, -2); // minetest
}
/*
luaentity
*/
bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
verbosestream<<"scriptapi_luaentity_add: id="<<id<<" name=\"" verbosestream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
<<name<<"\""<<std::endl; <<name<<"\""<<std::endl;
StackUnroller stack_unroller(L);
// Get minetest.registered_entities[name] // Get minetest.registered_entities[name]
lua_getglobal(L, "minetest"); lua_getglobal(L, "minetest");
@ -80,7 +59,7 @@ bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name)
// Add object reference // Add object reference
// This should be userdata with metatable ObjectRef // This should be userdata with metatable ObjectRef
objectref_get(L, id); objectrefGet(id);
luaL_checktype(L, -1, LUA_TUSERDATA); luaL_checktype(L, -1, LUA_TUSERDATA);
if(!luaL_checkudata(L, -1, "ObjectRef")) if(!luaL_checkudata(L, -1, "ObjectRef"))
luaL_typerror(L, -1, "ObjectRef"); luaL_typerror(L, -1, "ObjectRef");
@ -97,16 +76,15 @@ bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name)
return true; return true;
} }
void scriptapi_luaentity_activate(lua_State *L, u16 id, void ScriptApiEntity::luaentity_Activate(u16 id,
const std::string &staticdata, u32 dtime_s) const std::string &staticdata, u32 dtime_s)
{ {
realitycheck(L); SCRIPTAPI_PRECHECKHEADER
assert(lua_checkstack(L, 20));
verbosestream<<"scriptapi_luaentity_activate: id="<<id<<std::endl; verbosestream<<"scriptapi_luaentity_activate: id="<<id<<std::endl;
StackUnroller stack_unroller(L);
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
luaentity_get(L, id); luaentity_get(L,id);
int object = lua_gettop(L); int object = lua_gettop(L);
// Get on_activate function // Get on_activate function
@ -119,15 +97,15 @@ void scriptapi_luaentity_activate(lua_State *L, u16 id,
lua_pushinteger(L, dtime_s); lua_pushinteger(L, dtime_s);
// Call with 3 arguments, 0 results // Call with 3 arguments, 0 results
if(lua_pcall(L, 3, 0, 0)) if(lua_pcall(L, 3, 0, 0))
script_error(L, "error running function on_activate: %s\n", scriptError("error running function on_activate: %s\n",
lua_tostring(L, -1)); lua_tostring(L, -1));
} }
} }
void scriptapi_luaentity_rm(lua_State *L, u16 id) void ScriptApiEntity::luaentity_Remove(u16 id)
{ {
realitycheck(L); SCRIPTAPI_PRECHECKHEADER
assert(lua_checkstack(L, 20));
verbosestream<<"scriptapi_luaentity_rm: id="<<id<<std::endl; verbosestream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
// Get minetest.luaentities table // Get minetest.luaentities table
@ -144,15 +122,14 @@ void scriptapi_luaentity_rm(lua_State *L, u16 id)
lua_pop(L, 2); // pop luaentities, minetest lua_pop(L, 2); // pop luaentities, minetest
} }
std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id) std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
{ {
realitycheck(L); SCRIPTAPI_PRECHECKHEADER
assert(lua_checkstack(L, 20));
//infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl; //infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl;
StackUnroller stack_unroller(L);
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
luaentity_get(L, id); luaentity_get(L,id);
int object = lua_gettop(L); int object = lua_gettop(L);
// Get get_staticdata function // Get get_staticdata function
@ -165,7 +142,7 @@ std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id)
lua_pushvalue(L, object); // self lua_pushvalue(L, object); // self
// Call with 1 arguments, 1 results // Call with 1 arguments, 1 results
if(lua_pcall(L, 1, 1, 0)) if(lua_pcall(L, 1, 1, 0))
script_error(L, "error running function get_staticdata: %s\n", scriptError("error running function get_staticdata: %s\n",
lua_tostring(L, -1)); lua_tostring(L, -1));
size_t len=0; size_t len=0;
@ -173,16 +150,15 @@ std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id)
return std::string(s, len); return std::string(s, len);
} }
void scriptapi_luaentity_get_properties(lua_State *L, u16 id, void ScriptApiEntity::luaentity_GetProperties(u16 id,
ObjectProperties *prop) ObjectProperties *prop)
{ {
realitycheck(L); SCRIPTAPI_PRECHECKHEADER
assert(lua_checkstack(L, 20));
//infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl; //infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl;
StackUnroller stack_unroller(L);
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
luaentity_get(L, id); luaentity_get(L,id);
//int object = lua_gettop(L); //int object = lua_gettop(L);
// Set default values that differ from ObjectProperties defaults // Set default values that differ from ObjectProperties defaults
@ -214,15 +190,14 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
lua_pop(L, 1); lua_pop(L, 1);
} }
void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime) void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
{ {
realitycheck(L); SCRIPTAPI_PRECHECKHEADER
assert(lua_checkstack(L, 20));
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
StackUnroller stack_unroller(L);
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
luaentity_get(L, id); luaentity_get(L,id);
int object = lua_gettop(L); int object = lua_gettop(L);
// State: object is at top of stack // State: object is at top of stack
// Get step function // Get step function
@ -234,22 +209,21 @@ void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
lua_pushnumber(L, dtime); // dtime lua_pushnumber(L, dtime); // dtime
// Call with 2 arguments, 0 results // Call with 2 arguments, 0 results
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, 0))
script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1)); scriptError("error running function 'on_step': %s\n", lua_tostring(L, -1));
} }
// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch, // Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
// tool_capabilities, direction) // tool_capabilities, direction)
void scriptapi_luaentity_punch(lua_State *L, u16 id, void ScriptApiEntity::luaentity_Punch(u16 id,
ServerActiveObject *puncher, float time_from_last_punch, ServerActiveObject *puncher, float time_from_last_punch,
const ToolCapabilities *toolcap, v3f dir) const ToolCapabilities *toolcap, v3f dir)
{ {
realitycheck(L); SCRIPTAPI_PRECHECKHEADER
assert(lua_checkstack(L, 20));
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
StackUnroller stack_unroller(L);
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
luaentity_get(L, id); luaentity_get(L,id);
int object = lua_gettop(L); int object = lua_gettop(L);
// State: object is at top of stack // State: object is at top of stack
// Get function // Get function
@ -258,26 +232,25 @@ void scriptapi_luaentity_punch(lua_State *L, u16 id,
return; return;
luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self lua_pushvalue(L, object); // self
objectref_get_or_create(L, puncher); // Clicker reference objectrefGetOrCreate(puncher); // Clicker reference
lua_pushnumber(L, time_from_last_punch); lua_pushnumber(L, time_from_last_punch);
push_tool_capabilities(L, *toolcap); push_tool_capabilities(L, *toolcap);
push_v3f(L, dir); push_v3f(L, dir);
// Call with 5 arguments, 0 results // Call with 5 arguments, 0 results
if(lua_pcall(L, 5, 0, 0)) if(lua_pcall(L, 5, 0, 0))
script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1)); scriptError("error running function 'on_punch': %s\n", lua_tostring(L, -1));
} }
// Calls entity:on_rightclick(ObjectRef clicker) // Calls entity:on_rightclick(ObjectRef clicker)
void scriptapi_luaentity_rightclick(lua_State *L, u16 id, void ScriptApiEntity::luaentity_Rightclick(u16 id,
ServerActiveObject *clicker) ServerActiveObject *clicker)
{ {
realitycheck(L); SCRIPTAPI_PRECHECKHEADER
assert(lua_checkstack(L, 20));
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
StackUnroller stack_unroller(L);
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
luaentity_get(L, id); luaentity_get(L,id);
int object = lua_gettop(L); int object = lua_gettop(L);
// State: object is at top of stack // State: object is at top of stack
// Get function // Get function
@ -286,8 +259,9 @@ void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
return; return;
luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self lua_pushvalue(L, object); // self
objectref_get_or_create(L, clicker); // Clicker reference objectrefGetOrCreate(clicker); // Clicker reference
// Call with 2 arguments, 0 results // Call with 2 arguments, 0 results
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, 0))
script_error(L, "error running function 'on_rightclick': %s\n", lua_tostring(L, -1)); scriptError("error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
} }

@ -0,0 +1,50 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef S_ENTITY_H_
#define S_ENTITY_H_
#include "cpp_api/s_base.h"
#include "irr_v3d.h"
class ObjectProperties;
class ToolCapabilities;
class ScriptApiEntity
: virtual public ScriptApiBase
{
public:
bool luaentity_Add(u16 id, const char *name);
void luaentity_Activate(u16 id,
const std::string &staticdata, u32 dtime_s);
void luaentity_Remove(u16 id);
std::string luaentity_GetStaticdata(u16 id);
void luaentity_GetProperties(u16 id,
ObjectProperties *prop);
void luaentity_Step(u16 id, float dtime);
void luaentity_Punch(u16 id,
ServerActiveObject *puncher, float time_from_last_punch,
const ToolCapabilities *toolcap, v3f dir);
void luaentity_Rightclick(u16 id,
ServerActiveObject *clicker);
};
#endif /* S_ENTITY_H_ */

@ -0,0 +1,132 @@
/*
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 "cpp_api/s_env.h"
#include "common/c_converter.h"
#include "log.h"
#include "environment.h"
#include "lua_api/l_env.h"
extern "C" {
#include "lauxlib.h"
}
void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp,
u32 blockseed)
{
SCRIPTAPI_PRECHECKHEADER
// Get minetest.registered_on_generateds
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_generateds");
// Call callbacks
push_v3s16(L, minp);
push_v3s16(L, maxp);
lua_pushnumber(L, blockseed);
runCallbacks(3, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiEnv::environment_Step(float dtime)
{
SCRIPTAPI_PRECHECKHEADER
//infostream<<"scriptapi_environment_step"<<std::endl;
// Get minetest.registered_globalsteps
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_globalsteps");
// Call callbacks
lua_pushnumber(L, dtime);
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
{
SCRIPTAPI_PRECHECKHEADER
verbosestream<<"scriptapi_add_environment"<<std::endl;
setEnv(env);
/*
Add ActiveBlockModifiers to environment
*/
// Get minetest.registered_abms
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_abms");
luaL_checktype(L, -1, LUA_TTABLE);
int registered_abms = lua_gettop(L);
if(lua_istable(L, registered_abms)){
int table = lua_gettop(L);
lua_pushnil(L);
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
int id = lua_tonumber(L, -2);
int current_abm = lua_gettop(L);
std::set<std::string> trigger_contents;
lua_getfield(L, current_abm, "nodenames");
if(lua_istable(L, -1)){
int table = lua_gettop(L);
lua_pushnil(L);
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
trigger_contents.insert(lua_tostring(L, -1));
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
} else if(lua_isstring(L, -1)){
trigger_contents.insert(lua_tostring(L, -1));
}
lua_pop(L, 1);
std::set<std::string> required_neighbors;
lua_getfield(L, current_abm, "neighbors");
if(lua_istable(L, -1)){
int table = lua_gettop(L);
lua_pushnil(L);
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
required_neighbors.insert(lua_tostring(L, -1));
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
} else if(lua_isstring(L, -1)){
required_neighbors.insert(lua_tostring(L, -1));
}
lua_pop(L, 1);
float trigger_interval = 10.0;
getfloatfield(L, current_abm, "interval", trigger_interval);
int trigger_chance = 50;
getintfield(L, current_abm, "chance", trigger_chance);
LuaABM *abm = new LuaABM(L, id, trigger_contents,
required_neighbors, trigger_interval, trigger_chance);
env->addActiveBlockModifier(abm);
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
}
lua_pop(L, 1);
}

@ -17,33 +17,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef SCRIPT_HEADER #ifndef S_ENV_H_
#define SCRIPT_HEADER #define S_ENV_H_
#include <exception> #include "cpp_api/s_base.h"
#include <string> #include "irr_v3d.h"
typedef struct lua_State lua_State; class ServerEnvironment;
class LuaError : public std::exception class ScriptApiEnv
: virtual public ScriptApiBase
{ {
public: public:
LuaError(lua_State *L, const std::string &s); // On environment step
void environment_Step(float dtime);
// After generating a piece of map
void environment_OnGenerated(v3s16 minp, v3s16 maxp,u32 blockseed);
virtual ~LuaError() throw() void initializeEnvironment(ServerEnvironment *env);
{}
virtual const char * what() const throw()
{
return m_s.c_str();
}
std::string m_s;
}; };
lua_State* script_init(); #endif /* S_ENV_H_ */
void script_deinit(lua_State *L);
std::string script_get_backtrace(lua_State *L);
void script_error(lua_State *L, const char *fmt, ...);
bool script_load(lua_State *L, const char *path);
#endif

@ -0,0 +1,260 @@
/*
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 "cpp_api/s_inventory.h"
#include "inventorymanager.h"
#include "lua_api/l_inventory.h"
#include "lua_api/l_item.h"
#include "log.h"
// Return number of accepted items to be moved
int ScriptApiDetached::detached_inventory_AllowMove(
const std::string &name,
const std::string &from_list, int from_index,
const std::string &to_list, int to_index,
int count, ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stack
if(!getDetachedInventoryCallback(name, "allow_move"))
return count;
// function(inv, from_list, from_index, to_list, to_index, count, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// from_list
lua_pushstring(L, from_list.c_str());
// from_index
lua_pushinteger(L, from_index + 1);
// to_list
lua_pushstring(L, to_list.c_str());
// to_index
lua_pushinteger(L, to_index + 1);
// count
lua_pushinteger(L, count);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 7, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_move should return a number");
return luaL_checkinteger(L, -1);
}
// Return number of accepted items to be put
int ScriptApiDetached::detached_inventory_AllowPut(
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stack
if(!getDetachedInventoryCallback(name, "allow_put"))
return stack.count; // All will be accepted
// Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_put should return a number");
return luaL_checkinteger(L, -1);
}
// Return number of accepted items to be taken
int ScriptApiDetached::detached_inventory_AllowTake(
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stack
if(!getDetachedInventoryCallback(name, "allow_take"))
return stack.count; // All will be accepted
// Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_take should return a number");
return luaL_checkinteger(L, -1);
}
// Report moved items
void ScriptApiDetached::detached_inventory_OnMove(
const std::string &name,
const std::string &from_list, int from_index,
const std::string &to_list, int to_index,
int count, ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stack
if(!getDetachedInventoryCallback(name, "on_move"))
return;
// function(inv, from_list, from_index, to_list, to_index, count, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// from_list
lua_pushstring(L, from_list.c_str());
// from_index
lua_pushinteger(L, from_index + 1);
// to_list
lua_pushstring(L, to_list.c_str());
// to_index
lua_pushinteger(L, to_index + 1);
// count
lua_pushinteger(L, count);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 7, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
// Report put items
void ScriptApiDetached::detached_inventory_OnPut(
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stack
if(!getDetachedInventoryCallback(name, "on_put"))
return;
// Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
// Report taken items
void ScriptApiDetached::detached_inventory_OnTake(
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stack
if(!getDetachedInventoryCallback(name, "on_take"))
return;
// Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
// Retrieves minetest.detached_inventories[name][callbackname]
// If that is nil or on error, return false and stack is unchanged
// If that is a function, returns true and pushes the
// function onto the stack
bool ScriptApiDetached::getDetachedInventoryCallback(
const std::string &name, const char *callbackname)
{
lua_State *L = getStack();
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "detached_inventories");
lua_remove(L, -2);
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, name.c_str());
lua_remove(L, -2);
// Should be a table
if(lua_type(L, -1) != LUA_TTABLE)
{
errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
lua_pop(L, 1);
return false;
}
lua_getfield(L, -1, callbackname);
lua_remove(L, -2);
// Should be a function or nil
if(lua_type(L, -1) == LUA_TFUNCTION)
{
return true;
}
else if(lua_isnil(L, -1))
{
lua_pop(L, 1);
return false;
}
else
{
errorstream<<"Detached inventory \""<<name<<"\" callback \""
<<callbackname<<"\" is not a function"<<std::endl;
lua_pop(L, 1);
return false;
}
}

@ -0,0 +1,71 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef S_INVENTORY_H_
#define S_INVENTORY_H_
#include "cpp_api/s_base.h"
class ItemStack;
class ScriptApiDetached
: virtual public ScriptApiBase
{
public:
/* Detached inventory callbacks */
// Return number of accepted items to be moved
int detached_inventory_AllowMove(
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 detached_inventory_AllowPut(
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player);
// Return number of accepted items to be taken
int detached_inventory_AllowTake(
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player);
// Report moved items
void detached_inventory_OnMove(
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 detached_inventory_OnPut(
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player);
// Report taken items
void detached_inventory_OnTake(
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player);
private:
bool getDetachedInventoryCallback(
const std::string &name, const char *callbackname);
};
#endif /* S_INVENTORY_H_ */

@ -0,0 +1,164 @@
/*
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 "cpp_api/s_item.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "lua_api/l_item.h"
#include "server.h"
bool ScriptApiItem::item_OnDrop(ItemStack &item,
ServerActiveObject *dropper, v3f pos)
{
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stack
if(!getItemCallback(item.name.c_str(), "on_drop"))
return false;
// Call function
LuaItemStack::create(L, item);
objectrefGetOrCreate(dropper);
pushFloatPos(L, pos);
if(lua_pcall(L, 3, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnil(L, -1))
item = read_item(L,-1, getServer());
return true;
}
bool ScriptApiItem::item_OnPlace(ItemStack &item,
ServerActiveObject *placer, const PointedThing &pointed)
{
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stack
if(!getItemCallback(item.name.c_str(), "on_place"))
return false;
// Call function
LuaItemStack::create(L, item);
objectrefGetOrCreate(placer);
pushPointedThing(pointed);
if(lua_pcall(L, 3, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnil(L, -1))
item = read_item(L,-1, getServer());
return true;
}
bool ScriptApiItem::item_OnUse(ItemStack &item,
ServerActiveObject *user, const PointedThing &pointed)
{
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stack
if(!getItemCallback(item.name.c_str(), "on_use"))
return false;
// Call function
LuaItemStack::create(L, item);
objectrefGetOrCreate(user);
pushPointedThing(pointed);
if(lua_pcall(L, 3, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnil(L, -1))
item = read_item(L,-1, getServer());
return true;
}
// Retrieves minetest.registered_items[name][callbackname]
// If that is nil or on error, return false and stack is unchanged
// If that is a function, returns true and pushes the
// function onto the stack
// If minetest.registered_items[name] doesn't exist, minetest.nodedef_default
// is tried instead so unknown items can still be manipulated to some degree
bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname)
{
lua_State* L = getStack();
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_items");
lua_remove(L, -2);
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, name);
lua_remove(L, -2);
// Should be a table
if(lua_type(L, -1) != LUA_TTABLE)
{
// Report error and clean up
errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
lua_pop(L, 1);
// Try minetest.nodedef_default instead
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "nodedef_default");
lua_remove(L, -2);
luaL_checktype(L, -1, LUA_TTABLE);
}
lua_getfield(L, -1, callbackname);
lua_remove(L, -2);
// Should be a function or nil
if(lua_type(L, -1) == LUA_TFUNCTION)
{
return true;
}
else if(lua_isnil(L, -1))
{
lua_pop(L, 1);
return false;
}
else
{
errorstream<<"Item \""<<name<<"\" callback \""
<<callbackname<<" is not a function"<<std::endl;
lua_pop(L, 1);
return false;
}
}
void ScriptApiItem::pushPointedThing(const PointedThing& pointed)
{
lua_State* L = getStack();
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");
objectrefGet(pointed.object_id);
lua_setfield(L, -2, "ref");
}
else
{
lua_pushstring(L, "nothing");
lua_setfield(L, -2, "type");
}
}

@ -0,0 +1,55 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef S_ITEM_H_
#define S_ITEM_H_
#include "cpp_api/s_base.h"
#include "irr_v3d.h"
class PointedThing;
class ItemStack;
class ServerActiveObject;
class ItemDefinition;
class LuaItemStack;
class ModApiItemMod;
class ScriptApiItem
: virtual public ScriptApiBase
{
public:
bool item_OnDrop(ItemStack &item,
ServerActiveObject *dropper, v3f pos);
bool item_OnPlace(ItemStack &item,
ServerActiveObject *placer, const PointedThing &pointed);
bool item_OnUse(ItemStack &item,
ServerActiveObject *user, const PointedThing &pointed);
protected:
friend class LuaItemStack;
friend class ModApiItemMod;
bool getItemCallback(const char *name, const char *callbackname);
private:
void pushPointedThing(const PointedThing& pointed);
};
#endif /* S_ITEM_H_ */

@ -0,0 +1,233 @@
/*
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 "cpp_api/s_node.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "nodedef.h"
#include "server.h"
struct EnumString ScriptApiNode::es_DrawType[] =
{
{NDT_NORMAL, "normal"},
{NDT_AIRLIKE, "airlike"},
{NDT_LIQUID, "liquid"},
{NDT_FLOWINGLIQUID, "flowingliquid"},
{NDT_GLASSLIKE, "glasslike"},
{NDT_GLASSLIKE_FRAMED, "glasslike_framed"},
{NDT_ALLFACES, "allfaces"},
{NDT_ALLFACES_OPTIONAL, "allfaces_optional"},
{NDT_TORCHLIKE, "torchlike"},
{NDT_SIGNLIKE, "signlike"},
{NDT_PLANTLIKE, "plantlike"},
{NDT_FENCELIKE, "fencelike"},
{NDT_RAILLIKE, "raillike"},
{NDT_NODEBOX, "nodebox"},
{0, NULL},
};
struct EnumString ScriptApiNode::es_ContentParamType2[] =
{
{CPT2_NONE, "none"},
{CPT2_FULL, "full"},
{CPT2_FLOWINGLIQUID, "flowingliquid"},
{CPT2_FACEDIR, "facedir"},
{CPT2_WALLMOUNTED, "wallmounted"},
{0, NULL},
};
struct EnumString ScriptApiNode::es_LiquidType[] =
{
{LIQUID_NONE, "none"},
{LIQUID_FLOWING, "flowing"},
{LIQUID_SOURCE, "source"},
{0, NULL},
};
struct EnumString ScriptApiNode::es_ContentParamType[] =
{
{CPT_NONE, "none"},
{CPT_LIGHT, "light"},
{0, NULL},
};
struct EnumString ScriptApiNode::es_NodeBoxType[] =
{
{NODEBOX_REGULAR, "regular"},
{NODEBOX_FIXED, "fixed"},
{NODEBOX_WALLMOUNTED, "wallmounted"},
{0, NULL},
};
ScriptApiNode::ScriptApiNode() {
}
ScriptApiNode::~ScriptApiNode() {
}
bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node,
ServerActiveObject *puncher)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(), "on_punch"))
return false;
// Call function
push_v3s16(L, p);
pushnode(L, node, ndef);
objectrefGetOrCreate(puncher);
if(lua_pcall(L, 3, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
return true;
}
bool ScriptApiNode::node_on_dig(v3s16 p, MapNode node,
ServerActiveObject *digger)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(), "on_dig"))
return false;
// Call function
push_v3s16(L, p);
pushnode(L, node, ndef);
objectrefGetOrCreate(digger);
if(lua_pcall(L, 3, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
return true;
}
void ScriptApiNode::node_on_construct(v3s16 p, MapNode node)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(), "on_construct"))
return;
// Call function
push_v3s16(L, p);
if(lua_pcall(L, 1, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(), "on_destruct"))
return;
// Call function
push_v3s16(L, p);
if(lua_pcall(L, 1, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(), "after_destruct"))
return;
// Call function
push_v3s16(L, p);
pushnode(L, node, ndef);
if(lua_pcall(L, 2, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(), "on_timer"))
return false;
// Call function
push_v3s16(L, p);
lua_pushnumber(L,dtime);
if(lua_pcall(L, 2, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if((bool)lua_isboolean(L,-1) && (bool)lua_toboolean(L,-1) == true)
return true;
return false;
}
void ScriptApiNode::node_on_receive_fields(v3s16 p,
const std::string &formname,
const std::map<std::string, std::string> &fields,
ServerActiveObject *sender)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = getEnv()->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return;
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(), "on_receive_fields"))
return;
// Call function
// param 1
push_v3s16(L, p);
// param 2
lua_pushstring(L, formname.c_str());
// param 3
lua_newtable(L);
for(std::map<std::string, std::string>::const_iterator
i = fields.begin(); i != fields.end(); i++){
const std::string &name = i->first;
const std::string &value = i->second;
lua_pushstring(L, name.c_str());
lua_pushlstring(L, value.c_str(), value.size());
lua_settable(L, -3);
}
// param 4
objectrefGetOrCreate(sender);
if(lua_pcall(L, 4, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}

@ -0,0 +1,62 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef S_NODE_H_
#define S_NODE_H_
#include <map>
#include "irr_v3d.h"
#include "cpp_api/s_base.h"
#include "cpp_api/s_nodemeta.h"
class MapNode;
class ServerActiveObject;
class ScriptApiNode
: virtual public ScriptApiBase,
public ScriptApiNodemeta
{
public:
ScriptApiNode();
virtual ~ScriptApiNode();
bool node_on_punch(v3s16 p, MapNode node,
ServerActiveObject *puncher);
bool node_on_dig(v3s16 p, MapNode node,
ServerActiveObject *digger);
void node_on_construct(v3s16 p, MapNode node);
void node_on_destruct(v3s16 p, MapNode node);
void node_after_destruct(v3s16 p, MapNode node);
bool node_on_timer(v3s16 p, MapNode node, f32 dtime);
void node_on_receive_fields(v3s16 p,
const std::string &formname,
const std::map<std::string, std::string> &fields,
ServerActiveObject *sender);
public:
static struct EnumString es_DrawType[];
static struct EnumString es_ContentParamType[];
static struct EnumString es_ContentParamType2[];
static struct EnumString es_LiquidType[];
static struct EnumString es_NodeBoxType[];
};
#endif /* S_NODE_H_ */

@ -0,0 +1,261 @@
/*
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 "cpp_api/s_nodemeta.h"
#include "common/c_converter.h"
#include "nodedef.h"
#include "mapnode.h"
#include "server.h"
#include "lua_api/l_item.h"
extern "C" {
#include "lauxlib.h"
}
// Return number of accepted items to be moved
int ScriptApiNodemeta::nodemeta_inventory_AllowMove(v3s16 p,
const std::string &from_list, int from_index,
const std::string &to_list, int to_index,
int count, ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = getEnv()->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return 0;
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(),
"allow_metadata_inventory_move"))
return count;
// function(pos, from_list, from_index, to_list, to_index, count, player)
// pos
push_v3s16(L, p);
// from_list
lua_pushstring(L, from_list.c_str());
// from_index
lua_pushinteger(L, from_index + 1);
// to_list
lua_pushstring(L, to_list.c_str());
// to_index
lua_pushinteger(L, to_index + 1);
// count
lua_pushinteger(L, count);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 7, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_metadata_inventory_move should return a number");
return luaL_checkinteger(L, -1);
}
// Return number of accepted items to be put
int ScriptApiNodemeta::nodemeta_inventory_AllowPut(v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = getEnv()->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return 0;
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(),
"allow_metadata_inventory_put"))
return stack.count;
// Call function(pos, listname, index, stack, player)
// pos
push_v3s16(L, p);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_metadata_inventory_put should return a number");
return luaL_checkinteger(L, -1);
}
// Return number of accepted items to be taken
int ScriptApiNodemeta::nodemeta_inventory_AllowTake(v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = getEnv()->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return 0;
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(),
"allow_metadata_inventory_take"))
return stack.count;
// Call function(pos, listname, index, count, player)
// pos
push_v3s16(L, p);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_metadata_inventory_take should return a number");
return luaL_checkinteger(L, -1);
}
// Report moved items
void ScriptApiNodemeta::nodemeta_inventory_OnMove(v3s16 p,
const std::string &from_list, int from_index,
const std::string &to_list, int to_index,
int count, ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = getEnv()->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return;
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(),
"on_metadata_inventory_move"))
return;
// function(pos, from_list, from_index, to_list, to_index, count, player)
// pos
push_v3s16(L, p);
// from_list
lua_pushstring(L, from_list.c_str());
// from_index
lua_pushinteger(L, from_index + 1);
// to_list
lua_pushstring(L, to_list.c_str());
// to_index
lua_pushinteger(L, to_index + 1);
// count
lua_pushinteger(L, count);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 7, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
// Report put items
void ScriptApiNodemeta::nodemeta_inventory_OnPut(v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = getEnv()->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return;
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(),
"on_metadata_inventory_put"))
return;
// Call function(pos, listname, index, stack, player)
// pos
push_v3s16(L, p);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
// Report taken items
void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = getEnv()->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return;
// Push callback function on stack
if(!getItemCallback(ndef->get(node).name.c_str(),
"on_metadata_inventory_take"))
return;
// Call function(pos, listname, index, stack, player)
// pos
push_v3s16(L, p);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
ScriptApiNodemeta::ScriptApiNodemeta() {
}
ScriptApiNodemeta::~ScriptApiNodemeta() {
}

@ -0,0 +1,67 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef S_NODEMETA_H_
#define S_NODEMETA_H_
#include "cpp_api/s_base.h"
#include "cpp_api/s_item.h"
#include "irr_v3d.h"
class ItemStack;
class ScriptApiNodemeta
: virtual public ScriptApiBase,
public ScriptApiItem
{
public:
ScriptApiNodemeta();
virtual ~ScriptApiNodemeta();
// Return number of accepted items to be moved
int nodemeta_inventory_AllowMove(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 nodemeta_inventory_AllowPut(v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player);
// Return number of accepted items to be taken
int nodemeta_inventory_AllowTake(v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player);
// Report moved items
void nodemeta_inventory_OnMove(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 nodemeta_inventory_OnPut(v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player);
// Report taken items
void nodemeta_inventory_OnTake(v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player);
private:
};
#endif /* S_NODEMETA_H_ */

@ -0,0 +1,113 @@
/*
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 "cpp_api/s_player.h"
void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Get minetest.registered_on_newplayers
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_newplayers");
// Call callbacks
objectrefGetOrCreate(player);
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Get minetest.registered_on_dieplayers
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_dieplayers");
// Call callbacks
objectrefGetOrCreate(player);
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
bool ScriptApiPlayer::on_respawnplayer(ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Get minetest.registered_on_respawnplayers
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_respawnplayers");
// Call callbacks
objectrefGetOrCreate(player);
runCallbacks(1, RUN_CALLBACKS_MODE_OR);
bool positioning_handled_by_some = lua_toboolean(L, -1);
return positioning_handled_by_some;
}
void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Get minetest.registered_on_joinplayers
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_joinplayers");
// Call callbacks
objectrefGetOrCreate(player);
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player)
{
SCRIPTAPI_PRECHECKHEADER
// Get minetest.registered_on_leaveplayers
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_leaveplayers");
// Call callbacks
objectrefGetOrCreate(player);
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
const std::string &formname,
const std::map<std::string, std::string> &fields)
{
SCRIPTAPI_PRECHECKHEADER
// Get minetest.registered_on_chat_messages
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_player_receive_fields");
// Call callbacks
// param 1
objectrefGetOrCreate(player);
// param 2
lua_pushstring(L, formname.c_str());
// param 3
lua_newtable(L);
for(std::map<std::string, std::string>::const_iterator
i = fields.begin(); i != fields.end(); i++){
const std::string &name = i->first;
const std::string &value = i->second;
lua_pushstring(L, name.c_str());
lua_pushlstring(L, value.c_str(), value.size());
lua_settable(L, -3);
}
runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC);
}
ScriptApiPlayer::~ScriptApiPlayer() {
}

@ -0,0 +1,44 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef S_PLAYER_H_
#define S_PLAYER_H_
#include "cpp_api/s_base.h"
class ScriptApiPlayer
: virtual public ScriptApiBase
{
public:
virtual ~ScriptApiPlayer();
void on_newplayer(ServerActiveObject *player);
void on_dieplayer(ServerActiveObject *player);
bool on_respawnplayer(ServerActiveObject *player);
void on_joinplayer(ServerActiveObject *player);
void on_leaveplayer(ServerActiveObject *player);
void on_playerReceiveFields(ServerActiveObject *player,
const std::string &formname,
const std::map<std::string, std::string> &fields);
};
#endif /* S_PLAYER_H_ */

@ -0,0 +1,291 @@
/*
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.
*/
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include "scriptapi.h"
#include "common/c_converter.h"
#include "lua_api/l_base.h"
#include "log.h"
#include "mods.h"
int script_ErrorHandler(lua_State *L) {
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1);
lua_pushinteger(L, 2);
lua_call(L, 2, 1);
return 1;
}
bool ScriptApi::getAuth(const std::string &playername,
std::string *dst_password, std::set<std::string> *dst_privs)
{
SCRIPTAPI_PRECHECKHEADER
getAuthHandler();
lua_getfield(L, -1, "get_auth");
if(lua_type(L, -1) != LUA_TFUNCTION)
throw LuaError(L, "Authentication handler missing get_auth");
lua_pushstring(L, playername.c_str());
if(lua_pcall(L, 1, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
// nil = login not allowed
if(lua_isnil(L, -1))
return false;
luaL_checktype(L, -1, LUA_TTABLE);
std::string password;
bool found = getstringfield(L, -1, "password", password);
if(!found)
throw LuaError(L, "Authentication handler didn't return password");
if(dst_password)
*dst_password = password;
lua_getfield(L, -1, "privileges");
if(!lua_istable(L, -1))
throw LuaError(L,
"Authentication handler didn't return privilege table");
if(dst_privs)
readPrivileges(-1, *dst_privs);
lua_pop(L, 1);
return true;
}
void ScriptApi::getAuthHandler()
{
lua_State *L = getStack();
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_auth_handler");
if(lua_isnil(L, -1)){
lua_pop(L, 1);
lua_getfield(L, -1, "builtin_auth_handler");
}
if(lua_type(L, -1) != LUA_TTABLE)
throw LuaError(L, "Authentication handler table not valid");
}
void ScriptApi::readPrivileges(int index,std::set<std::string> &result)
{
lua_State *L = getStack();
result.clear();
lua_pushnil(L);
if(index < 0)
index -= 1;
while(lua_next(L, index) != 0){
// key at index -2 and value at index -1
std::string key = luaL_checkstring(L, -2);
bool value = lua_toboolean(L, -1);
if(value)
result.insert(key);
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
}
void ScriptApi::createAuth(const std::string &playername,
const std::string &password)
{
SCRIPTAPI_PRECHECKHEADER
getAuthHandler();
lua_getfield(L, -1, "create_auth");
if(lua_type(L, -1) != LUA_TFUNCTION)
throw LuaError(L, "Authentication handler missing create_auth");
lua_pushstring(L, playername.c_str());
lua_pushstring(L, password.c_str());
if(lua_pcall(L, 2, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
}
bool ScriptApi::setPassword(const std::string &playername,
const std::string &password)
{
SCRIPTAPI_PRECHECKHEADER
getAuthHandler();
lua_getfield(L, -1, "set_password");
if(lua_type(L, -1) != LUA_TFUNCTION)
throw LuaError(L, "Authentication handler missing set_password");
lua_pushstring(L, playername.c_str());
lua_pushstring(L, password.c_str());
if(lua_pcall(L, 2, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
return lua_toboolean(L, -1);
}
bool ScriptApi::on_chat_message(const std::string &name,
const std::string &message)
{
SCRIPTAPI_PRECHECKHEADER
// Get minetest.registered_on_chat_messages
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_chat_messages");
// Call callbacks
lua_pushstring(L, name.c_str());
lua_pushstring(L, message.c_str());
runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC);
bool ate = lua_toboolean(L, -1);
return ate;
}
void ScriptApi::on_shutdown()
{
SCRIPTAPI_PRECHECKHEADER
// Get registered shutdown hooks
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_shutdown");
// Call callbacks
runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
}
bool ScriptApi::loadMod(const std::string &scriptpath,const std::string &modname)
{
ModNameStorer modnamestorer(getStack(), modname);
if(!string_allowed(modname, MODNAME_ALLOWED_CHARS)){
errorstream<<"Error loading mod \""<<modname
<<"\": modname does not follow naming conventions: "
<<"Only chararacters [a-z0-9_] are allowed."<<std::endl;
return false;
}
bool success = false;
try{
success = scriptLoad(scriptpath.c_str());
}
catch(LuaError &e){
errorstream<<"Error loading mod \""<<modname
<<"\": "<<e.what()<<std::endl;
}
return success;
}
ScriptApi::ScriptApi() {
assert("Invalid call to default constructor of scriptapi!" == 0);
}
ScriptApi::ScriptApi(Server* server)
{
setServer(server);
setStack(luaL_newstate());
assert(getStack());
//TODO add security
luaL_openlibs(getStack());
SCRIPTAPI_PRECHECKHEADER
lua_pushlightuserdata(L, this);
lua_setfield(L, LUA_REGISTRYINDEX, "scriptapi");
lua_newtable(L);
lua_setglobal(L, "minetest");
for (std::vector<ModApiBase*>::iterator i = m_mod_api_modules->begin();
i != m_mod_api_modules->end(); i++) {
//initializers are called within minetest global table!
lua_getglobal(L, "minetest");
int top = lua_gettop(L);
bool ModInitializedSuccessfull = (*i)->Initialize(L,top);
assert(ModInitializedSuccessfull);
}
infostream << "SCRIPTAPI: initialized " << m_mod_api_modules->size()
<< " modules" << std::endl;
// Get the main minetest table
lua_getglobal(L, "minetest");
// Add tables to minetest
lua_newtable(L);
lua_setfield(L, -2, "object_refs");
lua_newtable(L);
lua_setfield(L, -2, "luaentities");
}
ScriptApi::~ScriptApi() {
lua_close(getStack());
}
bool ScriptApi::scriptLoad(const char *path)
{
lua_State* L = getStack();
setStack(0);
verbosestream<<"Loading and running script from "<<path<<std::endl;
lua_pushcfunction(L, script_ErrorHandler);
int errorhandler = lua_gettop(L);
int ret = luaL_loadfile(L, path) || lua_pcall(L, 0, 0, errorhandler);
if(ret){
errorstream<<"========== ERROR FROM LUA ==========="<<std::endl;
errorstream<<"Failed to load and run script from "<<std::endl;
errorstream<<path<<":"<<std::endl;
errorstream<<std::endl;
errorstream<<lua_tostring(L, -1)<<std::endl;
errorstream<<std::endl;
errorstream<<"=======END OF ERROR FROM LUA ========"<<std::endl;
lua_pop(L, 1); // Pop error message from stack
lua_pop(L, 1); // Pop the error handler from stack
return false;
}
lua_pop(L, 1); // Pop the error handler from stack
return true;
}
bool ScriptApi::registerModApiModule(ModApiBase* ptr) {
if (ScriptApi::m_mod_api_modules == 0)
ScriptApi::m_mod_api_modules = new std::vector<ModApiBase*>();
assert(ScriptApi::m_mod_api_modules != 0);
ScriptApi::m_mod_api_modules->push_back(ptr);
return true;
}
std::vector<ModApiBase*>* ScriptApi::m_mod_api_modules = 0;

@ -0,0 +1,82 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef SCRIPTAPI_H_
#define SCRIPTAPI_H_
#include <map>
#include <set>
#include <vector>
#include "cpp_api/s_base.h"
#include "cpp_api/s_player.h"
#include "cpp_api/s_env.h"
#include "cpp_api/s_node.h"
#include "cpp_api/s_inventory.h"
#include "cpp_api/s_entity.h"
class ModApiBase;
/*****************************************************************************/
/* Scriptapi <-> Core Interface */
/*****************************************************************************/
class ScriptApi
: virtual public ScriptApiBase,
public ScriptApiPlayer,
public ScriptApiEnv,
public ScriptApiNode,
public ScriptApiDetached,
public ScriptApiEntity
{
public:
ScriptApi();
ScriptApi(Server* server);
~ScriptApi();
// Returns true if script handled message
bool on_chat_message(const std::string &name, const std::string &message);
/* server */
void on_shutdown();
/* auth */
bool getAuth(const std::string &playername,
std::string *dst_password, std::set<std::string> *dst_privs);
void createAuth(const std::string &playername,
const std::string &password);
bool setPassword(const std::string &playername,
const std::string &password);
/** register a lua api module to scriptapi */
static bool registerModApiModule(ModApiBase* prototype);
/** load a mod **/
bool loadMod(const std::string &scriptpath,const std::string &modname);
private:
void getAuthHandler();
void readPrivileges(int index,std::set<std::string> &result);
bool scriptLoad(const char *path);
static std::vector<ModApiBase*>* m_mod_api_modules;
};
#endif /* SCRIPTAPI_H_ */

@ -0,0 +1,13 @@
set(SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_base.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_craft.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_env.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_inventory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_item.cpp
${CMAKE_CURRENT_SOURCE_DIR}/luaapi.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_nodemeta.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_nodetimer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_noise.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_object.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_particles.cpp
PARENT_SCOPE)

@ -0,0 +1,63 @@
/*
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 "cpp_api/scriptapi.h"
#include "lua_api/l_base.h"
#include "common/c_internal.h"
#include "log.h"
extern "C" {
#include "lua.h"
}
ModApiBase::ModApiBase() {
ScriptApi::registerModApiModule(this);
}
Server* ModApiBase::getServer(lua_State* L) {
return get_scriptapi(L)->getServer();
}
Environment* ModApiBase::getEnv(lua_State* L) {
return get_scriptapi(L)->getEnv();
}
bool ModApiBase::registerFunction( lua_State* L,
const char* name,
lua_CFunction fct,
int top
) {
//TODO check presence first!
lua_pushstring(L,name);
lua_pushcfunction(L,fct);
lua_settable(L, top);
return true;
}
struct EnumString es_BiomeTerrainType[] =
{
{BIOME_TERRAIN_NORMAL, "normal"},
{BIOME_TERRAIN_LIQUID, "liquid"},
{BIOME_TERRAIN_NETHER, "nether"},
{BIOME_TERRAIN_AETHER, "aether"},
{BIOME_TERRAIN_FLAT, "flat"},
{0, NULL},
};

@ -0,0 +1,63 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef L_BASE_H_
#define L_BASE_H_
#include "biome.h"
#include "common/c_types.h"
extern "C" {
#include "lua.h"
}
extern struct EnumString es_BiomeTerrainType[];
class ScriptApi;
class Server;
class Environment;
typedef class ModApiBase {
public:
ModApiBase();
virtual bool Initialize(lua_State* L, int top) = 0;
virtual ~ModApiBase() {};
protected:
static Server* getServer( lua_State* L);
static Environment* getEnv( lua_State* L);
static bool registerFunction( lua_State* L,
const char* name,
lua_CFunction fct,
int top
);
} ModApiBase;
#if (defined(WIN32) || defined(_WIN32_WCE))
#define NO_MAP_LOCK_REQUIRED
#else
#include "main.h"
#include "profiler.h"
#define NO_MAP_LOCK_REQUIRED ScopeProfiler nolocktime(g_profiler,"Scriptapi: unlockable time",SPT_ADD)
//#define NO_ENVLOCK_REQUIRED assert(getServer(L).m_env_mutex.IsLocked() == false)
#endif
#endif /* L_BASE_H_ */

@ -17,20 +17,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "scriptapi.h"
#include "scriptapi_craft.h" #include "lua_api/l_craft.h"
#include "common/c_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "server.h"
#include "lua_api/l_item.h"
extern "C" { extern "C" {
#include <lauxlib.h> #include "lauxlib.h"
} }
#include "script.h" ModApiCraft::ModApiCraft()
#include "scriptapi_types.h" : ModApiBase() {
#include "scriptapi_common.h"
#include "scriptapi_item.h"
}
struct EnumString es_CraftMethod[] = struct EnumString ModApiCraft::es_CraftMethod[] =
{ {
{CRAFT_METHOD_NORMAL, "normal"}, {CRAFT_METHOD_NORMAL, "normal"},
{CRAFT_METHOD_COOKING, "cooking"}, {CRAFT_METHOD_COOKING, "cooking"},
@ -40,7 +44,7 @@ struct EnumString es_CraftMethod[] =
// helper for register_craft // helper for register_craft
bool read_craft_recipe_shaped(lua_State *L, int index, bool ModApiCraft::readCraftRecipeShaped(lua_State *L, int index,
int &width, std::vector<std::string> &recipe) int &width, std::vector<std::string> &recipe)
{ {
if(index < 0) if(index < 0)
@ -81,7 +85,7 @@ bool read_craft_recipe_shaped(lua_State *L, int index,
} }
// helper for register_craft // helper for register_craft
bool read_craft_recipe_shapeless(lua_State *L, int index, bool ModApiCraft::readCraftRecipeShapeless(lua_State *L, int index,
std::vector<std::string> &recipe) std::vector<std::string> &recipe)
{ {
if(index < 0) if(index < 0)
@ -103,7 +107,7 @@ bool read_craft_recipe_shapeless(lua_State *L, int index,
} }
// helper for register_craft // helper for register_craft
bool read_craft_replacements(lua_State *L, int index, bool ModApiCraft::readCraftReplacements(lua_State *L, int index,
CraftReplacements &replacements) CraftReplacements &replacements)
{ {
if(index < 0) if(index < 0)
@ -135,15 +139,16 @@ bool read_craft_replacements(lua_State *L, int index,
return true; return true;
} }
// register_craft({output=item, recipe={{item00,item10},{item01,item11}}) // register_craft({output=item, recipe={{item00,item10},{item01,item11}})
int l_register_craft(lua_State *L) int ModApiCraft::l_register_craft(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
//infostream<<"register_craft"<<std::endl; //infostream<<"register_craft"<<std::endl;
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
int table = 1; int table = 1;
// Get the writable craft definition manager from the server // Get the writable craft definition manager from the server
IWritableCraftDefManager *craftdef = IWritableCraftDefManager *craftdef =
get_server(L)->getWritableCraftDefManager(); getServer(L)->getWritableCraftDefManager();
std::string type = getstringfield_default(L, table, "type", "shaped"); std::string type = getstringfield_default(L, table, "type", "shaped");
@ -161,7 +166,7 @@ int l_register_craft(lua_State *L)
if(lua_isnil(L, -1)) if(lua_isnil(L, -1))
throw LuaError(L, "Crafting definition is missing a recipe" throw LuaError(L, "Crafting definition is missing a recipe"
" (output=\"" + output + "\")"); " (output=\"" + output + "\")");
if(!read_craft_recipe_shaped(L, -1, width, recipe)) if(!readCraftRecipeShaped(L, -1, width, recipe))
throw LuaError(L, "Invalid crafting recipe" throw LuaError(L, "Invalid crafting recipe"
" (output=\"" + output + "\")"); " (output=\"" + output + "\")");
@ -169,7 +174,7 @@ int l_register_craft(lua_State *L)
lua_getfield(L, table, "replacements"); lua_getfield(L, table, "replacements");
if(!lua_isnil(L, -1)) if(!lua_isnil(L, -1))
{ {
if(!read_craft_replacements(L, -1, replacements)) if(!readCraftReplacements(L, -1, replacements))
throw LuaError(L, "Invalid replacements" throw LuaError(L, "Invalid replacements"
" (output=\"" + output + "\")"); " (output=\"" + output + "\")");
} }
@ -193,7 +198,7 @@ int l_register_craft(lua_State *L)
throw LuaError(L, "Crafting definition (shapeless)" throw LuaError(L, "Crafting definition (shapeless)"
" is missing a recipe" " is missing a recipe"
" (output=\"" + output + "\")"); " (output=\"" + output + "\")");
if(!read_craft_recipe_shapeless(L, -1, recipe)) if(!readCraftRecipeShapeless(L, -1, recipe))
throw LuaError(L, "Invalid crafting recipe" throw LuaError(L, "Invalid crafting recipe"
" (output=\"" + output + "\")"); " (output=\"" + output + "\")");
@ -201,7 +206,7 @@ int l_register_craft(lua_State *L)
lua_getfield(L, table, "replacements"); lua_getfield(L, table, "replacements");
if(!lua_isnil(L, -1)) if(!lua_isnil(L, -1))
{ {
if(!read_craft_replacements(L, -1, replacements)) if(!readCraftReplacements(L, -1, replacements))
throw LuaError(L, "Invalid replacements" throw LuaError(L, "Invalid replacements"
" (output=\"" + output + "\")"); " (output=\"" + output + "\")");
} }
@ -242,7 +247,7 @@ int l_register_craft(lua_State *L)
lua_getfield(L, table, "replacements"); lua_getfield(L, table, "replacements");
if(!lua_isnil(L, -1)) if(!lua_isnil(L, -1))
{ {
if(!read_craft_replacements(L, -1, replacements)) if(!readCraftReplacements(L, -1, replacements))
throw LuaError(L, "Invalid replacements" throw LuaError(L, "Invalid replacements"
" (cooking output=\"" + output + "\")"); " (cooking output=\"" + output + "\")");
} }
@ -266,7 +271,7 @@ int l_register_craft(lua_State *L)
lua_getfield(L, table, "replacements"); lua_getfield(L, table, "replacements");
if(!lua_isnil(L, -1)) if(!lua_isnil(L, -1))
{ {
if(!read_craft_replacements(L, -1, replacements)) if(!readCraftReplacements(L, -1, replacements))
throw LuaError(L, "Invalid replacements" throw LuaError(L, "Invalid replacements"
" (fuel recipe=\"" + recipe + "\")"); " (fuel recipe=\"" + recipe + "\")");
} }
@ -285,8 +290,10 @@ int l_register_craft(lua_State *L)
} }
// get_craft_result(input) // get_craft_result(input)
int l_get_craft_result(lua_State *L) int ModApiCraft::l_get_craft_result(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
int input_i = 1; int input_i = 1;
std::string method_s = getstringfield_default(L, input_i, "method", "normal"); std::string method_s = getstringfield_default(L, input_i, "method", "normal");
enum CraftMethod method = (CraftMethod)getenumfield(L, input_i, "method", enum CraftMethod method = (CraftMethod)getenumfield(L, input_i, "method",
@ -297,10 +304,10 @@ int l_get_craft_result(lua_State *L)
width = luaL_checkinteger(L, -1); width = luaL_checkinteger(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, input_i, "items"); lua_getfield(L, input_i, "items");
std::vector<ItemStack> items = read_items(L, -1); std::vector<ItemStack> items = read_items(L, -1,getServer(L));
lua_pop(L, 1); // items lua_pop(L, 1); // items
IGameDef *gdef = get_server(L); IGameDef *gdef = getServer(L);
ICraftDefManager *cdef = gdef->cdef(); ICraftDefManager *cdef = gdef->cdef();
CraftInput input(method, width, items); CraftInput input(method, width, items);
CraftOutput output; CraftOutput output;
@ -328,13 +335,15 @@ int l_get_craft_result(lua_State *L)
} }
// get_craft_recipe(result item) // get_craft_recipe(result item)
int l_get_craft_recipe(lua_State *L) int ModApiCraft::l_get_craft_recipe(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
int k = 1; int k = 1;
int input_i = 1; int input_i = 1;
std::string o_item = luaL_checkstring(L,input_i); std::string o_item = luaL_checkstring(L,input_i);
IGameDef *gdef = get_server(L); IGameDef *gdef = getServer(L);
ICraftDefManager *cdef = gdef->cdef(); ICraftDefManager *cdef = gdef->cdef();
CraftInput input; CraftInput input;
CraftOutput output(o_item,0); CraftOutput output(o_item,0);
@ -379,10 +388,12 @@ int l_get_craft_recipe(lua_State *L)
} }
// get_all_craft_recipes(result item) // get_all_craft_recipes(result item)
int l_get_all_craft_recipes(lua_State *L) int ModApiCraft::l_get_all_craft_recipes(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
std::string o_item = luaL_checkstring(L,1); std::string o_item = luaL_checkstring(L,1);
IGameDef *gdef = get_server(L); IGameDef *gdef = getServer(L);
ICraftDefManager *cdef = gdef->cdef(); ICraftDefManager *cdef = gdef->cdef();
CraftInput input; CraftInput input;
CraftOutput output(o_item,0); CraftOutput output(o_item,0);
@ -423,8 +434,8 @@ int l_get_all_craft_recipes(lua_State *L)
{ {
if (i->empty()) if (i->empty())
continue; continue;
lua_pushinteger(L, k); lua_pushinteger(L,k);
lua_pushstring(L, i->name.c_str()); lua_pushstring(L,i->name.c_str());
lua_settable(L, -3); lua_settable(L, -3);
} }
lua_setfield(L, -2, "items"); lua_setfield(L, -2, "items");
@ -451,3 +462,16 @@ int l_get_all_craft_recipes(lua_State *L)
} }
return 1; return 1;
} }
bool ModApiCraft::Initialize(lua_State* L, int top) {
bool retval = true;
retval &= API_FCT(get_all_craft_recipes);
retval &= API_FCT(get_craft_recipe);
retval &= API_FCT(get_craft_result);
retval &= API_FCT(register_craft);
return retval;
}
ModApiCraft modapicraft_prototype;

@ -0,0 +1,52 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef L_CRAFT_H_
#define L_CRAFT_H_
#include <vector>
extern "C" {
#include <lua.h>
}
#include "lua_api/l_base.h"
#include "craftdef.h"
class ModApiCraft : public ModApiBase {
public:
ModApiCraft();
bool Initialize(lua_State* L, int top);
private:
static int l_register_craft(lua_State *L);
static int l_get_craft_recipe(lua_State *L);
static int l_get_all_craft_recipes(lua_State *L);
static int l_get_craft_result(lua_State *L);
static bool readCraftReplacements(lua_State *L, int index,
CraftReplacements &replacements);
static bool readCraftRecipeShapeless(lua_State *L, int index,
std::vector<std::string> &recipe);
static bool readCraftRecipeShaped(lua_State *L, int index,
int &width, std::vector<std::string> &recipe);
static struct EnumString es_CraftMethod[];
};
#endif /* L_CRAFT_H_ */

@ -0,0 +1,687 @@
/*
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 "cpp_api/scriptapi.h"
#include "lua_api/l_base.h"
#include "lua_api/l_env.h"
#include "environment.h"
#include "server.h"
#include "daynightratio.h"
#include "util/pointedthing.h"
#include "content_sao.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "common/c_internal.h"
#include "lua_api/l_nodemeta.h"
#include "lua_api/l_nodetimer.h"
#include "lua_api/l_noise.h"
#include "treegen.h"
#include "pathfinder.h"
#define GET_ENV_PTR ServerEnvironment* env = \
dynamic_cast<ServerEnvironment*>(getEnv(L)); \
if( env == NULL) return 0
void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
u32 active_object_count, u32 active_object_count_wider)
{
ScriptApi* scriptIface = SERVER_TO_SA(env);
scriptIface->realityCheck();
lua_State* L = scriptIface->getStack();
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
// Get minetest.registered_abms
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_abms");
luaL_checktype(L, -1, LUA_TTABLE);
int registered_abms = lua_gettop(L);
// Get minetest.registered_abms[m_id]
lua_pushnumber(L, m_id);
lua_gettable(L, registered_abms);
if(lua_isnil(L, -1))
assert(0);
// Call action
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, "action");
luaL_checktype(L, -1, LUA_TFUNCTION);
push_v3s16(L, p);
pushnode(L, n, env->getGameDef()->ndef());
lua_pushnumber(L, active_object_count);
lua_pushnumber(L, active_object_count_wider);
if(lua_pcall(L, 4, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
// Exported functions
// minetest.set_node(pos, node)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_set_node(lua_State *L)
{
GET_ENV_PTR;
INodeDefManager *ndef = env->getGameDef()->ndef();
// parameters
v3s16 pos = read_v3s16(L, 1);
MapNode n = readnode(L, 2, ndef);
// Do it
bool succeeded = env->setNode(pos, n);
lua_pushboolean(L, succeeded);
return 1;
}
int ModApiEnvMod::l_add_node(lua_State *L)
{
return l_set_node(L);
}
// minetest.remove_node(pos)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_remove_node(lua_State *L)
{
GET_ENV_PTR;
// parameters
v3s16 pos = read_v3s16(L, 1);
// Do it
bool succeeded = env->removeNode(pos);
lua_pushboolean(L, succeeded);
return 1;
}
// minetest.get_node(pos)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node(lua_State *L)
{
GET_ENV_PTR;
// pos
v3s16 pos = read_v3s16(L, 1);
// Do it
MapNode n = env->getMap().getNodeNoEx(pos);
// Return node
pushnode(L, n, env->getGameDef()->ndef());
return 1;
}
// minetest.get_node_or_nil(pos)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node_or_nil(lua_State *L)
{
GET_ENV_PTR;
// pos
v3s16 pos = read_v3s16(L, 1);
// Do it
try{
MapNode n = env->getMap().getNode(pos);
// Return node
pushnode(L, n, env->getGameDef()->ndef());
return 1;
} catch(InvalidPositionException &e)
{
lua_pushnil(L);
return 1;
}
}
// minetest.get_node_light(pos, timeofday)
// pos = {x=num, y=num, z=num}
// timeofday: nil = current time, 0 = night, 0.5 = day
int ModApiEnvMod::l_get_node_light(lua_State *L)
{
GET_ENV_PTR;
// Do it
v3s16 pos = read_v3s16(L, 1);
u32 time_of_day = env->getTimeOfDay();
if(lua_isnumber(L, 2))
time_of_day = 24000.0 * lua_tonumber(L, 2);
time_of_day %= 24000;
u32 dnr = time_to_daynight_ratio(time_of_day, true);
try{
MapNode n = env->getMap().getNode(pos);
INodeDefManager *ndef = env->getGameDef()->ndef();
lua_pushinteger(L, n.getLightBlend(dnr, ndef));
return 1;
} catch(InvalidPositionException &e)
{
lua_pushnil(L);
return 1;
}
}
// minetest.place_node(pos, node)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_place_node(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
MapNode n = readnode(L, 2, env->getGameDef()->ndef());
// Don't attempt to load non-loaded area as of now
MapNode n_old = env->getMap().getNodeNoEx(pos);
if(n_old.getContent() == CONTENT_IGNORE){
lua_pushboolean(L, false);
return 1;
}
// Create item to place
INodeDefManager *ndef = getServer(L)->ndef();
IItemDefManager *idef = getServer(L)->idef();
ItemStack item(ndef->get(n).name, 1, 0, "", idef);
// Make pointed position
PointedThing pointed;
pointed.type = POINTEDTHING_NODE;
pointed.node_abovesurface = pos;
pointed.node_undersurface = pos + v3s16(0,-1,0);
// Place it with a NULL placer (appears in Lua as a non-functional
// ObjectRef)
bool success = get_scriptapi(L)->item_OnPlace(item, NULL, pointed);
lua_pushboolean(L, success);
return 1;
}
// minetest.dig_node(pos)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_dig_node(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
// Don't attempt to load non-loaded area as of now
MapNode n = env->getMap().getNodeNoEx(pos);
if(n.getContent() == CONTENT_IGNORE){
lua_pushboolean(L, false);
return 1;
}
// Dig it out with a NULL digger (appears in Lua as a
// non-functional ObjectRef)
bool success = get_scriptapi(L)->node_on_dig(pos, n, NULL);
lua_pushboolean(L, success);
return 1;
}
// minetest.punch_node(pos)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_punch_node(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
// Don't attempt to load non-loaded area as of now
MapNode n = env->getMap().getNodeNoEx(pos);
if(n.getContent() == CONTENT_IGNORE){
lua_pushboolean(L, false);
return 1;
}
// Punch it with a NULL puncher (appears in Lua as a non-functional
// ObjectRef)
bool success = get_scriptapi(L)->node_on_punch(pos, n, NULL);
lua_pushboolean(L, success);
return 1;
}
// minetest.get_meta(pos)
int ModApiEnvMod::l_get_meta(lua_State *L)
{
GET_ENV_PTR;
// Do it
v3s16 p = read_v3s16(L, 1);
NodeMetaRef::create(L, p, env);
return 1;
}
// minetest.get_node_timer(pos)
int ModApiEnvMod::l_get_node_timer(lua_State *L)
{
GET_ENV_PTR;
// Do it
v3s16 p = read_v3s16(L, 1);
NodeTimerRef::create(L, p, env);
return 1;
}
// minetest.add_entity(pos, entityname) -> ObjectRef or nil
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_add_entity(lua_State *L)
{
GET_ENV_PTR;
// pos
v3f pos = checkFloatPos(L, 1);
// content
const char *name = luaL_checkstring(L, 2);
// Do it
ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, "");
int objectid = env->addActiveObject(obj);
// If failed to add, return nothing (reads as nil)
if(objectid == 0)
return 0;
// Return ObjectRef
get_scriptapi(L)->objectrefGetOrCreate(obj);
return 1;
}
// minetest.add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_add_item(lua_State *L)
{
GET_ENV_PTR;
// pos
//v3f pos = checkFloatPos(L, 1);
// item
ItemStack item = read_item(L, 2,getServer(L));
if(item.empty() || !item.isKnown(getServer(L)->idef()))
return 0;
// Use minetest.spawn_item to spawn a __builtin:item
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "spawn_item");
if(lua_isnil(L, -1))
return 0;
lua_pushvalue(L, 1);
lua_pushstring(L, item.getItemString().c_str());
if(lua_pcall(L, 2, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
return 1;
/*lua_pushvalue(L, 1);
lua_pushstring(L, "__builtin:item");
lua_pushstring(L, item.getItemString().c_str());
return l_add_entity(L);*/
/*// Do it
ServerActiveObject *obj = createItemSAO(env, pos, item.getItemString());
int objectid = env->addActiveObject(obj);
// If failed to add, return nothing (reads as nil)
if(objectid == 0)
return 0;
// Return ObjectRef
objectrefGetOrCreate(L, obj);
return 1;*/
}
// minetest.get_player_by_name(name)
int ModApiEnvMod::l_get_player_by_name(lua_State *L)
{
GET_ENV_PTR;
// Do it
const char *name = luaL_checkstring(L, 1);
Player *player = env->getPlayer(name);
if(player == NULL){
lua_pushnil(L);
return 1;
}
PlayerSAO *sao = player->getPlayerSAO();
if(sao == NULL){
lua_pushnil(L);
return 1;
}
// Put player on stack
get_scriptapi(L)->objectrefGetOrCreate(sao);
return 1;
}
// minetest.get_objects_inside_radius(pos, radius)
int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
{
// Get the table insert function
lua_getglobal(L, "table");
lua_getfield(L, -1, "insert");
int table_insert = lua_gettop(L);
GET_ENV_PTR;
// Do it
v3f pos = checkFloatPos(L, 1);
float radius = luaL_checknumber(L, 2) * BS;
std::set<u16> ids = env->getObjectsInsideRadius(pos, radius);
lua_newtable(L);
int table = lua_gettop(L);
for(std::set<u16>::const_iterator
i = ids.begin(); i != ids.end(); i++){
ServerActiveObject *obj = env->getActiveObject(*i);
// Insert object reference into table
lua_pushvalue(L, table_insert);
lua_pushvalue(L, table);
get_scriptapi(L)->objectrefGetOrCreate(obj);
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
return 1;
}
// minetest.set_timeofday(val)
// val = 0...1
int ModApiEnvMod::l_set_timeofday(lua_State *L)
{
GET_ENV_PTR;
// Do it
float timeofday_f = luaL_checknumber(L, 1);
assert(timeofday_f >= 0.0 && timeofday_f <= 1.0);
int timeofday_mh = (int)(timeofday_f * 24000.0);
// This should be set directly in the environment but currently
// such changes aren't immediately sent to the clients, so call
// the server instead.
//env->setTimeOfDay(timeofday_mh);
getServer(L)->setTimeOfDay(timeofday_mh);
return 0;
}
// minetest.get_timeofday() -> 0...1
int ModApiEnvMod::l_get_timeofday(lua_State *L)
{
GET_ENV_PTR;
// Do it
int timeofday_mh = env->getTimeOfDay();
float timeofday_f = (float)timeofday_mh / 24000.0;
lua_pushnumber(L, timeofday_f);
return 1;
}
// minetest.find_node_near(pos, radius, nodenames) -> pos or nil
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
int ModApiEnvMod::l_find_node_near(lua_State *L)
{
GET_ENV_PTR;
INodeDefManager *ndef = getServer(L)->ndef();
v3s16 pos = read_v3s16(L, 1);
int radius = luaL_checkinteger(L, 2);
std::set<content_t> filter;
if(lua_istable(L, 3)){
int table = 3;
lua_pushnil(L);
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
ndef->getIds(lua_tostring(L, -1), filter);
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
} else if(lua_isstring(L, 3)){
ndef->getIds(lua_tostring(L, 3), filter);
}
for(int d=1; d<=radius; d++){
std::list<v3s16> list;
getFacePositions(list, d);
for(std::list<v3s16>::iterator i = list.begin();
i != list.end(); ++i){
v3s16 p = pos + (*i);
content_t c = env->getMap().getNodeNoEx(p).getContent();
if(filter.count(c) != 0){
push_v3s16(L, p);
return 1;
}
}
}
return 0;
}
// minetest.find_nodes_in_area(minp, maxp, nodenames) -> list of positions
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
{
GET_ENV_PTR;
INodeDefManager *ndef = getServer(L)->ndef();
v3s16 minp = read_v3s16(L, 1);
v3s16 maxp = read_v3s16(L, 2);
std::set<content_t> filter;
if(lua_istable(L, 3)){
int table = 3;
lua_pushnil(L);
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
ndef->getIds(lua_tostring(L, -1), filter);
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
} else if(lua_isstring(L, 3)){
ndef->getIds(lua_tostring(L, 3), filter);
}
// Get the table insert function
lua_getglobal(L, "table");
lua_getfield(L, -1, "insert");
int table_insert = lua_gettop(L);
lua_newtable(L);
int table = lua_gettop(L);
for(s16 x=minp.X; x<=maxp.X; x++)
for(s16 y=minp.Y; y<=maxp.Y; y++)
for(s16 z=minp.Z; z<=maxp.Z; z++)
{
v3s16 p(x,y,z);
content_t c = env->getMap().getNodeNoEx(p).getContent();
if(filter.count(c) != 0){
lua_pushvalue(L, table_insert);
lua_pushvalue(L, table);
push_v3s16(L, p);
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
}
return 1;
}
// minetest.get_perlin(seeddiff, octaves, persistence, scale)
// returns world-specific PerlinNoise
int ModApiEnvMod::l_get_perlin(lua_State *L)
{
GET_ENV_PTR;
int seeddiff = luaL_checkint(L, 1);
int octaves = luaL_checkint(L, 2);
float persistence = luaL_checknumber(L, 3);
float scale = luaL_checknumber(L, 4);
LuaPerlinNoise *n = new LuaPerlinNoise(seeddiff + int(env->getServerMap().getSeed()), octaves, persistence, scale);
*(void **)(lua_newuserdata(L, sizeof(void *))) = n;
luaL_getmetatable(L, "PerlinNoise");
lua_setmetatable(L, -2);
return 1;
}
// minetest.get_perlin_map(noiseparams, size)
// returns world-specific PerlinNoiseMap
int ModApiEnvMod::l_get_perlin_map(lua_State *L)
{
GET_ENV_PTR;
NoiseParams *np = read_noiseparams(L, 1);
if (!np)
return 0;
v3s16 size = read_v3s16(L, 2);
int seed = (int)(env->getServerMap().getSeed());
LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(np, seed, size);
*(void **)(lua_newuserdata(L, sizeof(void *))) = n;
luaL_getmetatable(L, "PerlinNoiseMap");
lua_setmetatable(L, -2);
return 1;
}
// minetest.clear_objects()
// clear all objects in the environment
int ModApiEnvMod::l_clear_objects(lua_State *L)
{
GET_ENV_PTR;
env->clearAllObjects();
return 0;
}
// minetest.line_of_sight(pos1, pos2, stepsize) -> true/false
int ModApiEnvMod::l_line_of_sight(lua_State *L) {
float stepsize = 1.0;
GET_ENV_PTR;
// read position 1 from lua
v3f pos1 = checkFloatPos(L, 2);
// read position 2 from lua
v3f pos2 = checkFloatPos(L, 2);
//read step size from lua
if(lua_isnumber(L, 3))
stepsize = lua_tonumber(L, 3);
return (env->line_of_sight(pos1,pos2,stepsize));
}
// minetest.find_path(pos1, pos2, searchdistance,
// max_jump, max_drop, algorithm) -> table containing path
int ModApiEnvMod::l_find_path(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos1 = read_v3s16(L, 2);
v3s16 pos2 = read_v3s16(L, 3);
unsigned int searchdistance = luaL_checkint(L, 4);
unsigned int max_jump = luaL_checkint(L, 5);
unsigned int max_drop = luaL_checkint(L, 6);
algorithm algo = A_PLAIN_NP;
if(! lua_isnil(L, 7)) {
std::string algorithm = luaL_checkstring(L,7);
if (algorithm == "A*")
algo = A_PLAIN;
if (algorithm == "Dijkstra")
algo = DIJKSTRA;
}
std::vector<v3s16> path =
get_Path(env,pos1,pos2,searchdistance,max_jump,max_drop,algo);
if (path.size() > 0)
{
lua_newtable(L);
int top = lua_gettop(L);
unsigned int index = 1;
for (std::vector<v3s16>::iterator i = path.begin(); i != path.end();i++)
{
lua_pushnumber(L,index);
push_v3s16(L, *i);
lua_settable(L, top);
index++;
}
return 1;
}
return 0;
}
// minetest.spawn_tree(pos, treedef)
int ModApiEnvMod::l_spawn_tree(lua_State *L)
{
GET_ENV_PTR;
v3s16 p0 = read_v3s16(L, 1);
treegen::TreeDef tree_def;
std::string trunk,leaves,fruit;
INodeDefManager *ndef = env->getGameDef()->ndef();
if(lua_istable(L, 2))
{
getstringfield(L, 2, "axiom", tree_def.initial_axiom);
getstringfield(L, 2, "rules_a", tree_def.rules_a);
getstringfield(L, 2, "rules_b", tree_def.rules_b);
getstringfield(L, 2, "rules_c", tree_def.rules_c);
getstringfield(L, 2, "rules_d", tree_def.rules_d);
getstringfield(L, 2, "trunk", trunk);
tree_def.trunknode=ndef->getId(trunk);
getstringfield(L, 2, "leaves", leaves);
tree_def.leavesnode=ndef->getId(leaves);
tree_def.leaves2_chance=0;
getstringfield(L, 2, "leaves2", leaves);
if (leaves !="")
{
tree_def.leaves2node=ndef->getId(leaves);
getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance);
}
getintfield(L, 2, "angle", tree_def.angle);
getintfield(L, 2, "iterations", tree_def.iterations);
getintfield(L, 2, "random_level", tree_def.iterations_random_level);
getstringfield(L, 2, "trunk_type", tree_def.trunk_type);
getboolfield(L, 2, "thin_branches", tree_def.thin_branches);
tree_def.fruit_chance=0;
getstringfield(L, 2, "fruit", fruit);
if (fruit != "")
{
tree_def.fruitnode=ndef->getId(fruit);
getintfield(L, 2, "fruit_chance",tree_def.fruit_chance);
}
getintfield(L, 2, "seed", tree_def.seed);
}
else
return 0;
treegen::spawn_ltree (env, p0, ndef, tree_def);
return 1;
}
bool ModApiEnvMod::Initialize(lua_State *L,int top)
{
bool retval = true;
retval &= API_FCT(set_node);
retval &= API_FCT(add_node);
retval &= API_FCT(add_item);
retval &= API_FCT(remove_node);
retval &= API_FCT(get_node);
retval &= API_FCT(get_node_or_nil);
retval &= API_FCT(get_node_light);
retval &= API_FCT(place_node);
retval &= API_FCT(dig_node);
retval &= API_FCT(punch_node);
retval &= API_FCT(add_entity);
retval &= API_FCT(get_meta);
retval &= API_FCT(get_node_timer);
retval &= API_FCT(get_player_by_name);
retval &= API_FCT(get_objects_inside_radius);
retval &= API_FCT(set_timeofday);
retval &= API_FCT(get_timeofday);
retval &= API_FCT(find_node_near);
retval &= API_FCT(find_nodes_in_area);
retval &= API_FCT(get_perlin);
retval &= API_FCT(get_perlin_map);
retval &= API_FCT(clear_objects);
retval &= API_FCT(spawn_tree);
return retval;
}
ModApiEnvMod modapienv_prototype;

@ -1,5 +1,5 @@
/* /*
Minetest-c55 Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -17,8 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef LUA_ENVIRONMENT_H_ #ifndef L_ENV_H_
#define LUA_ENVIRONMENT_H_ #define L_ENV_H_
extern "C" { extern "C" {
#include <lua.h> #include <lua.h>
@ -26,145 +26,147 @@ extern "C" {
} }
#include "environment.h" #include "environment.h"
#include "lua_api/l_base.h"
/* class ModApiEnvMod
EnvRef :public ModApiBase
*/
class EnvRef
{ {
private: private:
ServerEnvironment *m_env; // minetest.set_node(pos, node)
static const char className[];
static const luaL_reg methods[];
static int gc_object(lua_State *L) ;
static EnvRef *checkobject(lua_State *L, int narg);
// Exported functions
// EnvRef:set_node(pos, node)
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
static int l_set_node(lua_State *L); static int l_set_node(lua_State *L);
static int l_add_node(lua_State *L); static int l_add_node(lua_State *L);
// EnvRef:remove_node(pos) // minetest.remove_node(pos)
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
static int l_remove_node(lua_State *L); static int l_remove_node(lua_State *L);
// EnvRef:get_node(pos) // minetest.get_node(pos)
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
static int l_get_node(lua_State *L); static int l_get_node(lua_State *L);
// EnvRef:get_node_or_nil(pos) // minetest.get_node_or_nil(pos)
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
static int l_get_node_or_nil(lua_State *L); static int l_get_node_or_nil(lua_State *L);
// EnvRef:get_node_light(pos, timeofday) // minetest.get_node_light(pos, timeofday)
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
// timeofday: nil = current time, 0 = night, 0.5 = day // timeofday: nil = current time, 0 = night, 0.5 = day
static int l_get_node_light(lua_State *L); static int l_get_node_light(lua_State *L);
// EnvRef:place_node(pos, node) // minetest.place_node(pos, node)
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
static int l_place_node(lua_State *L); static int l_place_node(lua_State *L);
// EnvRef:dig_node(pos) // minetest.dig_node(pos)
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
static int l_dig_node(lua_State *L); static int l_dig_node(lua_State *L);
// EnvRef:punch_node(pos) // minetest.punch_node(pos)
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
static int l_punch_node(lua_State *L); static int l_punch_node(lua_State *L);
// EnvRef:get_meta(pos) // minetest.get_meta(pos)
static int l_get_meta(lua_State *L); static int l_get_meta(lua_State *L);
// EnvRef:get_node_timer(pos) // minetest.get_node_timer(pos)
static int l_get_node_timer(lua_State *L); static int l_get_node_timer(lua_State *L);
// EnvRef:add_entity(pos, entityname) -> ObjectRef or nil // minetest.add_entity(pos, entityname) -> ObjectRef or nil
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
static int l_add_entity(lua_State *L); static int l_add_entity(lua_State *L);
// EnvRef:add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil // minetest.add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
// pos = {x=num, y=num, z=num} // pos = {x=num, y=num, z=num}
static int l_add_item(lua_State *L); static int l_add_item(lua_State *L);
// EnvRef:add_rat(pos) // minetest.get_player_by_name(name)
// pos = {x=num, y=num, z=num}
static int l_add_rat(lua_State *L);
// EnvRef:add_firefly(pos)
// pos = {x=num, y=num, z=num}
static int l_add_firefly(lua_State *L);
// EnvRef:get_player_by_name(name)
static int l_get_player_by_name(lua_State *L); static int l_get_player_by_name(lua_State *L);
// EnvRef:get_objects_inside_radius(pos, radius) // minetest.get_objects_inside_radius(pos, radius)
static int l_get_objects_inside_radius(lua_State *L); static int l_get_objects_inside_radius(lua_State *L);
// EnvRef:set_timeofday(val) // minetest.set_timeofday(val)
// val = 0...1 // val = 0...1
static int l_set_timeofday(lua_State *L); static int l_set_timeofday(lua_State *L);
// EnvRef:get_timeofday() -> 0...1 // minetest.get_timeofday() -> 0...1
static int l_get_timeofday(lua_State *L); static int l_get_timeofday(lua_State *L);
// EnvRef:find_node_near(pos, radius, nodenames) -> pos or nil // minetest.find_node_near(pos, radius, nodenames) -> pos or nil
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt" // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
static int l_find_node_near(lua_State *L); static int l_find_node_near(lua_State *L);
// EnvRef:find_nodes_in_area(minp, maxp, nodenames) -> list of positions // minetest.find_nodes_in_area(minp, maxp, nodenames) -> list of positions
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt" // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
static int l_find_nodes_in_area(lua_State *L); static int l_find_nodes_in_area(lua_State *L);
// EnvRef:get_perlin(seeddiff, octaves, persistence, scale) // minetest.get_perlin(seeddiff, octaves, persistence, scale)
// returns world-specific PerlinNoise // returns world-specific PerlinNoise
static int l_get_perlin(lua_State *L); static int l_get_perlin(lua_State *L);
// EnvRef:get_perlin_map(noiseparams, size) // minetest.get_perlin_map(noiseparams, size)
// returns world-specific PerlinNoiseMap // returns world-specific PerlinNoiseMap
static int l_get_perlin_map(lua_State *L); static int l_get_perlin_map(lua_State *L);
// EnvRef:clear_objects() // minetest.clear_objects()
// clear all objects in the environment // clear all objects in the environment
static int l_clear_objects(lua_State *L); static int l_clear_objects(lua_State *L);
// minetest.spawn_tree(pos, treedef)
static int l_spawn_tree(lua_State *L); static int l_spawn_tree(lua_State *L);
// minetest.line_of_sight(pos1, pos2, stepsize) -> true/false
static int l_line_of_sight(lua_State *L); static int l_line_of_sight(lua_State *L);
//find a path between two positions // minetest.find_path(pos1, pos2, searchdistance,
// max_jump, max_drop, algorithm) -> table containing path
static int l_find_path(lua_State *L); static int l_find_path(lua_State *L);
public: public:
EnvRef(ServerEnvironment *env); bool Initialize(lua_State *L, int top);
~EnvRef();
// Creates an EnvRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side.
static void create(lua_State *L, ServerEnvironment *env);
static void set_null(lua_State *L);
static void Register(lua_State *L);
}; };
/*****************************************************************************/ class LuaABM : public ActiveBlockModifier
/* Minetest interface */ {
/*****************************************************************************/ private:
// On environment step int m_id;
void scriptapi_environment_step(lua_State *L, float dtime);
// After generating a piece of map
void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
u32 blockseed);
void scriptapi_add_environment(lua_State *L, ServerEnvironment *env);
#endif /* LUA_ENVIRONMENT_H_ */ std::set<std::string> m_trigger_contents;
std::set<std::string> m_required_neighbors;
float m_trigger_interval;
u32 m_trigger_chance;
public:
LuaABM(lua_State *L, int id,
const std::set<std::string> &trigger_contents,
const std::set<std::string> &required_neighbors,
float trigger_interval, u32 trigger_chance):
m_id(id),
m_trigger_contents(trigger_contents),
m_required_neighbors(required_neighbors),
m_trigger_interval(trigger_interval),
m_trigger_chance(trigger_chance)
{
}
virtual std::set<std::string> getTriggerContents()
{
return m_trigger_contents;
}
virtual std::set<std::string> getRequiredNeighbors()
{
return m_required_neighbors;
}
virtual float getTriggerInterval()
{
return m_trigger_interval;
}
virtual u32 getTriggerChance()
{
return m_trigger_chance;
}
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
u32 active_object_count, u32 active_object_count_wider);
};
#endif /* L_ENV_H_ */

@ -17,17 +17,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "scriptapi.h" #include "cpp_api/scriptapi.h"
#include "scriptapi_inventory.h" #include "common/c_converter.h"
#include "common/c_content.h"
#include "lua_api/l_inventory.h"
#include "lua_api/l_item.h"
#include "common/c_internal.h"
#include "server.h" #include "server.h"
#include "script.h"
#include "log.h" #include "log.h"
#include "scriptapi_types.h" #include "inventorymanager.h"
#include "scriptapi_common.h"
#include "scriptapi_inventory.h"
#include "scriptapi_item.h"
#include "scriptapi_object.h"
/* /*
InvRef InvRef
@ -42,12 +40,13 @@ InvRef* InvRef::checkobject(lua_State *L, int narg)
Inventory* InvRef::getinv(lua_State *L, InvRef *ref) Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
{ {
return get_server(L)->getInventory(ref->m_loc); return STACK_TO_SERVER(L)->getInventory(ref->m_loc);
} }
InventoryList* InvRef::getlist(lua_State *L, InvRef *ref, InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
const char *listname) const char *listname)
{ {
NO_MAP_LOCK_REQUIRED;
Inventory *inv = getinv(L, ref); Inventory *inv = getinv(L, ref);
if(!inv) if(!inv)
return NULL; return NULL;
@ -57,7 +56,7 @@ InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
void InvRef::reportInventoryChange(lua_State *L, InvRef *ref) void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
{ {
// Inform other things that the inventory has changed // Inform other things that the inventory has changed
get_server(L)->setInventoryModified(ref->m_loc); STACK_TO_SERVER(L)->setInventoryModified(ref->m_loc);
} }
// Exported functions // Exported functions
@ -72,6 +71,7 @@ int InvRef::gc_object(lua_State *L) {
// is_empty(self, listname) -> true/false // is_empty(self, listname) -> true/false
int InvRef::l_is_empty(lua_State *L) int InvRef::l_is_empty(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
@ -86,6 +86,7 @@ int InvRef::l_is_empty(lua_State *L)
// get_size(self, listname) // get_size(self, listname)
int InvRef::l_get_size(lua_State *L) int InvRef::l_get_size(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
@ -100,6 +101,7 @@ int InvRef::l_get_size(lua_State *L)
// get_width(self, listname) // get_width(self, listname)
int InvRef::l_get_width(lua_State *L) int InvRef::l_get_width(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
@ -114,6 +116,7 @@ int InvRef::l_get_width(lua_State *L)
// set_size(self, listname, size) // set_size(self, listname, size)
int InvRef::l_set_size(lua_State *L) int InvRef::l_set_size(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
int newsize = luaL_checknumber(L, 3); int newsize = luaL_checknumber(L, 3);
@ -136,6 +139,7 @@ int InvRef::l_set_size(lua_State *L)
// set_width(self, listname, size) // set_width(self, listname, size)
int InvRef::l_set_width(lua_State *L) int InvRef::l_set_width(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
int newwidth = luaL_checknumber(L, 3); int newwidth = luaL_checknumber(L, 3);
@ -153,6 +157,7 @@ int InvRef::l_set_width(lua_State *L)
// get_stack(self, listname, i) -> itemstack // get_stack(self, listname, i) -> itemstack
int InvRef::l_get_stack(lua_State *L) int InvRef::l_get_stack(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
int i = luaL_checknumber(L, 3) - 1; int i = luaL_checknumber(L, 3) - 1;
@ -167,10 +172,11 @@ int InvRef::l_get_stack(lua_State *L)
// set_stack(self, listname, i, stack) -> true/false // set_stack(self, listname, i, stack) -> true/false
int InvRef::l_set_stack(lua_State *L) int InvRef::l_set_stack(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
int i = luaL_checknumber(L, 3) - 1; int i = luaL_checknumber(L, 3) - 1;
ItemStack newitem = read_item(L, 4); ItemStack newitem = read_item(L, 4,STACK_TO_SERVER(L));
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
if(list != NULL && i >= 0 && i < (int) list->getSize()){ if(list != NULL && i >= 0 && i < (int) list->getSize()){
list->changeItem(i, newitem); list->changeItem(i, newitem);
@ -185,25 +191,27 @@ int InvRef::l_set_stack(lua_State *L)
// get_list(self, listname) -> list or nil // get_list(self, listname) -> list or nil
int InvRef::l_get_list(lua_State *L) int InvRef::l_get_list(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
Inventory *inv = getinv(L, ref); Inventory *inv = getinv(L, ref);
inventory_get_list_to_lua(inv, listname, L); push_inventory_list(inv, listname, L);
return 1; return 1;
} }
// set_list(self, listname, list) // set_list(self, listname, list)
int InvRef::l_set_list(lua_State *L) int InvRef::l_set_list(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
Inventory *inv = getinv(L, ref); Inventory *inv = getinv(L, ref);
InventoryList *list = inv->getList(listname); InventoryList *list = inv->getList(listname);
if(list) if(list)
inventory_set_list_from_lua(inv, listname, L, 3, read_inventory_list(inv, listname, L, 3,
list->getSize()); STACK_TO_SERVER(L),list->getSize());
else else
inventory_set_list_from_lua(inv, listname, L, 3); read_inventory_list(inv, listname, L, 3,STACK_TO_SERVER(L));
reportInventoryChange(L, ref); reportInventoryChange(L, ref);
return 0; return 0;
} }
@ -212,9 +220,10 @@ int InvRef::l_set_list(lua_State *L)
// Returns the leftover stack // Returns the leftover stack
int InvRef::l_add_item(lua_State *L) int InvRef::l_add_item(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
ItemStack item = read_item(L, 3); ItemStack item = read_item(L, 3,STACK_TO_SERVER(L));
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
if(list){ if(list){
ItemStack leftover = list->addItem(item); ItemStack leftover = list->addItem(item);
@ -231,9 +240,10 @@ int InvRef::l_add_item(lua_State *L)
// Returns true if the item completely fits into the list // Returns true if the item completely fits into the list
int InvRef::l_room_for_item(lua_State *L) int InvRef::l_room_for_item(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
ItemStack item = read_item(L, 3); ItemStack item = read_item(L, 3,STACK_TO_SERVER(L));
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
if(list){ if(list){
lua_pushboolean(L, list->roomForItem(item)); lua_pushboolean(L, list->roomForItem(item));
@ -247,9 +257,10 @@ int InvRef::l_room_for_item(lua_State *L)
// Returns true if the list contains the given count of the given item name // Returns true if the list contains the given count of the given item name
int InvRef::l_contains_item(lua_State *L) int InvRef::l_contains_item(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
ItemStack item = read_item(L, 3); ItemStack item = read_item(L, 3, STACK_TO_SERVER(L));
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
if(list){ if(list){
lua_pushboolean(L, list->containsItem(item)); lua_pushboolean(L, list->containsItem(item));
@ -263,9 +274,10 @@ int InvRef::l_contains_item(lua_State *L)
// Returns the items that were actually removed // Returns the items that were actually removed
int InvRef::l_remove_item(lua_State *L) int InvRef::l_remove_item(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2); const char *listname = luaL_checkstring(L, 2);
ItemStack item = read_item(L, 3); ItemStack item = read_item(L, 3,STACK_TO_SERVER(L));
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
if(list){ if(list){
ItemStack removed = list->removeItem(item); ItemStack removed = list->removeItem(item);
@ -281,6 +293,7 @@ int InvRef::l_remove_item(lua_State *L)
// get_location() -> location (like minetest.get_inventory(location)) // get_location() -> location (like minetest.get_inventory(location))
int InvRef::l_get_location(lua_State *L) int InvRef::l_get_location(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1); InvRef *ref = checkobject(L, 1);
const InventoryLocation &loc = ref->m_loc; const InventoryLocation &loc = ref->m_loc;
switch(loc.type){ switch(loc.type){
@ -293,10 +306,10 @@ int InvRef::l_get_location(lua_State *L)
return 1; return 1;
case InventoryLocation::NODEMETA: case InventoryLocation::NODEMETA:
lua_newtable(L); lua_newtable(L);
lua_pushstring(L, "nodemeta"); lua_pushstring(L, "node");
lua_setfield(L, -2, "type"); lua_setfield(L, -2, "type");
push_v3s16(L, loc.p); push_v3s16(L, loc.p);
lua_setfield(L, -2, "name"); lua_setfield(L, -2, "pos");
return 1; return 1;
case InventoryLocation::DETACHED: case InventoryLocation::DETACHED:
lua_newtable(L); lua_newtable(L);
@ -329,6 +342,7 @@ InvRef::~InvRef()
// Not callable from Lua; all references are created on the C side. // Not callable from Lua; all references are created on the C side.
void InvRef::create(lua_State *L, const InventoryLocation &loc) void InvRef::create(lua_State *L, const InventoryLocation &loc)
{ {
NO_MAP_LOCK_REQUIRED;
InvRef *o = new InvRef(loc); InvRef *o = new InvRef(loc);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o; *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className); luaL_getmetatable(L, className);
@ -336,6 +350,7 @@ void InvRef::create(lua_State *L, const InventoryLocation &loc)
} }
void InvRef::createPlayer(lua_State *L, Player *player) void InvRef::createPlayer(lua_State *L, Player *player)
{ {
NO_MAP_LOCK_REQUIRED;
InventoryLocation loc; InventoryLocation loc;
loc.setPlayer(player->getName()); loc.setPlayer(player->getName());
create(L, loc); create(L, loc);
@ -394,328 +409,48 @@ const luaL_reg InvRef::methods[] = {
{0,0} {0,0}
}; };
void inventory_get_list_to_lua(Inventory *inv, const char *name,
lua_State *L)
{
InventoryList *invlist = inv->getList(name);
if(invlist == NULL){
lua_pushnil(L);
return;
}
std::vector<ItemStack> items;
for(u32 i=0; i<invlist->getSize(); i++)
items.push_back(invlist->getItem(i));
push_items(L, items);
}
void inventory_set_list_from_lua(Inventory *inv, const char *name,
lua_State *L, int tableindex, int forcesize)
{
if(tableindex < 0)
tableindex = lua_gettop(L) + 1 + tableindex;
// If nil, delete list
if(lua_isnil(L, tableindex)){
inv->deleteList(name);
return;
}
// Otherwise set list
std::vector<ItemStack> items = read_items(L, tableindex);
int listsize = (forcesize != -1) ? forcesize : items.size();
InventoryList *invlist = inv->addList(name, listsize);
int index = 0;
for(std::vector<ItemStack>::const_iterator
i = items.begin(); i != items.end(); i++){
if(forcesize != -1 && index == forcesize)
break;
invlist->changeItem(index, *i);
index++;
}
while(forcesize != -1 && index < forcesize){
invlist->deleteItem(index);
index++;
}
}
// get_inventory(location) // get_inventory(location)
int l_get_inventory(lua_State *L) int ModApiInventory::l_get_inventory(lua_State *L)
{ {
InventoryLocation loc; InventoryLocation loc;
std::string type = checkstringfield(L, 1, "type"); std::string type = checkstringfield(L, 1, "type");
if(type == "player"){
std::string name = checkstringfield(L, 1, "name"); if(type == "node"){
loc.setPlayer(name);
} else if(type == "node"){
lua_getfield(L, 1, "pos"); lua_getfield(L, 1, "pos");
v3s16 pos = check_v3s16(L, -1); v3s16 pos = check_v3s16(L, -1);
loc.setNodeMeta(pos); loc.setNodeMeta(pos);
} else if(type == "detached"){
std::string name = checkstringfield(L, 1, "name"); if(getServer(L)->getInventory(loc) != NULL)
loc.setDetached(name); InvRef::create(L, loc);
else
lua_pushnil(L);
return 1;
} else {
NO_MAP_LOCK_REQUIRED;
if(type == "player"){
std::string name = checkstringfield(L, 1, "name");
loc.setPlayer(name);
} else if(type == "detached"){
std::string name = checkstringfield(L, 1, "name");
loc.setDetached(name);
}
if(getServer(L)->getInventory(loc) != NULL)
InvRef::create(L, loc);
else
lua_pushnil(L);
return 1;
// END NO_MAP_LOCK_REQUIRED;
} }
if(get_server(L)->getInventory(loc) != NULL)
InvRef::create(L, loc);
else
lua_pushnil(L);
return 1;
}
/*
Detached inventory callbacks
*/
// Retrieves minetest.detached_inventories[name][callbackname]
// If that is nil or on error, return false and stack is unchanged
// If that is a function, returns true and pushes the
// function onto the stack
static bool get_detached_inventory_callback(lua_State *L,
const std::string &name, const char *callbackname)
{
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "detached_inventories");
lua_remove(L, -2);
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, name.c_str());
lua_remove(L, -2);
// Should be a table
if(lua_type(L, -1) != LUA_TTABLE)
{
errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
lua_pop(L, 1);
return false;
}
lua_getfield(L, -1, callbackname);
lua_remove(L, -2);
// Should be a function or nil
if(lua_type(L, -1) == LUA_TFUNCTION)
{
return true;
}
else if(lua_isnil(L, -1))
{
lua_pop(L, 1);
return false;
}
else
{
errorstream<<"Detached inventory \""<<name<<"\" callback \""
<<callbackname<<"\" is not a function"<<std::endl;
lua_pop(L, 1);
return false;
}
}
// Return number of accepted items to be moved
int scriptapi_detached_inventory_allow_move(lua_State *L,
const std::string &name,
const std::string &from_list, int from_index,
const std::string &to_list, int to_index,
int count, ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
// Push callback function on stack
if(!get_detached_inventory_callback(L, name, "allow_move"))
return count;
// function(inv, from_list, from_index, to_list, to_index, count, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// from_list
lua_pushstring(L, from_list.c_str());
// from_index
lua_pushinteger(L, from_index + 1);
// to_list
lua_pushstring(L, to_list.c_str());
// to_index
lua_pushinteger(L, to_index + 1);
// count
lua_pushinteger(L, count);
// player
objectref_get_or_create(L, player);
if(lua_pcall(L, 7, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_move should return a number");
return luaL_checkinteger(L, -1);
}
// Return number of accepted items to be put
int scriptapi_detached_inventory_allow_put(lua_State *L,
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
// Push callback function on stack
if(!get_detached_inventory_callback(L, name, "allow_put"))
return stack.count; // All will be accepted
// Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectref_get_or_create(L, player);
if(lua_pcall(L, 5, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_put should return a number");
return luaL_checkinteger(L, -1);
}
// Return number of accepted items to be taken
int scriptapi_detached_inventory_allow_take(lua_State *L,
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
// Push callback function on stack
if(!get_detached_inventory_callback(L, name, "allow_take"))
return stack.count; // All will be accepted
// Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectref_get_or_create(L, player);
if(lua_pcall(L, 5, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_take should return a number");
return luaL_checkinteger(L, -1);
}
// Report moved items
void scriptapi_detached_inventory_on_move(lua_State *L,
const std::string &name,
const std::string &from_list, int from_index,
const std::string &to_list, int to_index,
int count, ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
// Push callback function on stack
if(!get_detached_inventory_callback(L, name, "on_move"))
return;
// function(inv, from_list, from_index, to_list, to_index, count, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// from_list
lua_pushstring(L, from_list.c_str());
// from_index
lua_pushinteger(L, from_index + 1);
// to_list
lua_pushstring(L, to_list.c_str());
// to_index
lua_pushinteger(L, to_index + 1);
// count
lua_pushinteger(L, count);
// player
objectref_get_or_create(L, player);
if(lua_pcall(L, 7, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
// Report put items
void scriptapi_detached_inventory_on_put(lua_State *L,
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
// Push callback function on stack
if(!get_detached_inventory_callback(L, name, "on_put"))
return;
// Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectref_get_or_create(L, player);
if(lua_pcall(L, 5, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
// Report taken items
void scriptapi_detached_inventory_on_take(lua_State *L,
const std::string &name,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
// Push callback function on stack
if(!get_detached_inventory_callback(L, name, "on_take"))
return;
// Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
// listname
lua_pushstring(L, listname.c_str());
// index
lua_pushinteger(L, index + 1);
// stack
LuaItemStack::create(L, stack);
// player
objectref_get_or_create(L, player);
if(lua_pcall(L, 5, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
} }
// create_detached_inventory_raw(name) // create_detached_inventory_raw(name)
int l_create_detached_inventory_raw(lua_State *L) int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED;
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
if(get_server(L)->createDetachedInventory(name) != NULL){ if(getServer(L)->createDetachedInventory(name) != NULL){
InventoryLocation loc; InventoryLocation loc;
loc.setDetached(name); loc.setDetached(name);
InvRef::create(L, loc); InvRef::create(L, loc);
@ -724,3 +459,21 @@ int l_create_detached_inventory_raw(lua_State *L)
} }
return 1; return 1;
} }
bool ModApiInventory::Initialize(lua_State *L, int top) {
bool retval = true;
retval &= API_FCT(create_detached_inventory_raw);
retval &= API_FCT(get_inventory);
InvRef::Register(L);
return retval;
}
ModApiInventory::ModApiInventory()
: ModApiBase() {
}
ModApiInventory modapiinventory_prototype;

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