s_env.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "cpp_api/s_env.h"
  17. #include "cpp_api/s_internal.h"
  18. #include "common/c_converter.h"
  19. #include "log.h"
  20. #include "environment.h"
  21. #include "mapgen/mapgen.h"
  22. #include "lua_api/l_env.h"
  23. #include "server.h"
  24. #include "script/common/c_content.h"
  25. void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp,
  26. u32 blockseed)
  27. {
  28. SCRIPTAPI_PRECHECKHEADER
  29. // Get core.registered_on_generateds
  30. lua_getglobal(L, "core");
  31. lua_getfield(L, -1, "registered_on_generateds");
  32. // Call callbacks
  33. push_v3s16(L, minp);
  34. push_v3s16(L, maxp);
  35. lua_pushnumber(L, blockseed);
  36. runCallbacks(3, RUN_CALLBACKS_MODE_FIRST);
  37. }
  38. void ScriptApiEnv::environment_Step(float dtime)
  39. {
  40. SCRIPTAPI_PRECHECKHEADER
  41. //infostream << "scriptapi_environment_step" << std::endl;
  42. // Get core.registered_globalsteps
  43. lua_getglobal(L, "core");
  44. lua_getfield(L, -1, "registered_globalsteps");
  45. // Call callbacks
  46. lua_pushnumber(L, dtime);
  47. runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
  48. }
  49. void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &type)
  50. {
  51. SCRIPTAPI_PRECHECKHEADER
  52. if (player == NULL)
  53. return;
  54. // Get minetest.registered_playerevents
  55. lua_getglobal(L, "minetest");
  56. lua_getfield(L, -1, "registered_playerevents");
  57. // Call callbacks
  58. objectrefGetOrCreate(L, player); // player
  59. lua_pushstring(L,type.c_str()); // event type
  60. runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
  61. }
  62. void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
  63. {
  64. SCRIPTAPI_PRECHECKHEADER
  65. verbosestream << "ScriptApiEnv: Environment initialized" << std::endl;
  66. setEnv(env);
  67. /*
  68. Add {Loading,Active}BlockModifiers to environment
  69. */
  70. // Get core.registered_abms
  71. lua_getglobal(L, "core");
  72. lua_getfield(L, -1, "registered_abms");
  73. int registered_abms = lua_gettop(L);
  74. if (!lua_istable(L, registered_abms)) {
  75. lua_pop(L, 1);
  76. throw LuaError("core.registered_abms was not a lua table, as expected.");
  77. }
  78. lua_pushnil(L);
  79. while (lua_next(L, registered_abms)) {
  80. // key at index -2 and value at index -1
  81. int id = lua_tonumber(L, -2);
  82. int current_abm = lua_gettop(L);
  83. std::vector<std::string> trigger_contents;
  84. lua_getfield(L, current_abm, "nodenames");
  85. if (lua_istable(L, -1)) {
  86. int table = lua_gettop(L);
  87. lua_pushnil(L);
  88. while (lua_next(L, table)) {
  89. // key at index -2 and value at index -1
  90. luaL_checktype(L, -1, LUA_TSTRING);
  91. trigger_contents.emplace_back(readParam<std::string>(L, -1));
  92. // removes value, keeps key for next iteration
  93. lua_pop(L, 1);
  94. }
  95. } else if (lua_isstring(L, -1)) {
  96. trigger_contents.emplace_back(readParam<std::string>(L, -1));
  97. }
  98. lua_pop(L, 1);
  99. std::vector<std::string> required_neighbors;
  100. lua_getfield(L, current_abm, "neighbors");
  101. if (lua_istable(L, -1)) {
  102. int table = lua_gettop(L);
  103. lua_pushnil(L);
  104. while (lua_next(L, table)) {
  105. // key at index -2 and value at index -1
  106. luaL_checktype(L, -1, LUA_TSTRING);
  107. required_neighbors.emplace_back(readParam<std::string>(L, -1));
  108. // removes value, keeps key for next iteration
  109. lua_pop(L, 1);
  110. }
  111. } else if (lua_isstring(L, -1)) {
  112. required_neighbors.emplace_back(readParam<std::string>(L, -1));
  113. }
  114. lua_pop(L, 1);
  115. float trigger_interval = 10.0;
  116. getfloatfield(L, current_abm, "interval", trigger_interval);
  117. int trigger_chance = 50;
  118. getintfield(L, current_abm, "chance", trigger_chance);
  119. bool simple_catch_up = true;
  120. getboolfield(L, current_abm, "catch_up", simple_catch_up);
  121. s16 min_y = INT16_MIN;
  122. getintfield(L, current_abm, "min_y", min_y);
  123. s16 max_y = INT16_MAX;
  124. getintfield(L, current_abm, "max_y", max_y);
  125. lua_getfield(L, current_abm, "action");
  126. luaL_checktype(L, current_abm + 1, LUA_TFUNCTION);
  127. lua_pop(L, 1);
  128. LuaABM *abm = new LuaABM(L, id, trigger_contents, required_neighbors,
  129. trigger_interval, trigger_chance, simple_catch_up, min_y, max_y);
  130. env->addActiveBlockModifier(abm);
  131. // removes value, keeps key for next iteration
  132. lua_pop(L, 1);
  133. }
  134. lua_pop(L, 1);
  135. // Get core.registered_lbms
  136. lua_getglobal(L, "core");
  137. lua_getfield(L, -1, "registered_lbms");
  138. int registered_lbms = lua_gettop(L);
  139. if (!lua_istable(L, registered_lbms)) {
  140. lua_pop(L, 1);
  141. throw LuaError("core.registered_lbms was not a lua table, as expected.");
  142. }
  143. lua_pushnil(L);
  144. while (lua_next(L, registered_lbms)) {
  145. // key at index -2 and value at index -1
  146. int id = lua_tonumber(L, -2);
  147. int current_lbm = lua_gettop(L);
  148. std::set<std::string> trigger_contents;
  149. lua_getfield(L, current_lbm, "nodenames");
  150. if (lua_istable(L, -1)) {
  151. int table = lua_gettop(L);
  152. lua_pushnil(L);
  153. while (lua_next(L, table)) {
  154. // key at index -2 and value at index -1
  155. luaL_checktype(L, -1, LUA_TSTRING);
  156. trigger_contents.insert(readParam<std::string>(L, -1));
  157. // removes value, keeps key for next iteration
  158. lua_pop(L, 1);
  159. }
  160. } else if (lua_isstring(L, -1)) {
  161. trigger_contents.insert(readParam<std::string>(L, -1));
  162. }
  163. lua_pop(L, 1);
  164. std::string name;
  165. getstringfield(L, current_lbm, "name", name);
  166. bool run_at_every_load = getboolfield_default(L, current_lbm,
  167. "run_at_every_load", false);
  168. lua_getfield(L, current_lbm, "action");
  169. luaL_checktype(L, current_lbm + 1, LUA_TFUNCTION);
  170. lua_pop(L, 1);
  171. LuaLBM *lbm = new LuaLBM(L, id, trigger_contents, name,
  172. run_at_every_load);
  173. env->addLoadingBlockModifierDef(lbm);
  174. // removes value, keeps key for next iteration
  175. lua_pop(L, 1);
  176. }
  177. lua_pop(L, 1);
  178. }
  179. void ScriptApiEnv::on_emerge_area_completion(
  180. v3s16 blockpos, int action, ScriptCallbackState *state)
  181. {
  182. Server *server = getServer();
  183. // This function should be executed with envlock held.
  184. // The caller (LuaEmergeAreaCallback in src/script/lua_api/l_env.cpp)
  185. // should have obtained the lock.
  186. // Note that the order of these locks is important! Envlock must *ALWAYS*
  187. // be acquired before attempting to acquire scriptlock, or else ServerThread
  188. // will try to acquire scriptlock after it already owns envlock, thus
  189. // deadlocking EmergeThread and ServerThread
  190. SCRIPTAPI_PRECHECKHEADER
  191. int error_handler = PUSH_ERROR_HANDLER(L);
  192. lua_rawgeti(L, LUA_REGISTRYINDEX, state->callback_ref);
  193. luaL_checktype(L, -1, LUA_TFUNCTION);
  194. push_v3s16(L, blockpos);
  195. lua_pushinteger(L, action);
  196. lua_pushinteger(L, state->refcount);
  197. lua_rawgeti(L, LUA_REGISTRYINDEX, state->args_ref);
  198. setOriginDirect(state->origin.c_str());
  199. try {
  200. PCALL_RES(lua_pcall(L, 4, 0, error_handler));
  201. } catch (LuaError &e) {
  202. // Note: don't throw here, we still need to run the cleanup code below
  203. server->setAsyncFatalError(e);
  204. }
  205. lua_pop(L, 1); // Pop error handler
  206. if (state->refcount == 0) {
  207. luaL_unref(L, LUA_REGISTRYINDEX, state->callback_ref);
  208. luaL_unref(L, LUA_REGISTRYINDEX, state->args_ref);
  209. }
  210. }
  211. void ScriptApiEnv::check_for_falling(v3s16 p)
  212. {
  213. SCRIPTAPI_PRECHECKHEADER
  214. int error_handler = PUSH_ERROR_HANDLER(L);
  215. lua_getglobal(L, "core");
  216. lua_getfield(L, -1, "check_for_falling");
  217. luaL_checktype(L, -1, LUA_TFUNCTION);
  218. push_v3s16(L, p);
  219. PCALL_RES(lua_pcall(L, 1, 0, error_handler));
  220. }
  221. void ScriptApiEnv::on_liquid_transformed(
  222. const std::vector<std::pair<v3s16, MapNode>> &list)
  223. {
  224. SCRIPTAPI_PRECHECKHEADER
  225. // Get core.registered_on_liquid_transformed
  226. lua_getglobal(L, "core");
  227. lua_getfield(L, -1, "registered_on_liquid_transformed");
  228. luaL_checktype(L, -1, LUA_TTABLE);
  229. lua_remove(L, -2);
  230. // Skip converting list and calling hook if there are
  231. // no registered callbacks.
  232. if(lua_objlen(L, -1) < 1) return;
  233. // Convert the list to a pos array and a node array for lua
  234. int index = 1;
  235. lua_createtable(L, list.size(), 0);
  236. lua_createtable(L, list.size(), 0);
  237. for(std::pair<v3s16, MapNode> p : list) {
  238. lua_pushnumber(L, index);
  239. push_v3s16(L, p.first);
  240. lua_rawset(L, -4);
  241. lua_pushnumber(L, index++);
  242. pushnode(L, p.second);
  243. lua_rawset(L, -3);
  244. }
  245. runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
  246. }
  247. void ScriptApiEnv::on_mapblocks_changed(const std::unordered_set<v3s16> &set)
  248. {
  249. SCRIPTAPI_PRECHECKHEADER
  250. // Get core.registered_on_mapblocks_changed
  251. lua_getglobal(L, "core");
  252. lua_getfield(L, -1, "registered_on_mapblocks_changed");
  253. luaL_checktype(L, -1, LUA_TTABLE);
  254. lua_remove(L, -2);
  255. // Convert the set to a set of position hashes
  256. lua_createtable(L, 0, set.size());
  257. for(const v3s16 &p : set) {
  258. lua_pushnumber(L, hash_node_position(p));
  259. lua_pushboolean(L, true);
  260. lua_rawset(L, -3);
  261. }
  262. lua_pushinteger(L, set.size());
  263. runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
  264. }
  265. bool ScriptApiEnv::has_on_mapblocks_changed()
  266. {
  267. SCRIPTAPI_PRECHECKHEADER
  268. // Get core.registered_on_mapblocks_changed
  269. lua_getglobal(L, "core");
  270. lua_getfield(L, -1, "registered_on_mapblocks_changed");
  271. luaL_checktype(L, -1, LUA_TTABLE);
  272. return lua_objlen(L, -1) > 0;
  273. }