3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "cpp_api/s_env.h"
21 #include "cpp_api/s_internal.h"
22 #include "common/c_converter.h"
24 #include "environment.h"
25 #include "mapgen/mapgen.h"
26 #include "lua_api/l_env.h"
28 #include "script/common/c_content.h"
31 void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp,
34 SCRIPTAPI_PRECHECKHEADER
36 // Get core.registered_on_generateds
37 lua_getglobal(L, "core");
38 lua_getfield(L, -1, "registered_on_generateds");
42 lua_pushnumber(L, blockseed);
43 runCallbacks(3, RUN_CALLBACKS_MODE_FIRST);
46 void ScriptApiEnv::environment_Step(float dtime)
48 SCRIPTAPI_PRECHECKHEADER
49 //infostream << "scriptapi_environment_step" << std::endl;
51 // Get core.registered_globalsteps
52 lua_getglobal(L, "core");
53 lua_getfield(L, -1, "registered_globalsteps");
55 lua_pushnumber(L, dtime);
56 runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
59 void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &type)
61 SCRIPTAPI_PRECHECKHEADER
66 // Get minetest.registered_playerevents
67 lua_getglobal(L, "minetest");
68 lua_getfield(L, -1, "registered_playerevents");
71 objectrefGetOrCreate(L, player); // player
72 lua_pushstring(L,type.c_str()); // event type
73 runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
76 void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
78 SCRIPTAPI_PRECHECKHEADER
79 verbosestream << "ScriptApiEnv: Environment initialized" << std::endl;
83 Add {Loading,Active}BlockModifiers to environment
86 // Get core.registered_abms
87 lua_getglobal(L, "core");
88 lua_getfield(L, -1, "registered_abms");
89 int registered_abms = lua_gettop(L);
91 if (!lua_istable(L, registered_abms)) {
93 throw LuaError("core.registered_abms was not a lua table, as expected.");
96 while (lua_next(L, registered_abms)) {
97 // key at index -2 and value at index -1
98 int id = lua_tonumber(L, -2);
99 int current_abm = lua_gettop(L);
101 std::vector<std::string> trigger_contents;
102 lua_getfield(L, current_abm, "nodenames");
103 if (lua_istable(L, -1)) {
104 int table = lua_gettop(L);
106 while (lua_next(L, table)) {
107 // key at index -2 and value at index -1
108 luaL_checktype(L, -1, LUA_TSTRING);
109 trigger_contents.emplace_back(readParam<std::string>(L, -1));
110 // removes value, keeps key for next iteration
113 } else if (lua_isstring(L, -1)) {
114 trigger_contents.emplace_back(readParam<std::string>(L, -1));
118 std::vector<std::string> required_neighbors;
119 lua_getfield(L, current_abm, "neighbors");
120 if (lua_istable(L, -1)) {
121 int table = lua_gettop(L);
123 while (lua_next(L, table)) {
124 // key at index -2 and value at index -1
125 luaL_checktype(L, -1, LUA_TSTRING);
126 required_neighbors.emplace_back(readParam<std::string>(L, -1));
127 // removes value, keeps key for next iteration
130 } else if (lua_isstring(L, -1)) {
131 required_neighbors.emplace_back(readParam<std::string>(L, -1));
135 float trigger_interval = 10.0;
136 getfloatfield(L, current_abm, "interval", trigger_interval);
138 int trigger_chance = 50;
139 getintfield(L, current_abm, "chance", trigger_chance);
141 bool simple_catch_up = true;
142 getboolfield(L, current_abm, "catch_up", simple_catch_up);
144 s16 min_y = INT16_MIN;
145 getintfield(L, current_abm, "min_y", min_y);
147 s16 max_y = INT16_MAX;
148 getintfield(L, current_abm, "max_y", max_y);
150 lua_getfield(L, current_abm, "action");
151 luaL_checktype(L, current_abm + 1, LUA_TFUNCTION);
154 LuaABM *abm = new LuaABM(L, id, trigger_contents, required_neighbors,
155 trigger_interval, trigger_chance, simple_catch_up, min_y, max_y);
157 env->addActiveBlockModifier(abm);
159 // removes value, keeps key for next iteration
164 // Get core.registered_lbms
165 lua_getglobal(L, "core");
166 lua_getfield(L, -1, "registered_lbms");
167 int registered_lbms = lua_gettop(L);
169 if (!lua_istable(L, registered_lbms)) {
171 throw LuaError("core.registered_lbms was not a lua table, as expected.");
175 while (lua_next(L, registered_lbms)) {
176 // key at index -2 and value at index -1
177 int id = lua_tonumber(L, -2);
178 int current_lbm = lua_gettop(L);
180 std::set<std::string> trigger_contents;
181 lua_getfield(L, current_lbm, "nodenames");
182 if (lua_istable(L, -1)) {
183 int table = lua_gettop(L);
185 while (lua_next(L, table)) {
186 // key at index -2 and value at index -1
187 luaL_checktype(L, -1, LUA_TSTRING);
188 trigger_contents.insert(readParam<std::string>(L, -1));
189 // removes value, keeps key for next iteration
192 } else if (lua_isstring(L, -1)) {
193 trigger_contents.insert(readParam<std::string>(L, -1));
198 getstringfield(L, current_lbm, "name", name);
200 bool run_at_every_load = getboolfield_default(L, current_lbm,
201 "run_at_every_load", false);
203 lua_getfield(L, current_lbm, "action");
204 luaL_checktype(L, current_lbm + 1, LUA_TFUNCTION);
207 LuaLBM *lbm = new LuaLBM(L, id, trigger_contents, name,
210 env->addLoadingBlockModifierDef(lbm);
212 // removes value, keeps key for next iteration
218 void ScriptApiEnv::on_emerge_area_completion(
219 v3s16 blockpos, int action, ScriptCallbackState *state)
221 Server *server = getServer();
223 // This function should be executed with envlock held.
224 // The caller (LuaEmergeAreaCallback in src/script/lua_api/l_env.cpp)
225 // should have obtained the lock.
226 // Note that the order of these locks is important! Envlock must *ALWAYS*
227 // be acquired before attempting to acquire scriptlock, or else ServerThread
228 // will try to acquire scriptlock after it already owns envlock, thus
229 // deadlocking EmergeThread and ServerThread
231 SCRIPTAPI_PRECHECKHEADER
233 int error_handler = PUSH_ERROR_HANDLER(L);
235 lua_rawgeti(L, LUA_REGISTRYINDEX, state->callback_ref);
236 luaL_checktype(L, -1, LUA_TFUNCTION);
238 push_v3s16(L, blockpos);
239 lua_pushinteger(L, action);
240 lua_pushinteger(L, state->refcount);
241 lua_rawgeti(L, LUA_REGISTRYINDEX, state->args_ref);
243 setOriginDirect(state->origin.c_str());
246 PCALL_RES(lua_pcall(L, 4, 0, error_handler));
247 } catch (LuaError &e) {
248 // Note: don't throw here, we still need to run the cleanup code below
249 server->setAsyncFatalError(e);
252 lua_pop(L, 1); // Pop error handler
254 if (state->refcount == 0) {
255 luaL_unref(L, LUA_REGISTRYINDEX, state->callback_ref);
256 luaL_unref(L, LUA_REGISTRYINDEX, state->args_ref);
260 void ScriptApiEnv::check_for_falling(v3s16 p)
262 SCRIPTAPI_PRECHECKHEADER
264 int error_handler = PUSH_ERROR_HANDLER(L);
265 lua_getglobal(L, "core");
266 lua_getfield(L, -1, "check_for_falling");
267 luaL_checktype(L, -1, LUA_TFUNCTION);
269 PCALL_RES(lua_pcall(L, 1, 0, error_handler));
272 void ScriptApiEnv::on_liquid_transformed(
273 const std::vector<std::pair<v3s16, MapNode>> &list)
275 SCRIPTAPI_PRECHECKHEADER
277 // Get core.registered_on_liquid_transformed
278 lua_getglobal(L, "core");
279 lua_getfield(L, -1, "registered_on_liquid_transformed");
280 luaL_checktype(L, -1, LUA_TTABLE);
283 // Skip converting list and calling hook if there are
284 // no registered callbacks.
285 if(lua_objlen(L, -1) < 1) return;
287 // Convert the list to a pos array and a node array for lua
289 lua_createtable(L, list.size(), 0);
290 lua_createtable(L, list.size(), 0);
291 for(std::pair<v3s16, MapNode> p : list) {
292 lua_pushnumber(L, index);
293 push_v3s16(L, p.first);
295 lua_pushnumber(L, index++);
296 pushnode(L, p.second);
300 runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);