Browse Source

Bug fixes and improvements related to Lua and CSM

This Final Minetest commit includes ports of  the following Troll-
test commits plus  additional changes.  The changes are related to
MT Lua C++ to interface code,  the MT Lua API, and MT CSM (Client-
Side Modding).

Desc:   Fix "add_entity" returning unusable reference
Commit: f6f6dd140f
From:   sfan5 <sfan5@live.de>
Date:   Sun, 26 Apr 2020 20:29:16 +0200

Desc:   [CSM] Fix and improve "minetest.get_language()"
Commit: c44318a253
From:   sfan5 <sfan5@live.de>
Date:   Sat Nov 9 16:15:05 2019 +0100

Desc:   [CSM] Expose more env functions
Commit: b57dc70769
From:   sfan5 <sfan5@live.de>
Date:   Sat, 9 Nov 2019 00:22:42 +0100

Desc:   Introduce "get_modpath()" for CSM
Commit: b1f2a69382
From:   sfan5 <sfan5@live.de>
Date:   Fri Nov 8 20:18:41 2019 +0100

Desc:   Modernize Lua read part 2 of 2 (#7410)
Commit: eef62c82a2
From:   Loic Blot <nerzhul@users.noreply.github.com>
Date:   Sat, 30 Jun 2018 17:11:38 +0200

Desc:   Modernize Lua read part 1 of 2 (#7394)
Commit: 180e551c56
From:   Loic Blot <nerzhul@users.noreply.github.com>
Date:   Mon, 4 Jun 2018 22:38:07 +0200

Related technical notes:

1. To  enable CSM,  users  need to  add  the following  setting to
"minetest.conf" on the client side:

enable_client_modding = false

2. Additionally,  to load the sample CSM mod provided,  users need
to  edit  "clientmods/mods.conf" on the client side and set "load_
mod_previw" to true:

load_mod_preview = true
master
Robert Kiraly 3 months ago
parent
commit
a0d8004edc
49 changed files with 586 additions and 282 deletions
  1. +1
    -0
      build/android/jni/Android.mk
  2. +16
    -0
      builtin/client/death_formspec.lua
  3. +1
    -0
      clientmods/mods.conf
  4. +2
    -2
      clientmods/preview/example.lua
  5. +1
    -1
      clientmods/preview/examples/first.lua
  6. +162
    -97
      clientmods/preview/init.lua
  7. +84
    -5
      doc/client_lua_api.txt
  8. +5
    -0
      src/client.cpp
  9. +1
    -0
      src/client.h
  10. +15
    -6
      src/guiFormSpecMenu.cpp
  11. +1
    -0
      src/script/common/CMakeLists.txt
  12. +1
    -2
      src/script/common/c_internal.h
  13. +73
    -0
      src/script/common/helper.cpp
  14. +54
    -0
      src/script/common/helper.h
  15. +4
    -4
      src/script/cpp_api/s_base.cpp
  16. +3
    -1
      src/script/cpp_api/s_base.h
  17. +5
    -8
      src/script/cpp_api/s_client.cpp
  18. +2
    -2
      src/script/cpp_api/s_entity.cpp
  19. +6
    -6
      src/script/cpp_api/s_env.cpp
  20. +0
    -3
      src/script/cpp_api/s_item.h
  21. +2
    -2
      src/script/cpp_api/s_node.cpp
  22. +3
    -4
      src/script/cpp_api/s_player.cpp
  23. +3
    -3
      src/script/cpp_api/s_security.cpp
  24. +2
    -3
      src/script/cpp_api/s_server.cpp
  25. +2
    -2
      src/script/lua_api/l_areastore.cpp
  26. +2
    -7
      src/script/lua_api/l_base.cpp
  27. +2
    -3
      src/script/lua_api/l_base.h
  28. +26
    -15
      src/script/lua_api/l_client.cpp
  29. +3
    -0
      src/script/lua_api/l_client.h
  30. +4
    -4
      src/script/lua_api/l_craft.cpp
  31. +19
    -15
      src/script/lua_api/l_env.cpp
  32. +2
    -2
      src/script/lua_api/l_http.cpp
  33. +2
    -2
      src/script/lua_api/l_inventory.cpp
  34. +1
    -1
      src/script/lua_api/l_item.cpp
  35. +7
    -6
      src/script/lua_api/l_mainmenu.cpp
  36. +17
    -22
      src/script/lua_api/l_mapgen.cpp
  37. +2
    -2
      src/script/lua_api/l_metadata.cpp
  38. +2
    -2
      src/script/lua_api/l_nodemeta.cpp
  39. +3
    -3
      src/script/lua_api/l_nodetimer.cpp
  40. +2
    -2
      src/script/lua_api/l_noise.cpp
  41. +18
    -17
      src/script/lua_api/l_object.cpp
  42. +2
    -2
      src/script/lua_api/l_particles.cpp
  43. +9
    -13
      src/script/lua_api/l_server.cpp
  44. +2
    -2
      src/script/lua_api/l_settings.cpp
  45. +1
    -1
      src/script/lua_api/l_sound.cpp
  46. +1
    -1
      src/script/lua_api/l_storage.cpp
  47. +7
    -8
      src/script/lua_api/l_util.cpp
  48. +2
    -1
      src/script/lua_api/l_vmanip.cpp
  49. +1
    -0
      src/script/scripting_client.cpp

+ 1
- 0
build/android/jni/Android.mk View File

@@ -294,6 +294,7 @@ LOCAL_SRC_FILES += \
jni/src/script/common/c_converter.cpp \
jni/src/script/common/c_internal.cpp \
jni/src/script/common/c_types.cpp \
jni/src/script/common/helper.cpp \
jni/src/script/cpp_api/s_async.cpp \
jni/src/script/cpp_api/s_base.cpp \
jni/src/script/cpp_api/s_client.cpp \


+ 16
- 0
builtin/client/death_formspec.lua View File

@@ -0,0 +1,16 @@
-- CSM death formspec. Only used when clientside modding is enabled, otherwise
-- handled by the engine.

core.register_on_death(function()
core.display_chat_message("You died.")
local formspec = "size[11,5.5]bgcolor[#320000b4;true]" ..
"label[4.85,1.35;" .. fgettext("You died") ..
"]button_exit[4,3;3,0.5;btn_respawn;".. fgettext("Respawn") .."]"
core.show_formspec("bultin:death", formspec)
end)

core.register_on_formspec_input(function(formname, fields)
if formname == "bultin:death" then
core.send_respawn()
end
end)

+ 1
- 0
clientmods/mods.conf View File

@@ -0,0 +1 @@
load_mod_preview = false

+ 2
- 2
clientmods/preview/example.lua View File

@@ -1,2 +1,2 @@
print("Loaded example file!, loading more examples")
dofile("preview:examples/first.lua")
dofile (core.get_modpath (core.get_current_modname())
.. "examples/first.lua")

+ 1
- 1
clientmods/preview/examples/first.lua View File

@@ -1 +1 @@
print("loaded first.lua example file")
print ("Loaded first.lua example file")

+ 162
- 97
clientmods/preview/init.lua View File

@@ -1,173 +1,231 @@
local modname = core.get_current_modname() or "??"
-- ===================================================================

local modname = assert (core.get_current_modname())
local modstorage = core.get_mod_storage()
local mod_channel

dofile("preview:example.lua")
core.register_on_shutdown(function()
print("[PREVIEW] shutdown client")
end)
local id = nil
-- ===================================================================

local server_info = core.get_server_info()
print("Server version: " .. server_info.protocol_version)
print("Server ip: " .. server_info.ip)
print("Server address: " .. server_info.address)
print("Server port: " .. server_info.port)
dofile (core.get_modpath (modname) .. "example.lua")

core.register_on_inventory_open(function(inventory)
print("INVENTORY OPEN")
print(dump(inventory))
return false
end)
-- ===================================================================

core.register_on_placenode(function(pointed_thing, node)
print("The local player place a node!")
print("pointed_thing :" .. dump(pointed_thing))
print("node placed :" .. dump(node))
return false
core.register_on_shutdown (function()
print ("[Preview] shutdown client")
end)

core.register_on_item_use(function(itemstack, pointed_thing)
print("The local player used an item!")
print("pointed_thing :" .. dump(pointed_thing))
print("item = " .. itemstack:get_name())
return false
end)
-- ===================================================================

do
local server_info = core.get_server_info()
print ("Server version: " .. server_info.protocol_version)
print ("Server ip: " .. server_info.ip)
print ("Server address: " .. server_info.address)
print ("Server port: " .. server_info.port)

local l1, l2 = core.get_language()
print ("Configured language: " .. l1 .. " / " .. l2)
end

core.register_on_receiving_chat_message(function(message)
print("[PREVIEW] Received message " .. message)
-- ===================================================================

if false then
core.register_on_inventory_open (function (inventory)
print ("Inventory open")
print (dump (inventory))
return false
end)
end

-- ===================================================================

core.register_on_placenode (function (pointed_thing, node)
print ("The local player placed a node")
print ("pointed_thing :" .. dump (pointed_thing ))
print ("node placed :" .. dump (node ))
return false
end)

core.register_on_sending_chat_message(function(message)
print("[PREVIEW] Sending message " .. message)
-- ===================================================================

core.register_on_item_use (function (itemstack, pointed_thing)
print ("The local player used an item")
print ("pointed_thing :" .. dump (pointed_thing))
print ("item = " .. itemstack:get_name())
return false
end)

core.register_on_hp_modification(function(hp)
print("[PREVIEW] HP modified " .. hp)
end)
-- ===================================================================

core.register_on_damage_taken(function(hp)
print("[PREVIEW] Damage taken " .. hp)
end)
-- This setting should usually be false as it enables debug code that
-- is high-load and/or verbose.

core.register_globalstep(function(dtime)
-- print("[PREVIEW] globalstep " .. dtime)
end)
local high_debug = false

core.register_chatcommand("dump", {
func = function(param)
return true, dump(_G)
end,
})
if high_debug then
core.register_on_receiving_chat_message (function (message)
print ("[Preview] Received message " .. message)
return false
end)

core.register_on_sending_chat_message (function (message)
print ("[Preview] Sending message " .. message)
return false
end)

core.register_chatcommand("colorize_test", {
func = function(param)
return true, core.colorize("red", param)
core.register_on_hp_modification (function (hp)
print ("[Preview] HP modified " .. hp)
end)

core.register_on_damage_taken (function (hp)
print ("[Preview] Damage taken " .. hp)
end)

core.register_globalstep (function (dtime)
-- print ("[Preview] globalstep " .. dtime)
end)

core.register_chatcommand ("dump", {
func = function (param)
return true, dump(_G)
end,
})
end

-- ===================================================================

core.register_chatcommand ("colorize_test", {
func = function (param)
return true, core.colorize ("red", param)
end,
})

core.register_chatcommand("test_node", {
func = function(param)
core.display_chat_message(dump(core.get_node({x=0, y=0, z=0})))
core.display_chat_message(dump(core.get_node_or_nil({x=0, y=0, z=0})))
-- ===================================================================

core.register_chatcommand ("test_node", {
func = function (param)
core.display_chat_message (dump (core.get_node ({
x=0, y=0, z=0 })))
core.display_chat_message (dump (core.get_node_or_nil ({
x=0, y=0, z=0 })))
end,
})

-- ===================================================================

local function preview_minimap()
local minimap = core.ui.minimap
if not minimap then
print("[PREVIEW] Minimap is disabled. Skipping.")
print ("[Preview] Minimap is disabled. Skipping.")
return
end

minimap:set_mode(4)
minimap:show()
minimap:set_pos({x=5, y=50, z=5})
minimap:set_shape(math.random(0, 1))

print("[PREVIEW] Minimap: mode => " .. dump(minimap:get_mode()) ..
print ("[Preview] Minimap: mode => " .. dump(minimap:get_mode()) ..
" position => " .. dump(minimap:get_pos()) ..
" angle => " .. dump(minimap:get_angle()))
end

-- ===================================================================

core.after(2, function()
print("[PREVIEW] loaded " .. modname .. " mod")
modstorage:set_string("current_mod", modname)
print(modstorage:get_string("current_mod"))
print ("[Preview] loaded " .. modname .. " mod")
modstorage:set_string ("current_mod", modname)
print (modstorage:get_string ("current_mod"))
preview_minimap()
end)

-- ===================================================================

core.after(5, function()
if core.ui.minimap then
if core.ui.minimap then
core.ui.minimap:show()
end

print("[PREVIEW] Day count: " .. core.get_day_count() ..
print ("[Preview] Day count: " ..
core.get_day_count() ..
" time of day " .. core.get_timeofday())

print("[PREVIEW] Node level: " .. core.get_node_level({x=0, y=20, z=0}) ..
" max level " .. core.get_node_max_level({x=0, y=20, z=0}))
print ("[Preview] Node level: " ..
core.get_node_level({x=0, y=20, z=0}) ..
" max level " .. core.get_node_max_level ({x=0, y=20, z=0}))

print("[PREVIEW] Find node near: " .. dump(core.find_node_near({x=0, y=20, z=0}, 10,
print ("[Preview] Find node near: " ..
dump (core.find_node_near ({x=0, y=20, z=0}, 10,
{"group:tree", "default:dirt", "default:stone"})))
end)

core.register_on_dignode(function(pos, node)
print("The local player dug a node!")
print("pos:" .. dump(pos))
print("node:" .. dump(node))
-- ===================================================================

core.register_on_dignode (function (pos, node)
print ("The local player dug a node")
print ("pos:" .. dump (pos ))
print ("node:" .. dump (node ))
return false
end)

core.register_on_punchnode(function(pos, node)
print("The local player punched a node!")
-- ===================================================================

core.register_on_punchnode (function (pos, node)
print ("The local player punched a node")
local itemstack = core.get_wielded_item()
--[[

--[[
-- getters
print(dump(itemstack:is_empty()))
print(dump(itemstack:get_name()))
print(dump(itemstack:get_count()))
print(dump(itemstack:get_wear()))
print(dump(itemstack:get_meta()))
print(dump(itemstack:get_metadata()
print(dump(itemstack:is_known()))
--print(dump(itemstack:get_definition()))
print(dump(itemstack:get_tool_capabilities()))
print(dump(itemstack:to_string()))
print(dump(itemstack:to_table()))
print (dump(itemstack:is_empty()))
print (dump(itemstack:get_name()))
print (dump(itemstack:get_count()))
print (dump(itemstack:get_wear()))
print (dump(itemstack:get_meta()))
print (dump(itemstack:get_metadata()
print (dump(itemstack:is_known()))

--print (dump(itemstack:get_definition()))
print (dump(itemstack:get_tool_capabilities()))
print (dump(itemstack:to_string()))
print (dump(itemstack:to_table()))

-- setters
print(dump(itemstack:set_name("default:dirt")))
print(dump(itemstack:set_count("95")))
print(dump(itemstack:set_wear(934)))
print(dump(itemstack:get_meta()))
print(dump(itemstack:get_metadata()))
--]]
print(dump(itemstack:to_table()))
print("pos:" .. dump(pos))
print("node:" .. dump(node))
print (dump(itemstack:set_name("default:dirt")))
print (dump(itemstack:set_count("95")))
print (dump(itemstack:set_wear(934)))
print (dump(itemstack:get_meta()))
print (dump(itemstack:get_metadata()))
--]]

print (dump (itemstack:to_table()))
print ("pos:" .. dump (pos ))
print ("node:" .. dump (node ))
return false
end)

core.register_chatcommand("privs", {
func = function(param)
return true, core.privs_to_string(minetest.get_privilege_list())
-- ===================================================================

core.register_chatcommand ("privs", {
func = function (param)
return true, core.privs_to_string (minetest.get_privilege_list())
end,
})

core.register_chatcommand("text", {
func = function(param)
return core.localplayer:hud_change(id, "text", param)
-- ===================================================================

local id = nil

core.register_chatcommand ("text", {
func = function (param)
return core.localplayer:hud_change (id, "text", param)
end,
})

core.register_on_mods_loaded(function()
core.log("Yeah preview mod is loaded with other CSM mods.")
-- ===================================================================

core.register_on_mods_loaded (function()
core.log ("CSM preview mod is loaded")
end)

-- ===================================================================
-- End of file.

+ 84
- 5
doc/client_lua_api.txt View File

@@ -20,7 +20,7 @@ scripting in run-time loaded mods.
A mod is a self-contained bunch of scripts, textures and other things
that are loaded by and interface with Minetest.

Transferirng client-sided mods form the server to the client is planned, but not implemented yet.
Transferring client-sided mods form the server to the client is planned, but not implemented yet.

If you see a deficiency in the API, feel free to attempt to add the
functionality in the engine and API. You can send such improvements as
@@ -625,8 +625,19 @@ Minetest namespace reference

### Utilities

* `minetest.get_current_modname()`: returns the currently loading mod's name, when we are loading a mod
* `minetest.get_language()`: returns the currently set gettext language.
* `minetest.get_current_modname()`: returns the currently loading
mod's name, when we are loading a mod

* `minetest.get_modpath(modname)`: returns virtual path of given mod
including the trailing separator. This is useful to load additional
Lua files contained in your mod:
e.g. `dofile(minetest.get_modpath(minetest.get_current_modname()) .. "stuff.lua")`

* `minetest.get_language()`: returns two strings
* the current gettext locale
* the current language code (the same as used for client-side
translations)

* `minetest.get_version()`: returns a table containing components of the
engine version. Components:
* `project`: Name of the project, eg, "Minetest"
@@ -713,15 +724,57 @@ Call these functions only at load time!
* Returns the time of day: `0` for midnight, `0.5` for midday

### Map
* `minetest.get_node_or_nil(pos)`
* `minetest.get_node_or_nil (pos)`
* Returns the node at the given position as table in the format
`{name="node_name", param1=0, param2=0}`, returns `nil`
for unloaded areas or flavour limited areas.
* `minetest.find_node_near(pos, radius, nodenames, [search_center])`: returns pos or `nil`

* `minetest.get_node_light (pos, timeofday)`
* Gets the light value at the given position. Note that the light value
"inside" the node at the given position is returned, so you usually want
to get the light value of a neighbor.
* `pos`: The position where to measure the light.
* `timeofday`: `nil` for current time, `0` for night, `0.5` for day
* Returns a number between `0` and `15` or `nil`

* `minetest.find_node_near (pos, radius, nodenames, [search_center])`: returns pos or `nil`
* `radius`: using a maximum metric
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
* `search_center` is an optional boolean (default: `false`)
If true `pos` is also checked for the nodes

* `minetest.find_nodes_in_area (pos1, pos2, nodenames)`: returns a list of
positions.
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
* First return value: Table with all node positions
* Second return value: Table with the count of each node with the node name
as index.
* Area volume is limited to 4,096,000 nodes

* `minetest.find_nodes_in_area_under_air (pos1, pos2, nodenames)`: returns a
list of positions.
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
* Return value: Table with all node positions with a node air above
* Area volume is limited to 4,096,000 nodes

* `minetest.line_of_sight (pos1, pos2)`: returns `boolean, pos`
* Checks if there is anything other than air between pos1 and pos2.
* Returns false if something is blocking the sight.
* Returns the position of the blocking node when `false`
* `pos1`: First position
* `pos2`: Second position

* `minetest.raycast (pos1, pos2, objects, liquids)`: returns `Raycast`
* Creates a `Raycast` object.
* `pos1`: start of the ray
* `pos2`: end of the ray
* `objects`: if false, only nodes will be returned. Default is `true`.
* `liquids`: if false, liquid nodes won't be returned. Default is `false`.

* `minetest.find_nodes_with_meta(pos1, pos2)`
* Get a table of positions of nodes that have metadata within a region
{pos1, pos2}.

* `minetest.get_meta(pos)`
* Get a `NodeMetaRef` at that position
* `minetest.get_node_level(pos)`
@@ -1003,6 +1056,32 @@ Can be obtained via `minetest.get_meta(pos)`.
* `fields`: key-value storage
* `inventory`: `{list1 = {}, ...}}`

### `Raycast`

A raycast on the map. It works with selection boxes.
Can be used as an iterator in a for loop as:

local ray = Raycast(...)
for pointed_thing in ray do
...
end

The map is loaded as the ray advances. If the map is modified after the
`Raycast` is created, the changes may or may not have an effect on the object.

It can be created via `Raycast(pos1, pos2, objects, liquids)` or
`minetest.raycast(pos1, pos2, objects, liquids)` where:

* `pos1`: start of the ray
* `pos2`: end of the ray
* `objects`: if false, only nodes will be returned. Default is true.
* `liquids`: if false, liquid nodes won't be returned. Default is false.

#### Methods

* `next()`: returns a `pointed_thing` with exact pointing location
* Returns the next thing pointed by the ray or nil.

-----------------
### Definitions
* `minetest.get_node_def(nodename)`


+ 5
- 0
src/client.cpp View File

@@ -1355,6 +1355,11 @@ MapNode Client::getNode(v3s16 p, bool *is_valid_position)
return m_env.getMap().getNodeNoEx(p, is_valid_position);
}

v3s16 Client::CSMClampPos(v3s16 pos)
{
return pos;
}

void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
{
//TimeTaker timer1("Client::addNode()");


+ 1
- 0
src/client.h View File

@@ -380,6 +380,7 @@ public:
* @return
*/
MapNode getNode(v3s16 p, bool *is_valid_position);
v3s16 CSMClampPos (v3s16 pos);
void addNode(v3s16 p, MapNode n, bool remove_metadata = true);

void setPlayerControl(PlayerControl &control);


+ 15
- 6
src/guiFormSpecMenu.cpp View File

@@ -2289,19 +2289,28 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase,
video::IVideoDriver* driver = Environment->getVideoDriver();

Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
if(!inv){

if (!inv)
{
#ifdef NOTDEF // Prevent message flood
warningstream<<"GUIFormSpecMenu::drawList(): "
<<"The inventory location "
<<"\""<<s.inventoryloc.dump()<<"\" doesn't exist"
<<std::endl;
#endif
return;
}
InventoryList *ilist = inv->getList(s.listname);
if(!ilist){

InventoryList *ilist = inv->getList (s.listname);

if (!ilist)
{
#ifdef NOTDEF // Prevent message flood
warningstream<<"GUIFormSpecMenu::drawList(): "
<<"The inventory list \""<<s.listname<<"\" @ \""
<<s.inventoryloc.dump()<<"\" doesn't exist"
<<std::endl;
#endif
return;
}

@@ -3693,14 +3702,14 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
m_invmgr->inventoryAction(a);
} else if (craft_amount > 0) {
assert(s.isValid());
// if there are no items selected or the selected item
// belongs to craftresult list, proceed with crafting
if (m_selected_item == NULL ||
!m_selected_item->isValid() || m_selected_item->listname == "craftresult") {
m_selected_content_guess = ItemStack(); // Clear
assert(inv_s);

// Send IACTION_CRAFT


+ 1
- 0
src/script/common/CMakeLists.txt View File

@@ -3,6 +3,7 @@ set(common_SCRIPT_COMMON_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/c_converter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/c_types.cpp
${CMAKE_CURRENT_SOURCE_DIR}/c_internal.cpp
${CMAKE_CURRENT_SOURCE_DIR}/helper.cpp
PARENT_SCOPE)

set(client_SCRIPT_COMMON_SRCS


+ 1
- 2
src/script/common/c_internal.h View File

@@ -96,11 +96,10 @@ enum RunCallbacksMode
// 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.
// are converted by readParam<bool> to true or false, respectively.
};

std::string script_get_backtrace(lua_State *L);
int script_error_handler(lua_State *L);
int script_exception_wrapper(lua_State *L, lua_CFunction f);
void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn);
void script_run_callbacks_f(lua_State *L, int nargs,


+ 73
- 0
src/script/common/helper.cpp View File

@@ -0,0 +1,73 @@
/*
Minetest
Copyright (C) 2018 nerzhul, Loic Blot <loic.blot@unix-experience.fr>

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 "helper.h"
#include <cmath>
#include <sstream>
#include "c_types.h"

bool LuaHelper::isNaN(lua_State *L, int idx)
{
return lua_type(L, idx) == LUA_TNUMBER && std::isnan(lua_tonumber(L, idx));
}

/*
* Read template functions
*/
template <> bool LuaHelper::readParam(lua_State *L, int index)
{
return lua_toboolean(L, index) != 0;
}

template <> bool LuaHelper::readParam(lua_State *L, int index, const bool &default_value)
{
if (lua_isnil(L, index))
return default_value;

return lua_toboolean(L, index) != 0;
}

template <> float LuaHelper::readParam(lua_State *L, int index)
{
if (isNaN(L, index))
throw LuaError("NaN value is not allowed.");

return (float)luaL_checknumber(L, index);
}

template <> std::string LuaHelper::readParam(lua_State *L, int index)
{
std::string result;
const char *str = luaL_checkstring(L, index);
result.append(str);
return result;
}

template <>
std::string LuaHelper::readParam(
lua_State *L, int index, const std::string &default_value)
{
std::string result;
const char *str = lua_tostring(L, index);
if (str)
result.append(str);
else
result = default_value;
return result;
}

+ 54
- 0
src/script/common/helper.h View File

@@ -0,0 +1,54 @@
/*
Minetest
Copyright (C) 2018 nerzhul, Loic Blot <loic.blot@unix-experience.fr>

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.
*/

#pragma once

extern "C" {
#include <lua.h>
#include <lauxlib.h>
}

class LuaHelper
{
protected:
static bool isNaN(lua_State *L, int idx);

/**
* Read a value using a template type T from Lua State L and index
*
*
* @tparam T type to read from Lua
* @param L Lua state
* @param index Lua Index to read
* @return read value from Lua
*/
template <typename T> static T readParam(lua_State *L, int index);

/**
* Read a value using a template type T from Lua State L and index
*
* @tparam T type to read from Lua
* @param L Lua state
* @param index Lua Index to read
* @param default_value default value to apply if nil
* @return read value from Lua or default value if nil
*/
template <typename T>
static T readParam(lua_State *L, int index, const T &default_value);
};

+ 4
- 4
src/script/cpp_api/s_base.cpp View File

@@ -123,7 +123,7 @@ int ScriptApiBase::luaPanic(lua_State *L)
{
std::ostringstream oss;
oss << "LUA PANIC: unprotected error in call to Lua API ("
<< lua_tostring(L, -1) << ")";
<< readParam<std::string>(L, -1) << ")";
FATAL_ERROR(oss.str().c_str());
// NOTREACHED
return 0;
@@ -153,7 +153,7 @@ void ScriptApiBase::loadScript(const std::string &script_path)
}
ok = ok && !lua_pcall(L, 0, 0, error_handler);
if (!ok) {
std::string error_msg = lua_tostring(L, -1);
std::string error_msg = readParam<std::string>(L, -1);
lua_pop(L, 2); // Pop error message and error handler
throw ModError("Failed to load and run script from " +
script_path + ":\n" + error_msg);
@@ -255,10 +255,10 @@ void ScriptApiBase::stackDump(std::ostream &o)
int t = lua_type(m_luastack, i);
switch (t) {
case LUA_TSTRING: /* strings */
o << "\"" << lua_tostring(m_luastack, i) << "\"";
o << "\"" << readParam<std::string>(m_luastack, i) << "\"";
break;
case LUA_TBOOLEAN: /* booleans */
o << (lua_toboolean(m_luastack, i) ? "true" : "false");
o << (readParam<bool>(m_luastack, i) ? "true" : "false");
break;
case LUA_TNUMBER: /* numbers */ {
char buf[10];


+ 3
- 1
src/script/cpp_api/s_base.h View File

@@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include <thread>
#include <mutex>

#include "common/helper.h"
#include "util/basic_macros.h"

extern "C" {
@@ -70,7 +72,7 @@ class GUIEngine;
class ServerActiveObject;
class PlayerHPChangeReason;

class ScriptApiBase {
class ScriptApiBase : protected LuaHelper {
public:
ScriptApiBase();
virtual ~ScriptApiBase();


+ 5
- 8
src/script/cpp_api/s_client.cpp View File

@@ -57,8 +57,7 @@ bool ScriptApiClient::on_sending_message(const std::string &message)
// Call callbacks
lua_pushstring(L, message.c_str());
runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
bool ate = lua_toboolean(L, -1);
return ate;
return readParam<bool>(L, -1);
}

bool ScriptApiClient::on_receiving_message(const std::string &message)
@@ -71,8 +70,7 @@ bool ScriptApiClient::on_receiving_message(const std::string &message)
// Call callbacks
lua_pushstring(L, message.c_str());
runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
bool ate = lua_toboolean(L, -1);
return ate;
return readParam<bool>(L, -1);
}

void ScriptApiClient::on_damage_taken(int32_t damage_amount)
@@ -186,8 +184,7 @@ bool ScriptApiClient::on_punchnode(v3s16 p, MapNode node)

// Call functions
runCallbacks(2, RUN_CALLBACKS_MODE_OR);
bool blocked = lua_toboolean(L, -1);
return blocked;
return readParam<bool>(L, -1);
}

bool ScriptApiClient::on_placenode(const PointedThing &pointed, const ItemDefinition &item)
@@ -204,7 +201,7 @@ bool ScriptApiClient::on_placenode(const PointedThing &pointed, const ItemDefini

// Call functions
runCallbacks(2, RUN_CALLBACKS_MODE_OR);
return lua_toboolean(L, -1);
return readParam<bool>(L, -1);
}

bool ScriptApiClient::on_item_use(const ItemStack &item, const PointedThing &pointed)
@@ -221,7 +218,7 @@ bool ScriptApiClient::on_item_use(const ItemStack &item, const PointedThing &poi

// Call functions
runCallbacks(2, RUN_CALLBACKS_MODE_OR);
return lua_toboolean(L, -1);
return readParam<bool>(L, -1);
}

void ScriptApiClient::setEnv(ClientEnvironment *env)


+ 2
- 2
src/script/cpp_api/s_entity.cpp View File

@@ -257,7 +257,7 @@ bool ScriptApiEntity::luaentity_Punch(u16 id,
setOriginFromTable(object);
PCALL_RES(lua_pcall(L, 6, 1, error_handler));

bool retval = lua_toboolean(L, -1);
bool retval = readParam<bool>(L, -1);
lua_pop(L, 2); // Pop object and error handler
return retval;
}
@@ -285,7 +285,7 @@ bool ScriptApiEntity::luaentity_on_death(u16 id, ServerActiveObject *killer)
setOriginFromTable(object);
PCALL_RES(lua_pcall(L, 2, 1, error_handler));

bool retval = lua_toboolean(L, -1);
bool retval = readParam<bool>(L, -1);
lua_pop(L, 2); // Pop object and error handler
return retval;
}


+ 6
- 6
src/script/cpp_api/s_env.cpp View File

@@ -116,12 +116,12 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
while (lua_next(L, table)) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
trigger_contents.insert(lua_tostring(L, -1));
trigger_contents.insert(readParam<std::string>(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));
trigger_contents.insert(readParam<std::string>(L, -1));
}
lua_pop(L, 1);

@@ -133,12 +133,12 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
while (lua_next(L, table)) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
required_neighbors.insert(lua_tostring(L, -1));
required_neighbors.insert(readParam<std::string>(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));
required_neighbors.insert(readParam<std::string>(L, -1));
}
lua_pop(L, 1);

@@ -185,12 +185,12 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
while (lua_next(L, table)) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
trigger_contents.insert(lua_tostring(L, -1));
trigger_contents.insert(readParam<std::string>(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));
trigger_contents.insert(readParam<std::string>(L, -1));
}
lua_pop(L, 1);



+ 0
- 3
src/script/cpp_api/s_item.h View File

@@ -56,8 +56,5 @@ protected:

bool getItemCallback(const char *name, const char *callbackname, const v3s16 *p = nullptr);
void pushPointedThing(const PointedThing& pointed);

};


#endif /* S_ITEM_H_ */

+ 2
- 2
src/script/cpp_api/s_node.cpp View File

@@ -198,7 +198,7 @@ bool ScriptApiNode::node_on_flood(v3s16 p, MapNode node, MapNode newnode)
pushnode(L, newnode, ndef);
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
lua_remove(L, error_handler);
return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true;
return readParam<bool>(L, -1, false);
}

void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
@@ -237,7 +237,7 @@ bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime)
lua_pushnumber(L,dtime);
PCALL_RES(lua_pcall(L, 2, 1, error_handler));
lua_remove(L, error_handler);
return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true;
return readParam<bool>(L, -1, false);
}

void ScriptApiNode::node_on_receive_fields(v3s16 p,


+ 3
- 4
src/script/cpp_api/s_player.cpp View File

@@ -74,7 +74,7 @@ bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
push_v3f(L, dir);
lua_pushnumber(L, damage);
runCallbacks(6, RUN_CALLBACKS_MODE_OR);
return lua_toboolean(L, -1);
return readParam<bool>(L, -1);
}

s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
@@ -111,8 +111,7 @@ bool ScriptApiPlayer::on_respawnplayer(ServerActiveObject *player)
// Call callbacks
objectrefGetOrCreate(L, player);
runCallbacks(1, RUN_CALLBACKS_MODE_OR);
bool positioning_handled_by_some = lua_toboolean(L, -1);
return positioning_handled_by_some;
return readParam<bool>(L, -1);
}

bool ScriptApiPlayer::on_prejoinplayer(
@@ -129,7 +128,7 @@ bool ScriptApiPlayer::on_prejoinplayer(
lua_pushstring(L, ip.c_str());
runCallbacks(2, RUN_CALLBACKS_MODE_OR);
if (lua_isstring(L, -1)) {
reason->assign(lua_tostring(L, -1));
reason->assign(readParam<std::string>(L, -1));
return true;
}
return false;


+ 3
- 3
src/script/cpp_api/s_security.cpp View File

@@ -261,7 +261,7 @@ void ScriptApiSecurity::initializeSecurityClient()
static const char *os_whitelist[] = {
"clock",
"date",
"difftime",
"difftime",
"time",
"setlocale",
};
@@ -526,7 +526,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
// Get mod name
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
if (lua_isstring(L, -1)) {
std::string mod_name = lua_tostring(L, -1);
std::string mod_name = readParam<std::string>(L, -1);

// Builtin can access anything
if (mod_name == BUILTIN_MOD_NAME) {
@@ -649,7 +649,7 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L)
lua_pop(L, 1);

if (script->getType() == ScriptingType::Client) {
std:: string display_path = lua_tostring(L, 1);
std::string display_path = readParam<std::string>(L, 1);
const std::string *path = script->getClient()->getModFile(display_path);
if (!path) {
std::string error_msg = "Coudln't find script called:" + display_path;


+ 2
- 3
src/script/cpp_api/s_server.cpp View File

@@ -88,7 +88,7 @@ void ScriptApiServer::readPrivileges(int index, std::set<std::string> &result)
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);
bool value = readParam<bool>(L, -1);
if (value)
result.insert(key);
// removes value, keeps key for next iteration
@@ -143,8 +143,7 @@ bool ScriptApiServer::on_chat_message(const std::string &name,
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;
return readParam<bool>(L, -1);
}

void ScriptApiServer::on_mods_loaded()


+ 2
- 2
src/script/lua_api/l_areastore.cpp View File

@@ -156,7 +156,7 @@ int LuaAreaStore::l_get_areas_in_area(lua_State *L)
bool include_data = false;
bool accept_overlap = false;
if (lua_isboolean(L, 4)) {
accept_overlap = lua_toboolean(L, 4);
accept_overlap = readParam<bool>(L, 4);
get_data_and_border_flags(L, 5, &include_borders, &include_data);
}
std::vector<Area *> res;
@@ -329,7 +329,7 @@ int LuaAreaStore::create_object(lua_State *L)
NO_MAP_LOCK_REQUIRED;

LuaAreaStore *o = (lua_isstring(L, 1)) ?
new LuaAreaStore(lua_tostring(L, 1)) :
new LuaAreaStore(readParam<std::string>(L, 1)) :
new LuaAreaStore();

*(void **)(lua_newuserdata(L, sizeof(void *))) = o;


+ 2
- 7
src/script/lua_api/l_base.cpp View File

@@ -63,8 +63,8 @@ GUIEngine *ModApiBase::getGuiEngine(lua_State *L)
std::string ModApiBase::getCurrentModPath(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
const char *current_mod_name = lua_tostring(L, -1);
if (!current_mod_name)
std::string current_mod_name = readParam<std::string>(L, -1, "");
if (current_mod_name.empty())
return ".";

const ModSpec *mod = getServer(L)->getModSpec(current_mod_name);
@@ -85,8 +85,3 @@ bool ModApiBase::registerFunction(lua_State *L, const char *name,

return true;
}

bool ModApiBase::isNaN(lua_State *L, int idx)
{
return lua_type(L, idx) == LUA_TNUMBER && std::isnan(lua_tonumber(L, idx));
}

+ 2
- 3
src/script/lua_api/l_base.h View File

@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#include "common/c_types.h"
#include "common/c_internal.h"
#include "common/helper.h"
#include "gamedef.h"

extern "C" {
@@ -38,7 +39,7 @@ class Server;
class Environment;
class GUIEngine;

class ModApiBase {
class ModApiBase : protected LuaHelper {

public:
static ScriptApiBase* getScriptApiBase(lua_State *L);
@@ -70,8 +71,6 @@ public:
const char* name,
lua_CFunction func,
int top);

static bool isNaN(lua_State *L, int idx);
};

#endif /* L_BASE_H_ */

+ 26
- 15
src/script/lua_api/l_client.cpp View File

@@ -36,18 +36,29 @@ with this program; if not, write to the Free Software Foundation, Inc.,

extern MainGameCallback *g_gamecallback;

// get_current_modname()
int ModApiClient::l_get_current_modname(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
return 1;
}

// get_modpath(modname)
int ModApiClient::l_get_modpath(lua_State *L)
{
std::string modname = readParam<std::string>(L, 1);
// Client mods use a virtual filesystem, see Client::scanModSubfolder()
std::string path = modname + ":";
lua_pushstring(L, path.c_str());
return 1;
}

// get_last_run_mod()
int ModApiClient::l_get_last_run_mod(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
const char *current_mod = lua_tostring(L, -1);
if (current_mod == NULL || current_mod[0] == '\0') {
std::string current_mod = readParam<std::string>(L, -1, "");
if (current_mod.empty()) {
lua_pop(L, 1);
lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
}
@@ -90,15 +101,9 @@ int ModApiClient::l_display_chat_message(lua_State *L)
// send_chat_message(message)
int ModApiClient::l_send_chat_message(lua_State *L)
{
if (!lua_isstring(L, 1))
return 0;

// If server disabled this API, discard
if (getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_CHAT_MESSAGES))
return 0;

std::string message = luaL_checkstring(L, 1);
getClient(L)->sendChatMessage(utf8_to_wide(message));
if (!lua_isstring (L, 1)) return 0;
std::string message = luaL_checkstring (L, 1);
getClient (L)->sendChatMessage (utf8_to_wide (message));
return 0;
}

@@ -191,9 +196,14 @@ int ModApiClient::l_get_node_or_nil(lua_State *L)

int ModApiClient::l_get_language(lua_State *L)
{
char *locale = setlocale(LC_ALL, "");
char *locale = setlocale(LC_MESSAGES, NULL);
std::string lang = gettext("LANG_CODE");
if (lang == "LANG_CODE")
lang = "";

lua_pushstring(L, locale);
return 1;
lua_pushstring(L, lang.c_str());
return 2;
}

int ModApiClient::l_get_wielded_item(lua_State *L)
@@ -296,7 +306,7 @@ int ModApiClient::l_get_item_def(lua_State *L)
if (!lua_isstring(L, 1))
return 0;

const std::string &name(lua_tostring(L, 1));
std::string name = readParam<std::string>(L, 1);
if (!idef->isKnown(name))
return 0;
const ItemDefinition &def = idef->get(name);
@@ -321,7 +331,7 @@ int ModApiClient::l_get_node_def(lua_State *L)
if (getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_READ_NODEDEFS))
return 0;

const std::string &name = lua_tostring(L, 1);
std::string name = readParam<std::string>(L, 1);
const ContentFeatures &cf = ndef->get(ndef->getId(name));
if (cf.name != name) // Unknown node. | name = <whatever>, cf.name = ignore
return 0;
@@ -352,6 +362,7 @@ int ModApiClient::l_get_builtin_path(lua_State *L)
void ModApiClient::Initialize(lua_State *L, int top)
{
API_FCT(get_current_modname);
API_FCT(get_modpath);
API_FCT(print);
API_FCT(display_chat_message);
API_FCT(send_chat_message);


+ 3
- 0
src/script/lua_api/l_client.h View File

@@ -31,6 +31,9 @@ private:
// get_current_modname()
static int l_get_current_modname(lua_State *L);

// get_modpath(modname)
static int l_get_modpath(lua_State *L);

// print(text)
static int l_print(lua_State *L);



+ 4
- 4
src/script/lua_api/l_craft.cpp View File

@@ -57,7 +57,7 @@ bool ModApiCraft::readCraftRecipeShaped(lua_State *L, int index,
// key at index -2 and value at index -1
if(!lua_isstring(L, -1))
return false;
recipe.push_back(lua_tostring(L, -1));
recipe.push_back(readParam<std::string>(L, -1));
// removes value, keeps key for next iteration
lua_pop(L, 1);
colcount++;
@@ -90,7 +90,7 @@ bool ModApiCraft::readCraftRecipeShapeless(lua_State *L, int index,
// key at index -2 and value at index -1
if(!lua_isstring(L, -1))
return false;
recipe.push_back(lua_tostring(L, -1));
recipe.push_back(readParam<std::string>(L, -1));
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
@@ -115,12 +115,12 @@ bool ModApiCraft::readCraftReplacements(lua_State *L, int index,
lua_rawgeti(L, -1, 1);
if(!lua_isstring(L, -1))
return false;
std::string replace_from = lua_tostring(L, -1);
std::string replace_from = readParam<std::string>(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, -1, 2);
if(!lua_isstring(L, -1))
return false;
std::string replace_to = lua_tostring(L, -1);
std::string replace_to = readParam<std::string>(L, -1);
lua_pop(L, 1);
replacements.pairs.push_back(
std::make_pair(replace_from, replace_to));


+ 19
- 15
src/script/lua_api/l_env.cpp View File

@@ -165,10 +165,10 @@ int LuaRaycast::create_object(lua_State *L)
v3f pos1 = checkFloatPos(L, 1);
v3f pos2 = checkFloatPos(L, 2);
if (lua_isboolean(L, 3)) {
objects = lua_toboolean(L, 3);
objects = readParam<bool>(L, 3);
}
if (lua_isboolean(L, 4)) {
liquids = lua_toboolean(L, 4);
liquids = readParam<bool>(L, 4);
}

LuaRaycast *o = new LuaRaycast(core::line3d<f32>(pos1, pos2),
@@ -599,9 +599,13 @@ int ModApiEnvMod::l_add_entity(lua_State *L)
// Do it
ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, staticdata);
int objectid = env->addActiveObject(obj);

// If failed to add, return nothing (reads as nil)
if(objectid == 0)
return 0;
if(objectid == 0) return 0;

// If already deleted (can happen in on_activate), return nil
if (obj->isGone()) return 0;

// Return ObjectRef
getScriptApiBase(L)->objectrefGetOrCreate(L, obj);
return 1;
@@ -687,7 +691,7 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)

// Do it
v3f pos = checkFloatPos(L, 1);
float radius = luaL_checknumber(L, 2) * BS;
float radius = readParam<float>(L, 2) * BS;
std::vector<u16> ids;
env->getObjectsInsideRadius(ids, pos, radius);
ScriptApiBase *script = getScriptApiBase(L);
@@ -711,7 +715,7 @@ int ModApiEnvMod::l_set_timeofday(lua_State *L)
GET_ENV_PTR;

// Do it
float timeofday_f = luaL_checknumber(L, 1);
float timeofday_f = readParam<float>(L, 1);
sanity_check(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
@@ -778,15 +782,15 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
while (lua_next(L, 3) != 0) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
ndef->getIds(lua_tostring(L, -1), filter);
ndef->getIds(readParam<std::string>(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);
ndef->getIds(readParam<std::string>(L, 3), filter);
}

int start_radius = (lua_toboolean(L, 4)) ? 0 : 1;
int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;

#ifndef SERVER
// Client API limitations
@@ -836,12 +840,12 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
while (lua_next(L, 3) != 0) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
ndef->getIds(lua_tostring(L, -1), filter);
ndef->getIds(readParam<std::string>(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);
ndef->getIds(readParam<std::string>(L, 3), filter);
}

std::unordered_map<content_t, u32> individual_count;
@@ -901,12 +905,12 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
while (lua_next(L, 3) != 0) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
ndef->getIds(lua_tostring(L, -1), filter);
ndef->getIds(readParam<std::string>(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);
ndef->getIds(readParam<std::string>(L, 3), filter);
}

lua_newtable(L);
@@ -943,8 +947,8 @@ int ModApiEnvMod::l_get_perlin(lua_State *L)
} else {
params.seed = luaL_checkint(L, 1);
params.octaves = luaL_checkint(L, 2);
params.persist = luaL_checknumber(L, 3);
params.spread = v3f(1, 1, 1) * luaL_checknumber(L, 4);
params.persist = readParam<float>(L, 3);
params.spread = v3f(1, 1, 1) * readParam<float>(L, 4);
}

params.seed += (int)env->getServerMap().getSeed();


+ 2
- 2
src/script/lua_api/l_http.cpp View File

@@ -59,7 +59,7 @@ void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req)
lua_pop(L, 1);
}
} else if (lua_isstring(L, 2)) {
req.post_data = lua_tostring(L, 2);
req.post_data = readParam<std::string>(L, 2);
}
lua_pop(L, 1);

@@ -154,7 +154,7 @@ int ModApiHttp::l_request_http_api(lua_State *L)
return 0;
}

const char *mod_name = lua_tostring(L, -1);
std::string mod_name = readParam<std::string>(L, -1);
std::string http_mods = g_settings->get("secure.http_mods");
http_mods.erase(std::remove(http_mods.begin(), http_mods.end(), ' '), http_mods.end());
std::vector<std::string> mod_list_http = str_split(http_mods, ',');


+ 2
- 2
src/script/lua_api/l_inventory.cpp View File

@@ -336,7 +336,7 @@ int InvRef::l_contains_item(lua_State *L)
InventoryList *list = getlist(L, ref, listname);
bool match_meta = false;
if (lua_isboolean(L, 4))
match_meta = lua_toboolean(L, 4);
match_meta = readParam<bool>(L, 4);
if (list) {
lua_pushboolean(L, list->containsItem(item, match_meta));
} else {
@@ -528,7 +528,7 @@ int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
const char *name = luaL_checkstring(L, 1);
const char *player = lua_isstring(L, 2) ? lua_tostring(L, 2) : "";
std::string player = readParam<std::string>(L, 2, "");
if (getServer(L)->createDetachedInventory(name, player) != NULL) {
InventoryLocation loc;
loc.setDetached(name);


+ 1
- 1
src/script/lua_api/l_item.cpp View File

@@ -515,7 +515,7 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
std::string name;
lua_getfield(L, table, "name");
if(lua_isstring(L, -1)){
name = lua_tostring(L, -1);
name = readParam<std::string>(L, -1);
verbosestream<<"register_item_raw: "<<name<<std::endl;
} else {
throw LuaError("register_item_raw: name is not defined or not a string");


+ 7
- 6
src/script/lua_api/l_mainmenu.cpp View File

@@ -81,7 +81,7 @@ int ModApiMainMenu::getBoolData(lua_State *L, std::string name,bool& valid)
}

valid = true;
return lua_toboolean(L, -1);
return readParam<bool>(L, -1);
}

/******************************************************************************/
@@ -156,7 +156,7 @@ int ModApiMainMenu::l_set_background(lua_State *L)
unsigned int minsize = 16;

if (!lua_isnone(L, 3)) {
tile_image = lua_toboolean(L, 3);
tile_image = readParam<bool>(L, 3);
}

if (!lua_isnone(L, 4)) {
@@ -193,7 +193,7 @@ int ModApiMainMenu::l_set_clouds(lua_State *L)
GUIEngine* engine = getGuiEngine(L);
sanity_check(engine != NULL);

bool value = lua_toboolean(L,1);
bool value = readParam<bool>(L,1);

engine->m_clouds_enabled = value;

@@ -619,7 +619,8 @@ int ModApiMainMenu::l_set_topleft_text(lua_State *L)
int ModApiMainMenu::l_get_mapgen_names(lua_State *L)
{
std::vector<const char *> names;
Mapgen::getMapgenNames(&names, lua_toboolean(L, 1));
bool include_hidden = lua_isboolean(L, 1) && readParam<bool>(L, 1);
Mapgen::getMapgenNames(&names, include_hidden);

lua_newtable(L);
for (size_t i = 0; i != names.size(); i++) {
@@ -714,7 +715,7 @@ int ModApiMainMenu::l_copy_dir(lua_State *L)

if ((!lua_isnone(L,3)) &&
(!lua_isnil(L,3))) {
keep_source = lua_toboolean(L,3);
keep_source = readParam<bool>(L,3);
}

std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
@@ -859,7 +860,7 @@ int ModApiMainMenu::l_show_path_select_dialog(lua_State *L)

const char *formname= luaL_checkstring(L, 1);
const char *title = luaL_checkstring(L, 2);
bool is_file_select = lua_toboolean(L, 3);
bool is_file_select = readParam<bool>(L, 3);

GUIFileSelectMenu* fileOpenMenu =
new GUIFileSelectMenu(RenderingEngine::get_gui_env(),


+ 17
- 22
src/script/lua_api/l_mapgen.cpp View File

@@ -845,26 +845,26 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L)

lua_getfield(L, 1, "mgname");
if (lua_isstring(L, -1))
settingsmgr->setMapSetting("mg_name", lua_tostring(L, -1), true);
settingsmgr->setMapSetting("mg_name", readParam<std::string>(L, -1), true);

lua_getfield(L, 1, "seed");
if (lua_isnumber(L, -1))
settingsmgr->setMapSetting("seed", lua_tostring(L, -1), true);
settingsmgr->setMapSetting("seed", readParam<std::string>(L, -1), true);

lua_getfield(L, 1, "water_level");
if (lua_isnumber(L, -1))
settingsmgr->setMapSetting("water_level", lua_tostring(L, -1), true);
settingsmgr->setMapSetting("water_level", readParam<std::string>(L, -1), true);

lua_getfield(L, 1, "chunksize");
if (lua_isnumber(L, -1))
settingsmgr->setMapSetting("chunksize", lua_tostring(L, -1), true);
settingsmgr->setMapSetting("chunksize", readParam<std::string>(L, -1), true);

warn_if_field_exists(L, 1, "flagmask",
"Deprecated: flags field now includes unset flags.");

lua_getfield(L, 1, "flags");
if (lua_isstring(L, -1))
settingsmgr->setMapSetting("mg_flags", lua_tostring(L, -1), true);
settingsmgr->setMapSetting("mg_flags", readParam<std::string>(L, -1), true);

return 0;
}
@@ -914,7 +914,7 @@ int ModApiMapgen::l_set_mapgen_setting(lua_State *L)

const char *name = luaL_checkstring(L, 1);
const char *value = luaL_checkstring(L, 2);
bool override_meta = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : false;
bool override_meta = readParam<bool>(L, 3, false);

if (!settingsmgr->setMapSetting(name, value, override_meta)) {
errorstream << "set_mapgen_setting: cannot set '"
@@ -943,7 +943,7 @@ int ModApiMapgen::l_set_mapgen_setting_noiseparams(lua_State *L)
return 0;
}

bool override_meta = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : false;
bool override_meta = readParam<bool>(L, 3, false);

if (!settingsmgr->setMapSettingNoiseParams(name, &np, override_meta)) {
errorstream << "set_mapgen_setting_noiseparams: cannot set '"
@@ -953,13 +953,11 @@ int ModApiMapgen::l_set_mapgen_setting_noiseparams(lua_State *L)
return 0;
}


// set_noiseparams(name, noiseparams, set_default)
// set global config values for noise parameters
int ModApiMapgen::l_set_noiseparams(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;

const char *name = luaL_checkstring(L, 1);

NoiseParams np;
@@ -970,13 +968,10 @@ int ModApiMapgen::l_set_noiseparams(lua_State *L)
}

bool set_default = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : true;

g_settings->setNoiseParams(name, np, set_default);

return 0;
}


// get_noiseparams(name)
int ModApiMapgen::l_get_noiseparams(lua_State *L)
{
@@ -1589,14 +1584,14 @@ int ModApiMapgen::l_place_schematic(lua_State *L)

//// Read rotation
int rot = ROTATE_0;
const char *enumstr = lua_tostring(L, 3);
if (enumstr)
string_to_enum(es_Rotation, rot, std::string(enumstr));
std::string enumstr = readParam<std::string>(L, 3, "");
if (!enumstr.empty())
string_to_enum(es_Rotation, rot, enumstr);

//// Read force placement
bool force_placement = true;
if (lua_isboolean(L, 5))
force_placement = lua_toboolean(L, 5);
force_placement = readParam<bool>(L, 5);

//// Read node replacements
StringMap replace_names;
@@ -1637,14 +1632,14 @@ int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L)

//// Read rotation
int rot = ROTATE_0;
const char *enumstr = lua_tostring(L, 4);
if (enumstr)
std::string enumstr = readParam<std::string>(L, 4, "");
if (!enumstr.empty())
string_to_enum(es_Rotation, rot, std::string(enumstr));

//// Read force placement
bool force_placement = true;
if (lua_isboolean(L, 6))
force_placement = lua_toboolean(L, 6);
force_placement = readParam<bool>(L, 6);

//// Read node replacements
StringMap replace_names;
@@ -1695,9 +1690,9 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L)

//// Read format of definition to save as
int schem_format = SCHEM_FMT_MTS;
const char *enumstr = lua_tostring(L, 2);
if (enumstr)
string_to_enum(es_SchematicFormatType, schem_format, std::string(enumstr));
std::string enumstr = readParam<std::string>(L, 2, "");
if (!enumstr.empty())
string_to_enum(es_SchematicFormatType, schem_format, enumstr);

//// Serialize to binary string
std::ostringstream os(std::ios_base::binary);


+ 2
- 2
src/script/lua_api/l_metadata.cpp View File

@@ -190,7 +190,7 @@ int MetaDataRef::l_set_float(lua_State *L)

MetaDataRef *ref = checkobject(L, 1);
std::string name = luaL_checkstring(L, 2);
float a = luaL_checknumber(L, 3);
float a = readParam<float>(L, 3);
std::string str = ftos(a);

Metadata *meta = ref->getmeta(true);
@@ -276,7 +276,7 @@ bool MetaDataRef::handleFromTable(lua_State *L, int table, Metadata *meta)
lua_pushnil(L);
while (lua_next(L, fieldstable) != 0) {
// key at index -2 and value at index -1
std::string name = lua_tostring(L, -2);
std::string name = readParam<std::string>(L, -2);
size_t cl;
const char *cs = lua_tolstring(L, -1, &cl);
meta->setString(name, std::string(cs, cl));


+ 2
- 2
src/script/lua_api/l_nodemeta.cpp View File

@@ -109,12 +109,12 @@ int NodeMetaRef::l_mark_as_private(lua_State *L)
while (lua_next(L, 2) != 0) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
meta->markPrivate(lua_tostring(L, -1), true);
meta->markPrivate(readParam<std::string>(L, -1), true);
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
} else if (lua_isstring(L, 2)) {
meta->markPrivate(lua_tostring(L, 2), true);
meta->markPrivate(readParam<std::string>(L, 2), true);
}
ref->reportMetadataChange();



+ 3
- 3
src/script/lua_api/l_nodetimer.cpp View File

@@ -43,8 +43,8 @@ int NodeTimerRef::l_set(lua_State *L)
NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
f32 t = luaL_checknumber(L,2);
f32 e = luaL_checknumber(L,3);
f32 t = readParam<float>(L,2);
f32 e = readParam<float>(L,3);
env->getMap().setNodeTimer(NodeTimer(t, e, o->m_p));
return 0;
}
@@ -55,7 +55,7 @@ int NodeTimerRef::l_start(lua_State *L)
NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
f32 t = luaL_checknumber(L,2);
f32 t = readParam<float>(L,2);
env->getMap().setNodeTimer(NodeTimer(t, 0, o->m_p));
return 0;
}


+ 2
- 2
src/script/lua_api/l_noise.cpp View File

@@ -75,8 +75,8 @@ int LuaPerlinNoise::create_object(lua_State *L)
} else {
params.seed = luaL_checkint(L, 1);
params.octaves = luaL_checkint(L, 2);
params.persist = luaL_checknumber(L, 3);
params.spread = v3f(1, 1, 1) * luaL_checknumber(L, 4);
params.persist = readParam<float>(L, 3);
params.spread = v3f(1, 1, 1) * readParam<float>(L, 4);
}

LuaPerlinNoise *o = new LuaPerlinNoise(&params);


+ 18
- 17
src/script/lua_api/l_object.cpp View File

@@ -197,7 +197,7 @@ int ObjectRef::l_move_to(lua_State *L)
// pos
v3f pos = checkFloatPos(L, 2);
// continuous
bool continuous = lua_toboolean(L, 3);
bool continuous = readParam<bool>(L, 3);
// Do it
co->moveTo(pos, continuous);
return 0;
@@ -284,7 +284,8 @@ int ObjectRef::l_set_hp(lua_State *L)
lua_pushvalue(L, 3);

lua_getfield(L, -1, "type");
if (lua_isstring(L, -1) && !reason.setTypeFromString(lua_tostring(L, -1))) {
if (lua_isstring(L, -1) &&
!reason.setTypeFromString(readParam<std::string>(L, -1))) {
errorstream << "Bad type given!" << std::endl;
}
lua_pop(L, 1);
@@ -514,7 +515,7 @@ int ObjectRef::l_set_animation(lua_State *L)
frame_blend = lua_tonumber(L, 4);
bool frame_loop = true;
if (lua_isboolean(L, 5))
frame_loop = lua_toboolean(L, 5);
frame_loop = readParam<bool>(L, 5);
co->setAnimation(frames, frame_speed, frame_blend, frame_loop);
return 0;
}
@@ -679,7 +680,7 @@ int ObjectRef::l_set_bone_position(lua_State *L)
// Do it
std::string bone = "";
if (!lua_isnil(L, 2))
bone = lua_tostring(L, 2);
bone = readParam<std::string>(L, 2);
v3f position = v3f(0, 0, 0);
if (!lua_isnil(L, 3))
position = check_v3f(L, 3);
@@ -701,7 +702,7 @@ int ObjectRef::l_get_bone_position(lua_State *L)
// Do it
std::string bone = "";
if (!lua_isnil(L, 2))
bone = lua_tostring(L, 2);
bone = readParam<std::string>(L, 2);

v3f position = v3f(0, 0, 0);
v3f rotation = v3f(0, 0, 0);
@@ -738,7 +739,7 @@ int ObjectRef::l_set_attach(lua_State *L)

bone = "";
if (!lua_isnil(L, 3))
bone = lua_tostring(L, 3);
bone = readParam<std::string>(L, 3);
position = v3f(0, 0, 0);
if (!lua_isnil(L, 4))
position = read_v3f(L, 4);
@@ -976,7 +977,7 @@ int ObjectRef::l_set_yaw(lua_State *L)
if (isNaN(L, 2))
throw LuaError("ObjectRef::set_yaw: NaN value is not allowed.");

float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
float yaw = readParam<float>(L, 2) * core::RADTODEG;
// Do it
co->setYaw(yaw);
return 0;
@@ -1063,7 +1064,7 @@ int ObjectRef::l_set_sprite(lua_State *L)
framelength = lua_tonumber(L, 4);
bool select_horiz_by_yawpitch = false;
if (!lua_isnil(L, 5))
select_horiz_by_yawpitch = lua_toboolean(L, 5);
select_horiz_by_yawpitch = readParam<bool>(L, 5);
co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
return 0;
}
@@ -1220,7 +1221,7 @@ int ObjectRef::l_set_look_vertical(lua_State *L)
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
if (co == NULL) return 0;
float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
float pitch = readParam<float>(L, 2) * core::RADTODEG;
// Do it
co->setPitchAndSend(pitch);
return 1;
@@ -1233,7 +1234,7 @@ int ObjectRef::l_set_look_horizontal(lua_State *L)
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
if (co == NULL) return 0;
float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
float yaw = readParam<float>(L, 2) * core::RADTODEG;
// Do it
co->setYawAndSend(yaw);
return 1;
@@ -1251,7 +1252,7 @@ int ObjectRef::l_set_look_pitch(lua_State *L)
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
if (co == NULL) return 0;
float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
float pitch = readParam<float>(L, 2) * core::RADTODEG;
// Do it
co->setPitchAndSend(pitch);
return 1;
@@ -1269,7 +1270,7 @@ int ObjectRef::l_set_look_yaw(lua_State *L)
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
if (co == NULL) return 0;
float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
float yaw = readParam<float>(L, 2) * core::RADTODEG;
// Do it
co->setYawAndSend(yaw);
return 1;
@@ -1732,7 +1733,7 @@ int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
if (player == NULL)
return 0;

std::string name = lua_tostring(L, 2);
std::string name = readParam<std::string>(L, 2);

getServer(L)->hudSetHotbarImage(player, name);
return 1;
@@ -1761,7 +1762,7 @@ int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
if (player == NULL)
return 0;

std::string name = lua_tostring(L, 2);
std::string name = readParam<std::string>(L, 2);

getServer(L)->hudSetHotbarSelectedImage(player, name);
return 1;
@@ -1801,7 +1802,7 @@ int ObjectRef::l_set_sky(lua_State *L)
while (lua_next(L, 4) != 0) {
// key at index -2 and value at index -1
if (lua_isstring(L, -1))
params.push_back(lua_tostring(L, -1));
params.push_back(readParam<std::string>(L, -1));
else
params.push_back("");
// removes value, keeps key for next iteration
@@ -1814,7 +1815,7 @@ int ObjectRef::l_set_sky(lua_State *L)

bool clouds = true;
if (lua_isboolean(L, 5))
clouds = lua_toboolean(L, 5);
clouds = readParam<bool>(L, 5);

if (!getServer(L)->setSky(player, bgcolor, type, params, clouds))
return 0;
@@ -1890,7 +1891,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L)
float ratio = 0.0f;
if (!lua_isnil(L, 2)) {
do_override = true;
ratio = luaL_checknumber(L, 2);
ratio = readParam<float>(L, 2);
}

if (!getServer(L)->overrideDayNightRatio(player, do_override, ratio))


+ 2
- 2
src/script/lua_api/l_particles.cpp View File

@@ -66,7 +66,7 @@ int ModApiParticles::l_add_particle(lua_State *L)
acc = check_v3f(L, 3);
expirationtime = luaL_checknumber(L, 4);
size = luaL_checknumber(L, 5);
collisiondetection = lua_toboolean(L, 6);
collisiondetection = readParam<bool>(L, 6);
texture = luaL_checkstring(L, 7);
if (lua_gettop(L) == 8) // only spawn for a single player
playername = luaL_checkstring(L, 8);
@@ -177,7 +177,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
maxexptime = luaL_checknumber(L, 10);
minsize = luaL_checknumber(L, 11);
maxsize = luaL_checknumber(L, 12);
collisiondetection = lua_toboolean(L, 13);
collisiondetection = readParam<bool>(L, 13);
texture = luaL_checkstring(L, 14);
if (lua_gettop(L) == 15) // only spawn for a single player
playername = luaL_checkstring(L, 15);


+ 9
- 13
src/script/lua_api/l_server.cpp View File

@@ -33,7 +33,7 @@ int ModApiServer::l_request_shutdown(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
const char *msg = lua_tolstring(L, 1, NULL);
bool reconnect = lua_toboolean(L, 2);
bool reconnect = readParam<bool>(L, 2);
float seconds_before_shutdown = lua_tonumber(L, 3);
getServer(L)->requestShutdown(msg ? msg : "", reconnect, seconds_before_shutdown);
return 0;
@@ -314,15 +314,11 @@ int ModApiServer::l_kick_player(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
const char *name = luaL_checkstring(L, 1);
std::string message;
std::string message("Kicked");