1 /*
2 script/lua_api/l_util.cpp
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 */
5
6 /*
7 This file is part of Freeminer.
8
9 Freeminer is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Freeminer is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "lua_api/l_util.h"
24 #include "lua_api/l_internal.h"
25 #include "common/c_converter.h"
26 #include "common/c_content.h"
27 #include "cpp_api/s_async.h"
28 #include "serialization.h"
29 #include "json/json.h"
30 #include "debug.h"
31 #include "porting.h"
32 #include "log.h"
33 #include "tool.h"
34 #include "filesys.h"
35 #include "settings.h"
36 #include "main.h" //required for g_settings, g_settings_path
37
38 // debug(...)
39 // Writes a line to dstream
l_debug(lua_State * L)40 int ModApiUtil::l_debug(lua_State *L)
41 {
42 NO_MAP_LOCK_REQUIRED;
43 // Handle multiple parameters to behave like standard lua print()
44 int n = lua_gettop(L);
45 lua_getglobal(L, "tostring");
46 for (int i = 1; i <= n; i++) {
47 /*
48 Call tostring(i-th argument).
49 This is what print() does, and it behaves a bit
50 differently from directly calling lua_tostring.
51 */
52 lua_pushvalue(L, -1); /* function to be called */
53 lua_pushvalue(L, i); /* value to print */
54 lua_call(L, 1, 1);
55 size_t len;
56 const char *s = lua_tolstring(L, -1, &len);
57 if (i > 1)
58 dstream << "\t";
59 if (s)
60 dstream << std::string(s, len);
61 lua_pop(L, 1);
62 }
63 dstream << std::endl;
64 return 0;
65 }
66
67 // log([level,] text)
68 // Writes a line to the logger.
69 // The one-argument version logs to infostream.
70 // The two-argument version accept a log level: error, action, info, or verbose.
l_log(lua_State * L)71 int ModApiUtil::l_log(lua_State *L)
72 {
73 NO_MAP_LOCK_REQUIRED;
74 std::string text;
75 LogMessageLevel level = LMT_INFO;
76 if (lua_isnone(L, 2)) {
77 text = lua_tostring(L, 1);
78 }
79 else {
80 std::string levelname = luaL_checkstring(L, 1);
81 text = luaL_checkstring(L, 2);
82 if(levelname == "error")
83 level = LMT_ERROR;
84 else if(levelname == "action")
85 level = LMT_ACTION;
86 else if(levelname == "verbose")
87 level = LMT_VERBOSE;
88 else if (levelname == "deprecated") {
89 log_deprecated(L,text);
90 return 0;
91 }
92
93 }
94 log_printline(level, text);
95 return 0;
96 }
97
98 // setting_set(name, value)
l_setting_set(lua_State * L)99 int ModApiUtil::l_setting_set(lua_State *L)
100 {
101 NO_MAP_LOCK_REQUIRED;
102 const char *name = luaL_checkstring(L, 1);
103 const char *value = luaL_checkstring(L, 2);
104 g_settings->set(name, value);
105 return 0;
106 }
107
108 // setting_get(name)
l_setting_get(lua_State * L)109 int ModApiUtil::l_setting_get(lua_State *L)
110 {
111 NO_MAP_LOCK_REQUIRED;
112 const char *name = luaL_checkstring(L, 1);
113 try{
114 std::string value = g_settings->get(name);
115 lua_pushstring(L, value.c_str());
116 } catch(SettingNotFoundException &e){
117 lua_pushnil(L);
118 }
119 return 1;
120 }
121
122 // setting_setbool(name)
l_setting_setbool(lua_State * L)123 int ModApiUtil::l_setting_setbool(lua_State *L)
124 {
125 NO_MAP_LOCK_REQUIRED;
126 const char *name = luaL_checkstring(L, 1);
127 bool value = lua_toboolean(L, 2);
128 g_settings->setBool(name, value);
129 return 0;
130 }
131
132 // setting_getbool(name)
l_setting_getbool(lua_State * L)133 int ModApiUtil::l_setting_getbool(lua_State *L)
134 {
135 NO_MAP_LOCK_REQUIRED;
136 const char *name = luaL_checkstring(L, 1);
137 try{
138 bool value = g_settings->getBool(name);
139 lua_pushboolean(L, value);
140 } catch(SettingNotFoundException &e){
141 lua_pushnil(L);
142 }
143 return 1;
144 }
145
146 // setting_save()
l_setting_save(lua_State * L)147 int ModApiUtil::l_setting_save(lua_State *L)
148 {
149 NO_MAP_LOCK_REQUIRED;
150 if(g_settings_path != "")
151 g_settings->updateConfigFile(g_settings_path.c_str());
152 return 0;
153 }
154
155 // parse_json(str[, nullvalue])
l_parse_json(lua_State * L)156 int ModApiUtil::l_parse_json(lua_State *L)
157 {
158 NO_MAP_LOCK_REQUIRED;
159
160 const char *jsonstr = luaL_checkstring(L, 1);
161
162 // Use passed nullvalue or default to nil
163 int nullindex = 2;
164 if (lua_isnone(L, nullindex)) {
165 lua_pushnil(L);
166 nullindex = lua_gettop(L);
167 }
168
169 Json::Value root;
170
171 {
172 Json::Reader reader;
173 std::istringstream stream(jsonstr);
174
175 if (!reader.parse(stream, root)) {
176 errorstream << "Failed to parse json data "
177 << reader.getFormattedErrorMessages();
178 errorstream << "data: \"" << jsonstr << "\""
179 << std::endl;
180 lua_pushnil(L);
181 return 1;
182 }
183 }
184
185 if (!push_json_value(L, root, nullindex)) {
186 errorstream << "Failed to parse json data, "
187 << "depth exceeds lua stack limit" << std::endl;
188 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
189 lua_pushnil(L);
190 }
191 return 1;
192 }
193
194 // write_json(data[, styled]) -> string or nil and error message
l_write_json(lua_State * L)195 int ModApiUtil::l_write_json(lua_State *L)
196 {
197 NO_MAP_LOCK_REQUIRED;
198
199 bool styled = false;
200 if (!lua_isnone(L, 2)) {
201 styled = lua_toboolean(L, 2);
202 lua_pop(L, 1);
203 }
204
205 Json::Value root;
206 try {
207 read_json_value(L, root, 1);
208 } catch (SerializationError &e) {
209 lua_pushnil(L);
210 lua_pushstring(L, e.what());
211 return 2;
212 }
213
214 std::string out;
215 if (styled) {
216 Json::StyledWriter writer;
217 out = writer.write(root);
218 } else {
219 Json::FastWriter writer;
220 out = writer.write(root);
221 }
222 lua_pushlstring(L, out.c_str(), out.size());
223 return 1;
224 }
225
226 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
l_get_dig_params(lua_State * L)227 int ModApiUtil::l_get_dig_params(lua_State *L)
228 {
229 NO_MAP_LOCK_REQUIRED;
230 std::map<std::string, int> groups;
231 read_groups(L, 1, groups);
232 ToolCapabilities tp = read_tool_capabilities(L, 2);
233 if(lua_isnoneornil(L, 3))
234 push_dig_params(L, getDigParams(groups, &tp));
235 else
236 push_dig_params(L, getDigParams(groups, &tp,
237 luaL_checknumber(L, 3)));
238 return 1;
239 }
240
241 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
l_get_hit_params(lua_State * L)242 int ModApiUtil::l_get_hit_params(lua_State *L)
243 {
244 NO_MAP_LOCK_REQUIRED;
245 std::map<std::string, int> groups;
246 read_groups(L, 1, groups);
247 ToolCapabilities tp = read_tool_capabilities(L, 2);
248 if(lua_isnoneornil(L, 3))
249 push_hit_params(L, getHitParams(groups, &tp));
250 else
251 push_hit_params(L, getHitParams(groups, &tp,
252 luaL_checknumber(L, 3)));
253 return 1;
254 }
255
256 // get_password_hash(name, raw_password)
l_get_password_hash(lua_State * L)257 int ModApiUtil::l_get_password_hash(lua_State *L)
258 {
259 NO_MAP_LOCK_REQUIRED;
260 std::string name = luaL_checkstring(L, 1);
261 std::string raw_password = luaL_checkstring(L, 2);
262 std::string hash = translatePassword(name,
263 narrow_to_wide(raw_password));
264 lua_pushstring(L, hash.c_str());
265 return 1;
266 }
267
268 // is_yes(arg)
l_is_yes(lua_State * L)269 int ModApiUtil::l_is_yes(lua_State *L)
270 {
271 NO_MAP_LOCK_REQUIRED;
272
273 lua_getglobal(L, "tostring"); // function to be called
274 lua_pushvalue(L, 1); // 1st argument
275 lua_call(L, 1, 1); // execute function
276 std::string str(lua_tostring(L, -1)); // get result
277 lua_pop(L, 1);
278
279 bool yes = is_yes(str);
280 lua_pushboolean(L, yes);
281 return 1;
282 }
283
l_get_builtin_path(lua_State * L)284 int ModApiUtil::l_get_builtin_path(lua_State *L)
285 {
286 std::string path = porting::path_share + DIR_DELIM + "builtin";
287 lua_pushstring(L, path.c_str());
288 return 1;
289 }
290
291 // compress(data, method, level)
l_compress(lua_State * L)292 int ModApiUtil::l_compress(lua_State *L)
293 {
294 size_t size;
295 const char *data = luaL_checklstring(L, 1, &size);
296
297 int level = -1;
298 if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
299 level = luaL_checknumber(L, 3);
300
301 std::ostringstream os;
302 compressZlib(std::string(data, size), os, level);
303
304 std::string out = os.str();
305
306 lua_pushlstring(L, out.data(), out.size());
307 return 1;
308 }
309
310 // decompress(data, method)
l_decompress(lua_State * L)311 int ModApiUtil::l_decompress(lua_State *L)
312 {
313 size_t size;
314 const char * data = luaL_checklstring(L, 1, &size);
315
316 std::istringstream is(std::string(data, size));
317 std::ostringstream os;
318 decompressZlib(is, os);
319
320 std::string out = os.str();
321
322 lua_pushlstring(L, out.data(), out.size());
323 return 1;
324 }
325
Initialize(lua_State * L,int top)326 void ModApiUtil::Initialize(lua_State *L, int top)
327 {
328 API_FCT(debug);
329 API_FCT(log);
330
331 API_FCT(setting_set);
332 API_FCT(setting_get);
333 API_FCT(setting_setbool);
334 API_FCT(setting_getbool);
335 API_FCT(setting_save);
336
337 API_FCT(parse_json);
338 API_FCT(write_json);
339
340 API_FCT(get_dig_params);
341 API_FCT(get_hit_params);
342
343 API_FCT(get_password_hash);
344
345 API_FCT(is_yes);
346
347 API_FCT(get_builtin_path);
348
349 API_FCT(compress);
350 API_FCT(decompress);
351 }
352
InitializeAsync(AsyncEngine & engine)353 void ModApiUtil::InitializeAsync(AsyncEngine& engine)
354 {
355 ASYNC_API_FCT(debug);
356 ASYNC_API_FCT(log);
357
358 //ASYNC_API_FCT(setting_set);
359 ASYNC_API_FCT(setting_get);
360 //ASYNC_API_FCT(setting_setbool);
361 ASYNC_API_FCT(setting_getbool);
362 //ASYNC_API_FCT(setting_save);
363
364 ASYNC_API_FCT(parse_json);
365 ASYNC_API_FCT(write_json);
366
367 ASYNC_API_FCT(is_yes);
368
369 ASYNC_API_FCT(get_builtin_path);
370
371 ASYNC_API_FCT(compress);
372 ASYNC_API_FCT(decompress);
373 }
374
375