Line data Source code
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 : #include "common/c_content.h"
20 : #include "common/c_converter.h"
21 : #include "common/c_types.h"
22 : #include "nodedef.h"
23 : #include "itemdef.h"
24 : #include "object_properties.h"
25 : #include "cpp_api/s_node.h"
26 : #include "lua_api/l_object.h"
27 : #include "lua_api/l_item.h"
28 : #include "common/c_internal.h"
29 : #include "server.h"
30 : #include "log.h"
31 : #include "tool.h"
32 : #include "serverobject.h"
33 : #include "porting.h"
34 : #include "mg_schematic.h"
35 : #include "noise.h"
36 : #include "json/json.h"
37 :
38 : struct EnumString es_TileAnimationType[] =
39 : {
40 : {TAT_NONE, "none"},
41 : {TAT_VERTICAL_FRAMES, "vertical_frames"},
42 : {0, NULL},
43 : };
44 :
45 : /******************************************************************************/
46 0 : ItemDefinition read_item_definition(lua_State* L,int index,
47 : ItemDefinition default_def)
48 : {
49 0 : if(index < 0)
50 0 : index = lua_gettop(L) + 1 + index;
51 :
52 : // Read the item definition
53 0 : ItemDefinition def = default_def;
54 :
55 0 : def.type = (ItemType)getenumfield(L, index, "type",
56 0 : es_ItemType, ITEM_NONE);
57 0 : getstringfield(L, index, "name", def.name);
58 0 : getstringfield(L, index, "description", def.description);
59 0 : getstringfield(L, index, "inventory_image", def.inventory_image);
60 0 : getstringfield(L, index, "wield_image", def.wield_image);
61 :
62 0 : lua_getfield(L, index, "wield_scale");
63 0 : if(lua_istable(L, -1)){
64 0 : def.wield_scale = check_v3f(L, -1);
65 : }
66 0 : lua_pop(L, 1);
67 :
68 0 : def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
69 0 : if(def.stack_max == 0)
70 0 : def.stack_max = 1;
71 :
72 0 : lua_getfield(L, index, "on_use");
73 0 : def.usable = lua_isfunction(L, -1);
74 0 : lua_pop(L, 1);
75 :
76 0 : getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
77 :
78 0 : warn_if_field_exists(L, index, "tool_digging_properties",
79 0 : "deprecated: use tool_capabilities");
80 :
81 0 : lua_getfield(L, index, "tool_capabilities");
82 0 : if(lua_istable(L, -1)){
83 : def.tool_capabilities = new ToolCapabilities(
84 0 : read_tool_capabilities(L, -1));
85 : }
86 :
87 : // If name is "" (hand), ensure there are ToolCapabilities
88 : // because it will be looked up there whenever any other item has
89 : // no ToolCapabilities
90 0 : if(def.name == "" && def.tool_capabilities == NULL){
91 0 : def.tool_capabilities = new ToolCapabilities();
92 : }
93 :
94 0 : lua_getfield(L, index, "groups");
95 0 : read_groups(L, -1, def.groups);
96 0 : lua_pop(L, 1);
97 :
98 0 : lua_getfield(L, index, "sounds");
99 0 : if(lua_istable(L, -1)){
100 0 : lua_getfield(L, -1, "place");
101 0 : read_soundspec(L, -1, def.sound_place);
102 0 : lua_pop(L, 1);
103 : }
104 0 : lua_pop(L, 1);
105 :
106 0 : def.range = getfloatfield_default(L, index, "range", def.range);
107 :
108 : // Client shall immediately place this node when player places the item.
109 : // Server will update the precise end result a moment later.
110 : // "" = no prediction
111 0 : getstringfield(L, index, "node_placement_prediction",
112 0 : def.node_placement_prediction);
113 :
114 0 : return def;
115 : }
116 :
117 : /******************************************************************************/
118 0 : void read_object_properties(lua_State *L, int index,
119 : ObjectProperties *prop)
120 : {
121 0 : if(index < 0)
122 0 : index = lua_gettop(L) + 1 + index;
123 0 : if(!lua_istable(L, index))
124 0 : return;
125 :
126 0 : prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
127 :
128 0 : getboolfield(L, -1, "physical", prop->physical);
129 0 : getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
130 :
131 0 : getfloatfield(L, -1, "weight", prop->weight);
132 :
133 0 : lua_getfield(L, -1, "collisionbox");
134 0 : if(lua_istable(L, -1))
135 0 : prop->collisionbox = read_aabb3f(L, -1, 1.0);
136 0 : lua_pop(L, 1);
137 :
138 0 : getstringfield(L, -1, "visual", prop->visual);
139 :
140 0 : getstringfield(L, -1, "mesh", prop->mesh);
141 :
142 0 : lua_getfield(L, -1, "visual_size");
143 0 : if(lua_istable(L, -1))
144 0 : prop->visual_size = read_v2f(L, -1);
145 0 : lua_pop(L, 1);
146 :
147 0 : lua_getfield(L, -1, "textures");
148 0 : if(lua_istable(L, -1)){
149 0 : prop->textures.clear();
150 0 : int table = lua_gettop(L);
151 0 : lua_pushnil(L);
152 0 : while(lua_next(L, table) != 0){
153 : // key at index -2 and value at index -1
154 0 : if(lua_isstring(L, -1))
155 0 : prop->textures.push_back(lua_tostring(L, -1));
156 : else
157 0 : prop->textures.push_back("");
158 : // removes value, keeps key for next iteration
159 0 : lua_pop(L, 1);
160 : }
161 : }
162 0 : lua_pop(L, 1);
163 :
164 0 : lua_getfield(L, -1, "colors");
165 0 : if (lua_istable(L, -1)) {
166 0 : int table = lua_gettop(L);
167 0 : prop->colors.clear();
168 0 : for (lua_pushnil(L); lua_next(L, table); lua_pop(L, 1)) {
169 0 : video::SColor color(255, 255, 255, 255);
170 0 : read_color(L, -1, &color);
171 0 : prop->colors.push_back(color);
172 : }
173 : }
174 0 : lua_pop(L, 1);
175 :
176 0 : lua_getfield(L, -1, "spritediv");
177 0 : if(lua_istable(L, -1))
178 0 : prop->spritediv = read_v2s16(L, -1);
179 0 : lua_pop(L, 1);
180 :
181 0 : lua_getfield(L, -1, "initial_sprite_basepos");
182 0 : if(lua_istable(L, -1))
183 0 : prop->initial_sprite_basepos = read_v2s16(L, -1);
184 0 : lua_pop(L, 1);
185 :
186 0 : getboolfield(L, -1, "is_visible", prop->is_visible);
187 0 : getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
188 0 : getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
189 0 : if (getfloatfield(L, -1, "stepheight", prop->stepheight))
190 0 : prop->stepheight *= BS;
191 0 : lua_getfield(L, -1, "automatic_face_movement_dir");
192 0 : if (lua_isnumber(L, -1)) {
193 0 : prop->automatic_face_movement_dir = true;
194 0 : prop->automatic_face_movement_dir_offset = luaL_checknumber(L, -1);
195 0 : } else if (lua_isboolean(L, -1)) {
196 0 : prop->automatic_face_movement_dir = lua_toboolean(L, -1);
197 0 : prop->automatic_face_movement_dir_offset = 0.0;
198 : }
199 0 : lua_pop(L, 1);
200 : }
201 :
202 : /******************************************************************************/
203 0 : void push_object_properties(lua_State *L, ObjectProperties *prop)
204 : {
205 0 : lua_newtable(L);
206 0 : lua_pushnumber(L, prop->hp_max);
207 0 : lua_setfield(L, -2, "hp_max");
208 0 : lua_pushboolean(L, prop->physical);
209 0 : lua_setfield(L, -2, "physical");
210 0 : lua_pushboolean(L, prop->collideWithObjects);
211 0 : lua_setfield(L, -2, "collide_with_objects");
212 0 : lua_pushnumber(L, prop->weight);
213 0 : lua_setfield(L, -2, "weight");
214 0 : push_aabb3f(L, prop->collisionbox);
215 0 : lua_setfield(L, -2, "collisionbox");
216 0 : lua_pushlstring(L, prop->visual.c_str(), prop->visual.size());
217 0 : lua_setfield(L, -2, "visual");
218 0 : lua_pushlstring(L, prop->mesh.c_str(), prop->mesh.size());
219 0 : lua_setfield(L, -2, "mesh");
220 0 : push_v2f(L, prop->visual_size);
221 0 : lua_setfield(L, -2, "visual_size");
222 :
223 0 : lua_newtable(L);
224 0 : u16 i = 1;
225 0 : for (std::vector<std::string>::iterator it = prop->textures.begin();
226 0 : it != prop->textures.end(); ++it) {
227 0 : lua_pushlstring(L, it->c_str(), it->size());
228 0 : lua_rawseti(L, -2, i);
229 : }
230 0 : lua_setfield(L, -2, "textures");
231 :
232 0 : lua_newtable(L);
233 0 : i = 1;
234 0 : for (std::vector<video::SColor>::iterator it = prop->colors.begin();
235 0 : it != prop->colors.end(); ++it) {
236 0 : push_ARGB8(L, *it);
237 0 : lua_rawseti(L, -2, i);
238 : }
239 0 : lua_setfield(L, -2, "colors");
240 :
241 0 : push_v2s16(L, prop->spritediv);
242 0 : lua_setfield(L, -2, "spritediv");
243 0 : push_v2s16(L, prop->initial_sprite_basepos);
244 0 : lua_setfield(L, -2, "initial_sprite_basepos");
245 0 : lua_pushboolean(L, prop->is_visible);
246 0 : lua_setfield(L, -2, "is_visible");
247 0 : lua_pushboolean(L, prop->makes_footstep_sound);
248 0 : lua_setfield(L, -2, "makes_footstep_sound");
249 0 : lua_pushnumber(L, prop->automatic_rotate);
250 0 : lua_setfield(L, -2, "automatic_rotate");
251 0 : lua_pushnumber(L, prop->stepheight / BS);
252 0 : lua_setfield(L, -2, "stepheight");
253 0 : if (prop->automatic_face_movement_dir)
254 0 : lua_pushnumber(L, prop->automatic_face_movement_dir_offset);
255 : else
256 0 : lua_pushboolean(L, false);
257 0 : lua_setfield(L, -2, "automatic_face_movement_dir");
258 0 : }
259 :
260 : /******************************************************************************/
261 0 : TileDef read_tiledef(lua_State *L, int index)
262 : {
263 0 : if(index < 0)
264 0 : index = lua_gettop(L) + 1 + index;
265 :
266 0 : TileDef tiledef;
267 :
268 : // key at index -2 and value at index
269 0 : if(lua_isstring(L, index)){
270 : // "default_lava.png"
271 0 : tiledef.name = lua_tostring(L, index);
272 : }
273 0 : else if(lua_istable(L, index))
274 : {
275 : // {name="default_lava.png", animation={}}
276 0 : tiledef.name = "";
277 0 : getstringfield(L, index, "name", tiledef.name);
278 0 : getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
279 0 : tiledef.backface_culling = getboolfield_default(
280 0 : L, index, "backface_culling", true);
281 : // animation = {}
282 0 : lua_getfield(L, index, "animation");
283 0 : if(lua_istable(L, -1)){
284 : // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
285 : tiledef.animation.type = (TileAnimationType)
286 0 : getenumfield(L, -1, "type", es_TileAnimationType,
287 0 : TAT_NONE);
288 : tiledef.animation.aspect_w =
289 0 : getintfield_default(L, -1, "aspect_w", 16);
290 : tiledef.animation.aspect_h =
291 0 : getintfield_default(L, -1, "aspect_h", 16);
292 : tiledef.animation.length =
293 0 : getfloatfield_default(L, -1, "length", 1.0);
294 : }
295 0 : lua_pop(L, 1);
296 : }
297 :
298 0 : return tiledef;
299 : }
300 :
301 : /******************************************************************************/
302 0 : ContentFeatures read_content_features(lua_State *L, int index)
303 : {
304 0 : if(index < 0)
305 0 : index = lua_gettop(L) + 1 + index;
306 :
307 0 : ContentFeatures f;
308 :
309 : /* Cache existence of some callbacks */
310 0 : lua_getfield(L, index, "on_construct");
311 0 : if(!lua_isnil(L, -1)) f.has_on_construct = true;
312 0 : lua_pop(L, 1);
313 0 : lua_getfield(L, index, "on_destruct");
314 0 : if(!lua_isnil(L, -1)) f.has_on_destruct = true;
315 0 : lua_pop(L, 1);
316 0 : lua_getfield(L, index, "after_destruct");
317 0 : if(!lua_isnil(L, -1)) f.has_after_destruct = true;
318 0 : lua_pop(L, 1);
319 :
320 0 : lua_getfield(L, index, "on_rightclick");
321 0 : f.rightclickable = lua_isfunction(L, -1);
322 0 : lua_pop(L, 1);
323 :
324 : /* Name */
325 0 : getstringfield(L, index, "name", f.name);
326 :
327 : /* Groups */
328 0 : lua_getfield(L, index, "groups");
329 0 : read_groups(L, -1, f.groups);
330 0 : lua_pop(L, 1);
331 :
332 : /* Visual definition */
333 :
334 0 : f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype",
335 0 : ScriptApiNode::es_DrawType,NDT_NORMAL);
336 0 : getfloatfield(L, index, "visual_scale", f.visual_scale);
337 :
338 : /* Meshnode model filename */
339 0 : getstringfield(L, index, "mesh", f.mesh);
340 :
341 : // tiles = {}
342 0 : lua_getfield(L, index, "tiles");
343 : // If nil, try the deprecated name "tile_images" instead
344 0 : if(lua_isnil(L, -1)){
345 0 : lua_pop(L, 1);
346 0 : warn_if_field_exists(L, index, "tile_images",
347 0 : "Deprecated; new name is \"tiles\".");
348 0 : lua_getfield(L, index, "tile_images");
349 : }
350 0 : if(lua_istable(L, -1)){
351 0 : int table = lua_gettop(L);
352 0 : lua_pushnil(L);
353 0 : int i = 0;
354 0 : while(lua_next(L, table) != 0){
355 : // Read tiledef from value
356 0 : f.tiledef[i] = read_tiledef(L, -1);
357 : // removes value, keeps key for next iteration
358 0 : lua_pop(L, 1);
359 0 : i++;
360 0 : if(i==6){
361 0 : lua_pop(L, 1);
362 0 : break;
363 : }
364 : }
365 : // Copy last value to all remaining textures
366 0 : if(i >= 1){
367 0 : TileDef lasttile = f.tiledef[i-1];
368 0 : while(i < 6){
369 0 : f.tiledef[i] = lasttile;
370 0 : i++;
371 : }
372 : }
373 : }
374 0 : lua_pop(L, 1);
375 :
376 : // special_tiles = {}
377 0 : lua_getfield(L, index, "special_tiles");
378 : // If nil, try the deprecated name "special_materials" instead
379 0 : if(lua_isnil(L, -1)){
380 0 : lua_pop(L, 1);
381 0 : warn_if_field_exists(L, index, "special_materials",
382 0 : "Deprecated; new name is \"special_tiles\".");
383 0 : lua_getfield(L, index, "special_materials");
384 : }
385 0 : if(lua_istable(L, -1)){
386 0 : int table = lua_gettop(L);
387 0 : lua_pushnil(L);
388 0 : int i = 0;
389 0 : while(lua_next(L, table) != 0){
390 : // Read tiledef from value
391 0 : f.tiledef_special[i] = read_tiledef(L, -1);
392 : // removes value, keeps key for next iteration
393 0 : lua_pop(L, 1);
394 0 : i++;
395 0 : if(i==CF_SPECIAL_COUNT){
396 0 : lua_pop(L, 1);
397 0 : break;
398 : }
399 : }
400 : }
401 0 : lua_pop(L, 1);
402 :
403 0 : f.alpha = getintfield_default(L, index, "alpha", 255);
404 :
405 : bool usealpha = getboolfield_default(L, index,
406 0 : "use_texture_alpha", false);
407 0 : if (usealpha)
408 0 : f.alpha = 0;
409 :
410 : /* Other stuff */
411 :
412 0 : lua_getfield(L, index, "post_effect_color");
413 0 : read_color(L, -1, &f.post_effect_color);
414 0 : lua_pop(L, 1);
415 :
416 0 : f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
417 0 : ScriptApiNode::es_ContentParamType, CPT_NONE);
418 0 : f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
419 0 : ScriptApiNode::es_ContentParamType2, CPT2_NONE);
420 :
421 : // Warn about some deprecated fields
422 0 : warn_if_field_exists(L, index, "wall_mounted",
423 0 : "deprecated: use paramtype2 = 'wallmounted'");
424 0 : warn_if_field_exists(L, index, "light_propagates",
425 0 : "deprecated: determined from paramtype");
426 0 : warn_if_field_exists(L, index, "dug_item",
427 0 : "deprecated: use 'drop' field");
428 0 : warn_if_field_exists(L, index, "extra_dug_item",
429 0 : "deprecated: use 'drop' field");
430 0 : warn_if_field_exists(L, index, "extra_dug_item_rarity",
431 0 : "deprecated: use 'drop' field");
432 0 : warn_if_field_exists(L, index, "metadata_name",
433 0 : "deprecated: use on_add and metadata callbacks");
434 :
435 : // True for all ground-like things like stone and mud, false for eg. trees
436 0 : getboolfield(L, index, "is_ground_content", f.is_ground_content);
437 0 : f.light_propagates = (f.param_type == CPT_LIGHT);
438 0 : getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
439 : // This is used for collision detection.
440 : // Also for general solidness queries.
441 0 : getboolfield(L, index, "walkable", f.walkable);
442 : // Player can point to these
443 0 : getboolfield(L, index, "pointable", f.pointable);
444 : // Player can dig these
445 0 : getboolfield(L, index, "diggable", f.diggable);
446 : // Player can climb these
447 0 : getboolfield(L, index, "climbable", f.climbable);
448 : // Player can build on these
449 0 : getboolfield(L, index, "buildable_to", f.buildable_to);
450 : // Whether the node is non-liquid, source liquid or flowing liquid
451 0 : f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
452 0 : ScriptApiNode::es_LiquidType, LIQUID_NONE);
453 : // If the content is liquid, this is the flowing version of the liquid.
454 0 : getstringfield(L, index, "liquid_alternative_flowing",
455 0 : f.liquid_alternative_flowing);
456 : // If the content is liquid, this is the source version of the liquid.
457 0 : getstringfield(L, index, "liquid_alternative_source",
458 0 : f.liquid_alternative_source);
459 : // Viscosity for fluid flow, ranging from 1 to 7, with
460 : // 1 giving almost instantaneous propagation and 7 being
461 : // the slowest possible
462 0 : f.liquid_viscosity = getintfield_default(L, index,
463 0 : "liquid_viscosity", f.liquid_viscosity);
464 0 : f.liquid_range = getintfield_default(L, index,
465 0 : "liquid_range", f.liquid_range);
466 0 : f.leveled = getintfield_default(L, index, "leveled", f.leveled);
467 :
468 0 : getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
469 0 : f.drowning = getintfield_default(L, index,
470 0 : "drowning", f.drowning);
471 : // Amount of light the node emits
472 0 : f.light_source = getintfield_default(L, index,
473 0 : "light_source", f.light_source);
474 0 : f.damage_per_second = getintfield_default(L, index,
475 0 : "damage_per_second", f.damage_per_second);
476 :
477 0 : lua_getfield(L, index, "node_box");
478 0 : if(lua_istable(L, -1))
479 0 : f.node_box = read_nodebox(L, -1);
480 0 : lua_pop(L, 1);
481 :
482 0 : lua_getfield(L, index, "selection_box");
483 0 : if(lua_istable(L, -1))
484 0 : f.selection_box = read_nodebox(L, -1);
485 0 : lua_pop(L, 1);
486 :
487 0 : lua_getfield(L, index, "collision_box");
488 0 : if(lua_istable(L, -1))
489 0 : f.collision_box = read_nodebox(L, -1);
490 0 : lua_pop(L, 1);
491 :
492 0 : f.waving = getintfield_default(L, index,
493 0 : "waving", f.waving);
494 :
495 : // Set to true if paramtype used to be 'facedir_simple'
496 0 : getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
497 : // Set to true if wall_mounted used to be set to true
498 0 : getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
499 :
500 : // Sound table
501 0 : lua_getfield(L, index, "sounds");
502 0 : if(lua_istable(L, -1)){
503 0 : lua_getfield(L, -1, "footstep");
504 0 : read_soundspec(L, -1, f.sound_footstep);
505 0 : lua_pop(L, 1);
506 0 : lua_getfield(L, -1, "dig");
507 0 : read_soundspec(L, -1, f.sound_dig);
508 0 : lua_pop(L, 1);
509 0 : lua_getfield(L, -1, "dug");
510 0 : read_soundspec(L, -1, f.sound_dug);
511 0 : lua_pop(L, 1);
512 : }
513 0 : lua_pop(L, 1);
514 :
515 0 : return f;
516 : }
517 :
518 : /******************************************************************************/
519 0 : void read_server_sound_params(lua_State *L, int index,
520 : ServerSoundParams ¶ms)
521 : {
522 0 : if(index < 0)
523 0 : index = lua_gettop(L) + 1 + index;
524 : // Clear
525 0 : params = ServerSoundParams();
526 0 : if(lua_istable(L, index)){
527 0 : getfloatfield(L, index, "gain", params.gain);
528 0 : getstringfield(L, index, "to_player", params.to_player);
529 0 : lua_getfield(L, index, "pos");
530 0 : if(!lua_isnil(L, -1)){
531 0 : v3f p = read_v3f(L, -1)*BS;
532 0 : params.pos = p;
533 0 : params.type = ServerSoundParams::SSP_POSITIONAL;
534 : }
535 0 : lua_pop(L, 1);
536 0 : lua_getfield(L, index, "object");
537 0 : if(!lua_isnil(L, -1)){
538 0 : ObjectRef *ref = ObjectRef::checkobject(L, -1);
539 0 : ServerActiveObject *sao = ObjectRef::getobject(ref);
540 0 : if(sao){
541 0 : params.object = sao->getId();
542 0 : params.type = ServerSoundParams::SSP_OBJECT;
543 : }
544 : }
545 0 : lua_pop(L, 1);
546 0 : params.max_hear_distance = BS*getfloatfield_default(L, index,
547 0 : "max_hear_distance", params.max_hear_distance/BS);
548 0 : getboolfield(L, index, "loop", params.loop);
549 : }
550 0 : }
551 :
552 : /******************************************************************************/
553 1 : void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
554 : {
555 1 : if(index < 0)
556 0 : index = lua_gettop(L) + 1 + index;
557 1 : if(lua_isnil(L, index)){
558 1 : } else if(lua_istable(L, index)){
559 0 : getstringfield(L, index, "name", spec.name);
560 0 : getfloatfield(L, index, "gain", spec.gain);
561 1 : } else if(lua_isstring(L, index)){
562 1 : spec.name = lua_tostring(L, index);
563 : }
564 1 : }
565 :
566 : /******************************************************************************/
567 0 : NodeBox read_nodebox(lua_State *L, int index)
568 : {
569 0 : NodeBox nodebox;
570 0 : if(lua_istable(L, -1)){
571 0 : nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
572 0 : ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
573 :
574 0 : lua_getfield(L, index, "fixed");
575 0 : if(lua_istable(L, -1))
576 0 : nodebox.fixed = read_aabb3f_vector(L, -1, BS);
577 0 : lua_pop(L, 1);
578 :
579 0 : lua_getfield(L, index, "wall_top");
580 0 : if(lua_istable(L, -1))
581 0 : nodebox.wall_top = read_aabb3f(L, -1, BS);
582 0 : lua_pop(L, 1);
583 :
584 0 : lua_getfield(L, index, "wall_bottom");
585 0 : if(lua_istable(L, -1))
586 0 : nodebox.wall_bottom = read_aabb3f(L, -1, BS);
587 0 : lua_pop(L, 1);
588 :
589 0 : lua_getfield(L, index, "wall_side");
590 0 : if(lua_istable(L, -1))
591 0 : nodebox.wall_side = read_aabb3f(L, -1, BS);
592 0 : lua_pop(L, 1);
593 : }
594 0 : return nodebox;
595 : }
596 :
597 : /******************************************************************************/
598 0 : MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
599 : {
600 0 : lua_getfield(L, index, "name");
601 0 : if (!lua_isstring(L, -1))
602 0 : throw LuaError("Node name is not set or is not a string!");
603 0 : const char *name = lua_tostring(L, -1);
604 0 : lua_pop(L, 1);
605 :
606 0 : u8 param1 = 0;
607 0 : lua_getfield(L, index, "param1");
608 0 : if (!lua_isnil(L, -1))
609 0 : param1 = lua_tonumber(L, -1);
610 0 : lua_pop(L, 1);
611 :
612 0 : u8 param2 = 0;
613 0 : lua_getfield(L, index, "param2");
614 0 : if (!lua_isnil(L, -1))
615 0 : param2 = lua_tonumber(L, -1);
616 0 : lua_pop(L, 1);
617 :
618 0 : return MapNode(ndef, name, param1, param2);
619 : }
620 :
621 : /******************************************************************************/
622 0 : void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
623 : {
624 0 : lua_newtable(L);
625 0 : lua_pushstring(L, ndef->get(n).name.c_str());
626 0 : lua_setfield(L, -2, "name");
627 0 : lua_pushnumber(L, n.getParam1());
628 0 : lua_setfield(L, -2, "param1");
629 0 : lua_pushnumber(L, n.getParam2());
630 0 : lua_setfield(L, -2, "param2");
631 0 : }
632 :
633 : /******************************************************************************/
634 0 : void warn_if_field_exists(lua_State *L, int table,
635 : const char *fieldname, const std::string &message)
636 : {
637 0 : lua_getfield(L, table, fieldname);
638 0 : if(!lua_isnil(L, -1)){
639 : //TODO find way to access backtrace fct from here
640 : // infostream<<script_get_backtrace(L)<<std::endl;
641 0 : infostream<<"WARNING: field \""<<fieldname<<"\": "
642 0 : <<message<<std::endl;
643 : }
644 0 : lua_pop(L, 1);
645 0 : }
646 :
647 : /******************************************************************************/
648 0 : int getenumfield(lua_State *L, int table,
649 : const char *fieldname, const EnumString *spec, int default_)
650 : {
651 0 : int result = default_;
652 : string_to_enum(spec, result,
653 0 : getstringfield_default(L, table, fieldname, ""));
654 0 : return result;
655 : }
656 :
657 : /******************************************************************************/
658 0 : bool string_to_enum(const EnumString *spec, int &result,
659 : const std::string &str)
660 : {
661 0 : const EnumString *esp = spec;
662 0 : while(esp->str){
663 0 : if(str == std::string(esp->str)){
664 0 : result = esp->num;
665 0 : return true;
666 : }
667 0 : esp++;
668 : }
669 0 : return false;
670 : }
671 :
672 : /******************************************************************************/
673 0 : ItemStack read_item(lua_State* L, int index,Server* srv)
674 : {
675 0 : if(index < 0)
676 0 : index = lua_gettop(L) + 1 + index;
677 :
678 0 : if(lua_isnil(L, index))
679 : {
680 0 : return ItemStack();
681 : }
682 0 : else if(lua_isuserdata(L, index))
683 : {
684 : // Convert from LuaItemStack
685 0 : LuaItemStack *o = LuaItemStack::checkobject(L, index);
686 0 : return o->getItem();
687 : }
688 0 : else if(lua_isstring(L, index))
689 : {
690 : // Convert from itemstring
691 0 : std::string itemstring = lua_tostring(L, index);
692 0 : IItemDefManager *idef = srv->idef();
693 : try
694 : {
695 0 : ItemStack item;
696 0 : item.deSerialize(itemstring, idef);
697 0 : return item;
698 : }
699 0 : catch(SerializationError &e)
700 : {
701 0 : infostream<<"WARNING: unable to create item from itemstring"
702 0 : <<": "<<itemstring<<std::endl;
703 0 : return ItemStack();
704 : }
705 : }
706 0 : else if(lua_istable(L, index))
707 : {
708 : // Convert from table
709 0 : IItemDefManager *idef = srv->idef();
710 0 : std::string name = getstringfield_default(L, index, "name", "");
711 0 : int count = getintfield_default(L, index, "count", 1);
712 0 : int wear = getintfield_default(L, index, "wear", 0);
713 0 : std::string metadata = getstringfield_default(L, index, "metadata", "");
714 0 : return ItemStack(name, count, wear, metadata, idef);
715 : }
716 : else
717 : {
718 0 : throw LuaError("Expecting itemstack, itemstring, table or nil");
719 : }
720 : }
721 :
722 : /******************************************************************************/
723 0 : void push_tool_capabilities(lua_State *L,
724 : const ToolCapabilities &toolcap)
725 : {
726 0 : lua_newtable(L);
727 0 : setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
728 0 : setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
729 : // Create groupcaps table
730 0 : lua_newtable(L);
731 : // For each groupcap
732 0 : for(std::map<std::string, ToolGroupCap>::const_iterator
733 0 : i = toolcap.groupcaps.begin(); i != toolcap.groupcaps.end(); i++){
734 : // Create groupcap table
735 0 : lua_newtable(L);
736 0 : const std::string &name = i->first;
737 0 : const ToolGroupCap &groupcap = i->second;
738 : // Create subtable "times"
739 0 : lua_newtable(L);
740 0 : for(std::map<int, float>::const_iterator
741 0 : i = groupcap.times.begin(); i != groupcap.times.end(); i++){
742 0 : int rating = i->first;
743 0 : float time = i->second;
744 0 : lua_pushinteger(L, rating);
745 0 : lua_pushnumber(L, time);
746 0 : lua_settable(L, -3);
747 : }
748 : // Set subtable "times"
749 0 : lua_setfield(L, -2, "times");
750 : // Set simple parameters
751 0 : setintfield(L, -1, "maxlevel", groupcap.maxlevel);
752 0 : setintfield(L, -1, "uses", groupcap.uses);
753 : // Insert groupcap table into groupcaps table
754 0 : lua_setfield(L, -2, name.c_str());
755 : }
756 : // Set groupcaps table
757 0 : lua_setfield(L, -2, "groupcaps");
758 : //Create damage_groups table
759 0 : lua_newtable(L);
760 : // For each damage group
761 0 : for(std::map<std::string, s16>::const_iterator
762 0 : i = toolcap.damageGroups.begin(); i != toolcap.damageGroups.end(); i++){
763 : // Create damage group table
764 0 : lua_pushinteger(L, i->second);
765 0 : lua_setfield(L, -2, i->first.c_str());
766 : }
767 0 : lua_setfield(L, -2, "damage_groups");
768 0 : }
769 :
770 : /******************************************************************************/
771 0 : void push_inventory_list(lua_State *L, Inventory *inv, const char *name)
772 : {
773 0 : InventoryList *invlist = inv->getList(name);
774 0 : if(invlist == NULL){
775 0 : lua_pushnil(L);
776 0 : return;
777 : }
778 0 : std::vector<ItemStack> items;
779 0 : for(u32 i=0; i<invlist->getSize(); i++)
780 0 : items.push_back(invlist->getItem(i));
781 0 : push_items(L, items);
782 : }
783 :
784 : /******************************************************************************/
785 0 : void read_inventory_list(lua_State *L, int tableindex,
786 : Inventory *inv, const char *name, Server* srv, int forcesize)
787 : {
788 0 : if(tableindex < 0)
789 0 : tableindex = lua_gettop(L) + 1 + tableindex;
790 : // If nil, delete list
791 0 : if(lua_isnil(L, tableindex)){
792 0 : inv->deleteList(name);
793 0 : return;
794 : }
795 : // Otherwise set list
796 0 : std::vector<ItemStack> items = read_items(L, tableindex,srv);
797 0 : int listsize = (forcesize != -1) ? forcesize : items.size();
798 0 : InventoryList *invlist = inv->addList(name, listsize);
799 0 : int index = 0;
800 0 : for(std::vector<ItemStack>::const_iterator
801 0 : i = items.begin(); i != items.end(); i++){
802 0 : if(forcesize != -1 && index == forcesize)
803 0 : break;
804 0 : invlist->changeItem(index, *i);
805 0 : index++;
806 : }
807 0 : while(forcesize != -1 && index < forcesize){
808 0 : invlist->deleteItem(index);
809 0 : index++;
810 : }
811 : }
812 :
813 : /******************************************************************************/
814 0 : ToolCapabilities read_tool_capabilities(
815 : lua_State *L, int table)
816 : {
817 0 : ToolCapabilities toolcap;
818 0 : getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
819 0 : getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
820 0 : lua_getfield(L, table, "groupcaps");
821 0 : if(lua_istable(L, -1)){
822 0 : int table_groupcaps = lua_gettop(L);
823 0 : lua_pushnil(L);
824 0 : while(lua_next(L, table_groupcaps) != 0){
825 : // key at index -2 and value at index -1
826 0 : std::string groupname = luaL_checkstring(L, -2);
827 0 : if(lua_istable(L, -1)){
828 0 : int table_groupcap = lua_gettop(L);
829 : // This will be created
830 0 : ToolGroupCap groupcap;
831 : // Read simple parameters
832 0 : getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
833 0 : getintfield(L, table_groupcap, "uses", groupcap.uses);
834 : // DEPRECATED: maxwear
835 0 : float maxwear = 0;
836 0 : if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
837 0 : if(maxwear != 0)
838 0 : groupcap.uses = 1.0/maxwear;
839 : else
840 0 : groupcap.uses = 0;
841 0 : infostream<<script_get_backtrace(L)<<std::endl;
842 0 : infostream<<"WARNING: field \"maxwear\" is deprecated; "
843 0 : <<"should replace with uses=1/maxwear"<<std::endl;
844 : }
845 : // Read "times" table
846 0 : lua_getfield(L, table_groupcap, "times");
847 0 : if(lua_istable(L, -1)){
848 0 : int table_times = lua_gettop(L);
849 0 : lua_pushnil(L);
850 0 : while(lua_next(L, table_times) != 0){
851 : // key at index -2 and value at index -1
852 0 : int rating = luaL_checkinteger(L, -2);
853 0 : float time = luaL_checknumber(L, -1);
854 0 : groupcap.times[rating] = time;
855 : // removes value, keeps key for next iteration
856 0 : lua_pop(L, 1);
857 : }
858 : }
859 0 : lua_pop(L, 1);
860 : // Insert groupcap into toolcap
861 0 : toolcap.groupcaps[groupname] = groupcap;
862 : }
863 : // removes value, keeps key for next iteration
864 0 : lua_pop(L, 1);
865 : }
866 : }
867 0 : lua_pop(L, 1);
868 :
869 0 : lua_getfield(L, table, "damage_groups");
870 0 : if(lua_istable(L, -1)){
871 0 : int table_damage_groups = lua_gettop(L);
872 0 : lua_pushnil(L);
873 0 : while(lua_next(L, table_damage_groups) != 0){
874 : // key at index -2 and value at index -1
875 0 : std::string groupname = luaL_checkstring(L, -2);
876 0 : u16 value = luaL_checkinteger(L, -1);
877 0 : toolcap.damageGroups[groupname] = value;
878 : // removes value, keeps key for next iteration
879 0 : lua_pop(L, 1);
880 : }
881 : }
882 0 : lua_pop(L, 1);
883 0 : return toolcap;
884 : }
885 :
886 : /******************************************************************************/
887 0 : void push_dig_params(lua_State *L,const DigParams ¶ms)
888 : {
889 0 : lua_newtable(L);
890 0 : setboolfield(L, -1, "diggable", params.diggable);
891 0 : setfloatfield(L, -1, "time", params.time);
892 0 : setintfield(L, -1, "wear", params.wear);
893 0 : }
894 :
895 : /******************************************************************************/
896 0 : void push_hit_params(lua_State *L,const HitParams ¶ms)
897 : {
898 0 : lua_newtable(L);
899 0 : setintfield(L, -1, "hp", params.hp);
900 0 : setintfield(L, -1, "wear", params.wear);
901 0 : }
902 :
903 : /******************************************************************************/
904 :
905 0 : bool getflagsfield(lua_State *L, int table, const char *fieldname,
906 : FlagDesc *flagdesc, u32 *flags, u32 *flagmask)
907 : {
908 0 : lua_getfield(L, table, fieldname);
909 :
910 0 : bool success = read_flags(L, -1, flagdesc, flags, flagmask);
911 :
912 0 : lua_pop(L, 1);
913 :
914 0 : return success;
915 : }
916 :
917 0 : bool read_flags(lua_State *L, int index, FlagDesc *flagdesc,
918 : u32 *flags, u32 *flagmask)
919 : {
920 0 : if (lua_isstring(L, index)) {
921 0 : std::string flagstr = lua_tostring(L, index);
922 0 : *flags = readFlagString(flagstr, flagdesc, flagmask);
923 0 : } else if (lua_istable(L, index)) {
924 0 : *flags = read_flags_table(L, index, flagdesc, flagmask);
925 : } else {
926 0 : return false;
927 : }
928 :
929 0 : return true;
930 : }
931 :
932 0 : u32 read_flags_table(lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask)
933 : {
934 0 : u32 flags = 0, mask = 0;
935 0 : char fnamebuf[64] = "no";
936 :
937 0 : for (int i = 0; flagdesc[i].name; i++) {
938 : bool result;
939 :
940 0 : if (getboolfield(L, table, flagdesc[i].name, result)) {
941 0 : mask |= flagdesc[i].flag;
942 0 : if (result)
943 0 : flags |= flagdesc[i].flag;
944 : }
945 :
946 0 : strlcpy(fnamebuf + 2, flagdesc[i].name, sizeof(fnamebuf) - 2);
947 0 : if (getboolfield(L, table, fnamebuf, result))
948 0 : mask |= flagdesc[i].flag;
949 : }
950 :
951 0 : if (flagmask)
952 0 : *flagmask = mask;
953 :
954 0 : return flags;
955 : }
956 :
957 0 : void push_flags_string(lua_State *L, FlagDesc *flagdesc, u32 flags, u32 flagmask)
958 : {
959 0 : std::string flagstring = writeFlagString(flags, flagdesc, flagmask);
960 0 : lua_pushlstring(L, flagstring.c_str(), flagstring.size());
961 0 : }
962 :
963 : /******************************************************************************/
964 : /* Lua Stored data! */
965 : /******************************************************************************/
966 :
967 : /******************************************************************************/
968 0 : void read_groups(lua_State *L, int index,
969 : std::map<std::string, int> &result)
970 : {
971 0 : if (!lua_istable(L,index))
972 0 : return;
973 0 : result.clear();
974 0 : lua_pushnil(L);
975 0 : if(index < 0)
976 0 : index -= 1;
977 0 : while(lua_next(L, index) != 0){
978 : // key at index -2 and value at index -1
979 0 : std::string name = luaL_checkstring(L, -2);
980 0 : int rating = luaL_checkinteger(L, -1);
981 0 : result[name] = rating;
982 : // removes value, keeps key for next iteration
983 0 : lua_pop(L, 1);
984 : }
985 : }
986 :
987 : /******************************************************************************/
988 0 : void push_groups(lua_State *L, std::map<std::string, int> groups)
989 : {
990 0 : lua_newtable(L);
991 0 : for (std::map<std::string, int>::iterator it = groups.begin();
992 0 : it != groups.end(); ++it) {
993 0 : lua_pushnumber(L, it->second);
994 0 : lua_setfield(L, -2, it->first.c_str());
995 : }
996 0 : }
997 :
998 : /******************************************************************************/
999 0 : void push_items(lua_State *L, const std::vector<ItemStack> &items)
1000 : {
1001 : // Create and fill table
1002 0 : lua_createtable(L, items.size(), 0);
1003 0 : std::vector<ItemStack>::const_iterator iter = items.begin();
1004 0 : for (u32 i = 0; iter != items.end(); iter++) {
1005 0 : LuaItemStack::create(L, *iter);
1006 0 : lua_rawseti(L, -2, ++i);
1007 : }
1008 0 : }
1009 :
1010 : /******************************************************************************/
1011 0 : std::vector<ItemStack> read_items(lua_State *L, int index, Server *srv)
1012 : {
1013 0 : if(index < 0)
1014 0 : index = lua_gettop(L) + 1 + index;
1015 :
1016 0 : std::vector<ItemStack> items;
1017 0 : luaL_checktype(L, index, LUA_TTABLE);
1018 0 : lua_pushnil(L);
1019 0 : while (lua_next(L, index)) {
1020 0 : s32 key = luaL_checkinteger(L, -2);
1021 0 : if (key < 1) {
1022 0 : throw LuaError("Invalid inventory list index");
1023 : }
1024 0 : if (items.size() < (u32) key) {
1025 0 : items.resize(key);
1026 : }
1027 0 : items[key - 1] = read_item(L, -1, srv);
1028 0 : lua_pop(L, 1);
1029 : }
1030 0 : return items;
1031 : }
1032 :
1033 : /******************************************************************************/
1034 0 : void luaentity_get(lua_State *L, u16 id)
1035 : {
1036 : // Get luaentities[i]
1037 0 : lua_getglobal(L, "core");
1038 0 : lua_getfield(L, -1, "luaentities");
1039 0 : luaL_checktype(L, -1, LUA_TTABLE);
1040 0 : lua_pushnumber(L, id);
1041 0 : lua_gettable(L, -2);
1042 0 : lua_remove(L, -2); // Remove luaentities
1043 0 : lua_remove(L, -2); // Remove core
1044 0 : }
1045 :
1046 : /******************************************************************************/
1047 0 : bool read_noiseparams(lua_State *L, int index, NoiseParams *np)
1048 : {
1049 0 : if (index < 0)
1050 0 : index = lua_gettop(L) + 1 + index;
1051 :
1052 0 : if (!lua_istable(L, index))
1053 0 : return false;
1054 :
1055 0 : getfloatfield(L, index, "offset", np->offset);
1056 0 : getfloatfield(L, index, "scale", np->scale);
1057 0 : getfloatfield(L, index, "persist", np->persist);
1058 0 : getfloatfield(L, index, "persistence", np->persist);
1059 0 : getfloatfield(L, index, "lacunarity", np->lacunarity);
1060 0 : getintfield(L, index, "seed", np->seed);
1061 0 : getintfield(L, index, "octaves", np->octaves);
1062 :
1063 0 : u32 flags = 0;
1064 0 : u32 flagmask = 0;
1065 0 : np->flags = getflagsfield(L, index, "flags", flagdesc_noiseparams,
1066 0 : &flags, &flagmask) ? flags : NOISE_FLAG_DEFAULTS;
1067 :
1068 0 : lua_getfield(L, index, "spread");
1069 0 : np->spread = read_v3f(L, -1);
1070 0 : lua_pop(L, 1);
1071 :
1072 0 : return true;
1073 : }
1074 :
1075 0 : void push_noiseparams(lua_State *L, NoiseParams *np)
1076 : {
1077 0 : lua_newtable(L);
1078 0 : lua_pushnumber(L, np->offset);
1079 0 : lua_setfield(L, -2, "offset");
1080 0 : lua_pushnumber(L, np->scale);
1081 0 : lua_setfield(L, -2, "scale");
1082 0 : lua_pushnumber(L, np->persist);
1083 0 : lua_setfield(L, -2, "persistence");
1084 0 : lua_pushnumber(L, np->lacunarity);
1085 0 : lua_setfield(L, -2, "lacunarity");
1086 0 : lua_pushnumber(L, np->seed);
1087 0 : lua_setfield(L, -2, "seed");
1088 0 : lua_pushnumber(L, np->octaves);
1089 0 : lua_setfield(L, -2, "octaves");
1090 :
1091 0 : push_flags_string(L, flagdesc_noiseparams, np->flags,
1092 0 : np->flags);
1093 0 : lua_setfield(L, -2, "flags");
1094 :
1095 0 : push_v3f(L, np->spread);
1096 0 : lua_setfield(L, -2, "spread");
1097 0 : }
1098 :
1099 : /******************************************************************************/
1100 : // Returns depth of json value tree
1101 0 : static int push_json_value_getdepth(const Json::Value &value)
1102 : {
1103 0 : if (!value.isArray() && !value.isObject())
1104 0 : return 1;
1105 :
1106 0 : int maxdepth = 0;
1107 0 : for (Json::Value::const_iterator it = value.begin();
1108 0 : it != value.end(); ++it) {
1109 0 : int elemdepth = push_json_value_getdepth(*it);
1110 0 : if (elemdepth > maxdepth)
1111 0 : maxdepth = elemdepth;
1112 : }
1113 0 : return maxdepth + 1;
1114 : }
1115 : // Recursive function to convert JSON --> Lua table
1116 0 : static bool push_json_value_helper(lua_State *L, const Json::Value &value,
1117 : int nullindex)
1118 : {
1119 0 : switch(value.type()) {
1120 : case Json::nullValue:
1121 : default:
1122 0 : lua_pushvalue(L, nullindex);
1123 0 : break;
1124 : case Json::intValue:
1125 0 : lua_pushinteger(L, value.asInt());
1126 0 : break;
1127 : case Json::uintValue:
1128 0 : lua_pushinteger(L, value.asUInt());
1129 0 : break;
1130 : case Json::realValue:
1131 0 : lua_pushnumber(L, value.asDouble());
1132 0 : break;
1133 : case Json::stringValue:
1134 : {
1135 0 : const char *str = value.asCString();
1136 0 : lua_pushstring(L, str ? str : "");
1137 : }
1138 0 : break;
1139 : case Json::booleanValue:
1140 0 : lua_pushboolean(L, value.asInt());
1141 0 : break;
1142 : case Json::arrayValue:
1143 0 : lua_newtable(L);
1144 0 : for (Json::Value::const_iterator it = value.begin();
1145 0 : it != value.end(); ++it) {
1146 0 : push_json_value_helper(L, *it, nullindex);
1147 0 : lua_rawseti(L, -2, it.index() + 1);
1148 : }
1149 0 : break;
1150 : case Json::objectValue:
1151 0 : lua_newtable(L);
1152 0 : for (Json::Value::const_iterator it = value.begin();
1153 0 : it != value.end(); ++it) {
1154 0 : const char *str = it.memberName();
1155 0 : lua_pushstring(L, str ? str : "");
1156 0 : push_json_value_helper(L, *it, nullindex);
1157 0 : lua_rawset(L, -3);
1158 : }
1159 0 : break;
1160 : }
1161 0 : return true;
1162 : }
1163 : // converts JSON --> Lua table; returns false if lua stack limit exceeded
1164 : // nullindex: Lua stack index of value to use in place of JSON null
1165 0 : bool push_json_value(lua_State *L, const Json::Value &value, int nullindex)
1166 : {
1167 0 : if(nullindex < 0)
1168 0 : nullindex = lua_gettop(L) + 1 + nullindex;
1169 :
1170 0 : int depth = push_json_value_getdepth(value);
1171 :
1172 : // The maximum number of Lua stack slots used at each recursion level
1173 : // of push_json_value_helper is 2, so make sure there a depth * 2 slots
1174 0 : if (lua_checkstack(L, depth * 2))
1175 0 : return push_json_value_helper(L, value, nullindex);
1176 : else
1177 0 : return false;
1178 : }
1179 :
1180 : // Converts Lua table --> JSON
1181 0 : void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
1182 : {
1183 0 : if (recursion > 16) {
1184 0 : throw SerializationError("Maximum recursion depth exceeded");
1185 : }
1186 0 : int type = lua_type(L, index);
1187 0 : if (type == LUA_TBOOLEAN) {
1188 0 : root = (bool) lua_toboolean(L, index);
1189 0 : } else if (type == LUA_TNUMBER) {
1190 0 : root = lua_tonumber(L, index);
1191 0 : } else if (type == LUA_TSTRING) {
1192 : size_t len;
1193 0 : const char *str = lua_tolstring(L, index, &len);
1194 0 : root = std::string(str, len);
1195 0 : } else if (type == LUA_TTABLE) {
1196 0 : lua_pushnil(L);
1197 0 : while (lua_next(L, index)) {
1198 : // Key is at -2 and value is at -1
1199 0 : Json::Value value;
1200 0 : read_json_value(L, value, lua_gettop(L), recursion + 1);
1201 :
1202 0 : Json::ValueType roottype = root.type();
1203 0 : int keytype = lua_type(L, -1);
1204 0 : if (keytype == LUA_TNUMBER) {
1205 0 : lua_Number key = lua_tonumber(L, -1);
1206 0 : if (roottype != Json::nullValue && roottype != Json::arrayValue) {
1207 0 : throw SerializationError("Can't mix array and object values in JSON");
1208 0 : } else if (key < 1) {
1209 0 : throw SerializationError("Can't use zero-based or negative indexes in JSON");
1210 0 : } else if (floor(key) != key) {
1211 0 : throw SerializationError("Can't use indexes with a fractional part in JSON");
1212 : }
1213 0 : root[(Json::ArrayIndex) key - 1] = value;
1214 0 : } else if (keytype == LUA_TSTRING) {
1215 0 : if (roottype != Json::nullValue && roottype != Json::objectValue) {
1216 0 : throw SerializationError("Can't mix array and object values in JSON");
1217 : }
1218 0 : root[lua_tostring(L, -1)] = value;
1219 : } else {
1220 0 : throw SerializationError("Lua key to convert to JSON is not a string or number");
1221 : }
1222 : }
1223 0 : } else if (type == LUA_TNIL) {
1224 0 : root = Json::nullValue;
1225 : } else {
1226 0 : throw SerializationError("Can only store booleans, numbers, strings, objects, arrays, and null in JSON");
1227 : }
1228 0 : lua_pop(L, 1); // Pop value
1229 3 : }
1230 :
|