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"
29 void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp,
32 SCRIPTAPI_PRECHECKHEADER
34 // Get core.registered_on_generateds
35 lua_getglobal(L, "core");
36 lua_getfield(L, -1, "registered_on_generateds");
40 lua_pushnumber(L, blockseed);
41 runCallbacks(3, RUN_CALLBACKS_MODE_FIRST);
44 void ScriptApiEnv::environment_Step(float dtime)
46 SCRIPTAPI_PRECHECKHEADER
47 //infostream << "scriptapi_environment_step" << std::endl;
49 // Get core.registered_globalsteps
50 lua_getglobal(L, "core");
51 lua_getfield(L, -1, "registered_globalsteps");
53 lua_pushnumber(L, dtime);
55 runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
56 } catch (LuaError &e) {
57 getServer()->setAsyncFatalError(
58 std::string("environment_Step: ") + e.what() + "\n"
59 + script_get_backtrace(L));
63 void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &type)
65 SCRIPTAPI_PRECHECKHEADER
70 // Get minetest.registered_playerevents
71 lua_getglobal(L, "minetest");
72 lua_getfield(L, -1, "registered_playerevents");
75 objectrefGetOrCreate(L, player); // player
76 lua_pushstring(L,type.c_str()); // event type
78 runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
79 } catch (LuaError &e) {
80 getServer()->setAsyncFatalError(
81 std::string("player_event: ") + e.what() + "\n"
82 + script_get_backtrace(L) );
86 void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
88 SCRIPTAPI_PRECHECKHEADER
89 verbosestream << "ScriptApiEnv: Environment initialized" << std::endl;
93 Add {Loading,Active}BlockModifiers to environment
96 // Get core.registered_abms
97 lua_getglobal(L, "core");
98 lua_getfield(L, -1, "registered_abms");
99 int registered_abms = lua_gettop(L);
101 if (!lua_istable(L, registered_abms)) {
103 throw LuaError("core.registered_abms was not a lua table, as expected.");
106 while (lua_next(L, registered_abms)) {
107 // key at index -2 and value at index -1
108 int id = lua_tonumber(L, -2);
109 int current_abm = lua_gettop(L);
111 std::vector<std::string> trigger_contents;
112 lua_getfield(L, current_abm, "nodenames");
113 if (lua_istable(L, -1)) {
114 int table = lua_gettop(L);
116 while (lua_next(L, table)) {
117 // key at index -2 and value at index -1
118 luaL_checktype(L, -1, LUA_TSTRING);
119 trigger_contents.emplace_back(readParam<std::string>(L, -1));
120 // removes value, keeps key for next iteration
123 } else if (lua_isstring(L, -1)) {
124 trigger_contents.emplace_back(readParam<std::string>(L, -1));
128 std::vector<std::string> required_neighbors;
129 lua_getfield(L, current_abm, "neighbors");
130 if (lua_istable(L, -1)) {
131 int table = lua_gettop(L);
133 while (lua_next(L, table)) {
134 // key at index -2 and value at index -1
135 luaL_checktype(L, -1, LUA_TSTRING);
136 required_neighbors.emplace_back(readParam<std::string>(L, -1));
137 // removes value, keeps key for next iteration
140 } else if (lua_isstring(L, -1)) {
141 required_neighbors.emplace_back(readParam<std::string>(L, -1));
145 float trigger_interval = 10.0;
146 getfloatfield(L, current_abm, "interval", trigger_interval);
148 int trigger_chance = 50;
149 getintfield(L, current_abm, "chance", trigger_chance);
151 bool simple_catch_up = true;
152 getboolfield(L, current_abm, "catch_up", simple_catch_up);
154 lua_getfield(L, current_abm, "action");
155 luaL_checktype(L, current_abm + 1, LUA_TFUNCTION);
158 LuaABM *abm = new LuaABM(L, id, trigger_contents, required_neighbors,
159 trigger_interval, trigger_chance, simple_catch_up);
161 env->addActiveBlockModifier(abm);
163 // removes value, keeps key for next iteration
168 // Get core.registered_lbms
169 lua_getglobal(L, "core");
170 lua_getfield(L, -1, "registered_lbms");
171 int registered_lbms = lua_gettop(L);
173 if (!lua_istable(L, registered_lbms)) {
175 throw LuaError("core.registered_lbms was not a lua table, as expected.");
179 while (lua_next(L, registered_lbms)) {
180 // key at index -2 and value at index -1
181 int id = lua_tonumber(L, -2);
182 int current_lbm = lua_gettop(L);
184 std::set<std::string> trigger_contents;
185 lua_getfield(L, current_lbm, "nodenames");
186 if (lua_istable(L, -1)) {
187 int table = lua_gettop(L);
189 while (lua_next(L, table)) {
190 // key at index -2 and value at index -1
191 luaL_checktype(L, -1, LUA_TSTRING);
192 trigger_contents.insert(readParam<std::string>(L, -1));
193 // removes value, keeps key for next iteration
196 } else if (lua_isstring(L, -1)) {
197 trigger_contents.insert(readParam<std::string>(L, -1));
202 getstringfield(L, current_lbm, "name", name);
204 bool run_at_every_load = getboolfield_default(L, current_lbm,
205 "run_at_every_load", false);
207 lua_getfield(L, current_lbm, "action");
208 luaL_checktype(L, current_lbm + 1, LUA_TFUNCTION);
211 LuaLBM *lbm = new LuaLBM(L, id, trigger_contents, name,
214 env->addLoadingBlockModifierDef(lbm);
216 // removes value, keeps key for next iteration
222 void ScriptApiEnv::on_emerge_area_completion(
223 v3s16 blockpos, int action, ScriptCallbackState *state)
225 Server *server = getServer();
227 // This function should be executed with envlock held.
228 // The caller (LuaEmergeAreaCallback in src/script/lua_api/l_env.cpp)
229 // should have obtained the lock.
230 // Note that the order of these locks is important! Envlock must *ALWAYS*
231 // be acquired before attempting to acquire scriptlock, or else ServerThread
232 // will try to acquire scriptlock after it already owns envlock, thus
233 // deadlocking EmergeThread and ServerThread
235 SCRIPTAPI_PRECHECKHEADER
237 int error_handler = PUSH_ERROR_HANDLER(L);
239 lua_rawgeti(L, LUA_REGISTRYINDEX, state->callback_ref);
240 luaL_checktype(L, -1, LUA_TFUNCTION);
242 push_v3s16(L, blockpos);
243 lua_pushinteger(L, action);
244 lua_pushinteger(L, state->refcount);
245 lua_rawgeti(L, LUA_REGISTRYINDEX, state->args_ref);
247 setOriginDirect(state->origin.c_str());
250 PCALL_RES(lua_pcall(L, 4, 0, error_handler));
251 } catch (LuaError &e) {
252 server->setAsyncFatalError(
253 std::string("on_emerge_area_completion: ") + e.what() + "\n"
254 + script_get_backtrace(L));
257 lua_pop(L, 1); // Pop error handler
259 if (state->refcount == 0) {
260 luaL_unref(L, LUA_REGISTRYINDEX, state->callback_ref);
261 luaL_unref(L, LUA_REGISTRYINDEX, state->args_ref);