]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/cpp_api/scriptapi.cpp
Move scriptapi to separate folder (by sapier)
[dragonfireclient.git] / src / script / cpp_api / scriptapi.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 extern "C" {
21 #include "lua.h"
22 #include "lauxlib.h"
23 #include "lualib.h"
24 }
25
26
27 #include "scriptapi.h"
28 #include "common/c_converter.h"
29 #include "lua_api/l_base.h"
30 #include "log.h"
31 #include "mods.h"
32
33 int script_ErrorHandler(lua_State *L) {
34         lua_getfield(L, LUA_GLOBALSINDEX, "debug");
35         if (!lua_istable(L, -1)) {
36                 lua_pop(L, 1);
37                 return 1;
38         }
39         lua_getfield(L, -1, "traceback");
40         if (!lua_isfunction(L, -1)) {
41                 lua_pop(L, 2);
42                 return 1;
43         }
44         lua_pushvalue(L, 1);
45         lua_pushinteger(L, 2);
46         lua_call(L, 2, 1);
47         return 1;
48 }
49
50
51 bool ScriptApi::getAuth(const std::string &playername,
52                 std::string *dst_password, std::set<std::string> *dst_privs)
53 {
54         SCRIPTAPI_PRECHECKHEADER
55
56         getAuthHandler();
57         lua_getfield(L, -1, "get_auth");
58         if(lua_type(L, -1) != LUA_TFUNCTION)
59                 throw LuaError(L, "Authentication handler missing get_auth");
60         lua_pushstring(L, playername.c_str());
61         if(lua_pcall(L, 1, 1, 0))
62                 scriptError("error: %s", lua_tostring(L, -1));
63
64         // nil = login not allowed
65         if(lua_isnil(L, -1))
66                 return false;
67         luaL_checktype(L, -1, LUA_TTABLE);
68
69         std::string password;
70         bool found = getstringfield(L, -1, "password", password);
71         if(!found)
72                 throw LuaError(L, "Authentication handler didn't return password");
73         if(dst_password)
74                 *dst_password = password;
75
76         lua_getfield(L, -1, "privileges");
77         if(!lua_istable(L, -1))
78                 throw LuaError(L,
79                                 "Authentication handler didn't return privilege table");
80         if(dst_privs)
81                 readPrivileges(-1, *dst_privs);
82         lua_pop(L, 1);
83
84         return true;
85 }
86
87 void ScriptApi::getAuthHandler()
88 {
89         lua_State *L = getStack();
90
91         lua_getglobal(L, "minetest");
92         lua_getfield(L, -1, "registered_auth_handler");
93         if(lua_isnil(L, -1)){
94                 lua_pop(L, 1);
95                 lua_getfield(L, -1, "builtin_auth_handler");
96         }
97         if(lua_type(L, -1) != LUA_TTABLE)
98                 throw LuaError(L, "Authentication handler table not valid");
99 }
100
101 void ScriptApi::readPrivileges(int index,std::set<std::string> &result)
102 {
103         lua_State *L = getStack();
104
105         result.clear();
106         lua_pushnil(L);
107         if(index < 0)
108                 index -= 1;
109         while(lua_next(L, index) != 0){
110                 // key at index -2 and value at index -1
111                 std::string key = luaL_checkstring(L, -2);
112                 bool value = lua_toboolean(L, -1);
113                 if(value)
114                         result.insert(key);
115                 // removes value, keeps key for next iteration
116                 lua_pop(L, 1);
117         }
118 }
119
120 void ScriptApi::createAuth(const std::string &playername,
121                 const std::string &password)
122 {
123         SCRIPTAPI_PRECHECKHEADER
124
125         getAuthHandler();
126         lua_getfield(L, -1, "create_auth");
127         if(lua_type(L, -1) != LUA_TFUNCTION)
128                 throw LuaError(L, "Authentication handler missing create_auth");
129         lua_pushstring(L, playername.c_str());
130         lua_pushstring(L, password.c_str());
131         if(lua_pcall(L, 2, 0, 0))
132                 scriptError("error: %s", lua_tostring(L, -1));
133 }
134
135 bool ScriptApi::setPassword(const std::string &playername,
136                 const std::string &password)
137 {
138         SCRIPTAPI_PRECHECKHEADER
139
140         getAuthHandler();
141         lua_getfield(L, -1, "set_password");
142         if(lua_type(L, -1) != LUA_TFUNCTION)
143                 throw LuaError(L, "Authentication handler missing set_password");
144         lua_pushstring(L, playername.c_str());
145         lua_pushstring(L, password.c_str());
146         if(lua_pcall(L, 2, 1, 0))
147                 scriptError("error: %s", lua_tostring(L, -1));
148         return lua_toboolean(L, -1);
149 }
150
151 bool ScriptApi::on_chat_message(const std::string &name,
152                 const std::string &message)
153 {
154         SCRIPTAPI_PRECHECKHEADER
155
156         // Get minetest.registered_on_chat_messages
157         lua_getglobal(L, "minetest");
158         lua_getfield(L, -1, "registered_on_chat_messages");
159         // Call callbacks
160         lua_pushstring(L, name.c_str());
161         lua_pushstring(L, message.c_str());
162         runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC);
163         bool ate = lua_toboolean(L, -1);
164         return ate;
165 }
166
167 void ScriptApi::on_shutdown()
168 {
169         SCRIPTAPI_PRECHECKHEADER
170
171         // Get registered shutdown hooks
172         lua_getglobal(L, "minetest");
173         lua_getfield(L, -1, "registered_on_shutdown");
174         // Call callbacks
175         runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
176 }
177
178 bool ScriptApi::loadMod(const std::string &scriptpath,const std::string &modname)
179 {
180         ModNameStorer modnamestorer(getStack(), modname);
181
182         if(!string_allowed(modname, MODNAME_ALLOWED_CHARS)){
183                 errorstream<<"Error loading mod \""<<modname
184                                 <<"\": modname does not follow naming conventions: "
185                                 <<"Only chararacters [a-z0-9_] are allowed."<<std::endl;
186                 return false;
187         }
188
189         bool success = false;
190
191         try{
192                 success = scriptLoad(scriptpath.c_str());
193         }
194         catch(LuaError &e){
195                 errorstream<<"Error loading mod \""<<modname
196                                 <<"\": "<<e.what()<<std::endl;
197         }
198
199         return success;
200 }
201
202 ScriptApi::ScriptApi() {
203         assert("Invalid call to default constructor of scriptapi!" == 0);
204 }
205
206 ScriptApi::ScriptApi(Server* server)
207 {
208
209         setServer(server);
210         setStack(luaL_newstate());
211         assert(getStack());
212
213         //TODO add security
214
215         luaL_openlibs(getStack());
216
217         SCRIPTAPI_PRECHECKHEADER
218
219         lua_pushlightuserdata(L, this);
220         lua_setfield(L, LUA_REGISTRYINDEX, "scriptapi");
221
222         lua_newtable(L);
223         lua_setglobal(L, "minetest");
224
225
226         for (std::vector<ModApiBase*>::iterator i = m_mod_api_modules->begin();
227                         i != m_mod_api_modules->end(); i++) {
228                 //initializers are called within minetest global table!
229                 lua_getglobal(L, "minetest");
230                 int top = lua_gettop(L);
231                 bool ModInitializedSuccessfull = (*i)->Initialize(L,top);
232                 assert(ModInitializedSuccessfull);
233         }
234
235         infostream << "SCRIPTAPI: initialized " << m_mod_api_modules->size()
236                                                                                                         << " modules" << std::endl;
237
238         // Get the main minetest table
239         lua_getglobal(L, "minetest");
240
241         // Add tables to minetest
242         lua_newtable(L);
243         lua_setfield(L, -2, "object_refs");
244
245         lua_newtable(L);
246         lua_setfield(L, -2, "luaentities");
247 }
248
249 ScriptApi::~ScriptApi() {
250         lua_close(getStack());
251 }
252
253 bool ScriptApi::scriptLoad(const char *path)
254 {
255         lua_State* L = getStack();
256         setStack(0);
257
258         verbosestream<<"Loading and running script from "<<path<<std::endl;
259
260         lua_pushcfunction(L, script_ErrorHandler);
261         int errorhandler = lua_gettop(L);
262
263         int ret = luaL_loadfile(L, path) || lua_pcall(L, 0, 0, errorhandler);
264         if(ret){
265                 errorstream<<"========== ERROR FROM LUA ==========="<<std::endl;
266                 errorstream<<"Failed to load and run script from "<<std::endl;
267                 errorstream<<path<<":"<<std::endl;
268                 errorstream<<std::endl;
269                 errorstream<<lua_tostring(L, -1)<<std::endl;
270                 errorstream<<std::endl;
271                 errorstream<<"=======END OF ERROR FROM LUA ========"<<std::endl;
272                 lua_pop(L, 1); // Pop error message from stack
273                 lua_pop(L, 1); // Pop the error handler from stack
274                 return false;
275         }
276         lua_pop(L, 1); // Pop the error handler from stack
277         return true;
278 }
279
280 bool ScriptApi::registerModApiModule(ModApiBase* ptr) {
281         if (ScriptApi::m_mod_api_modules == 0)
282                 ScriptApi::m_mod_api_modules = new std::vector<ModApiBase*>();
283
284         assert(ScriptApi::m_mod_api_modules != 0);
285
286         ScriptApi::m_mod_api_modules->push_back(ptr);
287
288         return true;
289 }
290
291 std::vector<ModApiBase*>* ScriptApi::m_mod_api_modules = 0;