struct TileAnimationParams read_animation_definition(lua_State *L, int index) { if(index < 0) index = lua_gettop(L) + 1 + index; struct TileAnimationParams anim; anim.type = TAT_NONE; if (!lua_istable(L, index)) return anim; anim.type = (TileAnimationType) getenumfield(L, index, "type", es_TileAnimationType, TAT_NONE); if (anim.type == TAT_VERTICAL_FRAMES) { // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} anim.vertical_frames.aspect_w = getintfield_default(L, index, "aspect_w", 16); anim.vertical_frames.aspect_h = getintfield_default(L, index, "aspect_h", 16); anim.vertical_frames.length = getfloatfield_default(L, index, "length", 1.0); } else if (anim.type == TAT_SHEET_2D) { // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5} getintfield(L, index, "frames_w", anim.sheet_2d.frames_w); getintfield(L, index, "frames_h", anim.sheet_2d.frames_h); getfloatfield(L, index, "frame_length", anim.sheet_2d.frame_length); } return anim; }
Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef) { if (!lua_istable(L, index)) return NULL; BiomeType biometype = (BiomeType)getenumfield(L, index, "type", ModApiMapgen::es_BiomeTerrainType, BIOMETYPE_NORMAL); Biome *b = BiomeManager::create(biometype); b->name = getstringfield_default(L, index, "name", ""); b->depth_top = getintfield_default(L, index, "depth_top", 0); b->depth_filler = getintfield_default(L, index, "depth_filler", -31000); b->depth_water_top = getintfield_default(L, index, "depth_water_top", 0); b->depth_riverbed = getintfield_default(L, index, "depth_riverbed", 0); b->y_min = getintfield_default(L, index, "y_min", -31000); b->y_max = getintfield_default(L, index, "y_max", 31000); b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f); b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.f); b->flags = 0; //reserved std::vector<std::string> &nn = b->m_nodenames; nn.push_back(getstringfield_default(L, index, "node_top", "")); nn.push_back(getstringfield_default(L, index, "node_filler", "")); nn.push_back(getstringfield_default(L, index, "node_stone", "")); nn.push_back(getstringfield_default(L, index, "node_water_top", "")); nn.push_back(getstringfield_default(L, index, "node_water", "")); nn.push_back(getstringfield_default(L, index, "node_river_water", "")); nn.push_back(getstringfield_default(L, index, "node_riverbed", "")); nn.push_back(getstringfield_default(L, index, "node_dust", "")); ndef->pendNodeResolve(b); return b; }
bool ModApiMapgen::regDecoSchematic(lua_State *L, INodeDefManager *ndef, DecoSchematic *deco) { int index = 1; deco->rotation = (Rotation)getenumfield(L, index, "rotation", es_Rotation, ROTATE_0); std::map<std::string, std::string> replace_names; lua_getfield(L, index, "replacements"); if (lua_istable(L, -1)) read_schematic_replacements(L, replace_names, lua_gettop(L)); lua_pop(L, 1); // TODO(hmmmm): get a ref from registered schematics Schematic *schem = new Schematic; lua_getfield(L, index, "schematic"); if (!get_schematic(L, -1, schem, ndef, replace_names)) { lua_pop(L, 1); delete schem; return false; } lua_pop(L, 1); deco->schematic = schem; return true; }
// hud_add(self, form) int ObjectRef::l_hud_add(lua_State *L) { ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) return 0; HudElement *elem = new HudElement; elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type", es_HudElementType, HUD_ELEM_TEXT); lua_getfield(L, 2, "position"); elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "scale"); elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "size"); elem->size = lua_istable(L, -1) ? read_v2s32(L, -1) : v2s32(); lua_pop(L, 1); elem->name = getstringfield_default(L, 2, "name", ""); elem->text = getstringfield_default(L, 2, "text", ""); elem->number = getintfield_default(L, 2, "number", 0); elem->item = getintfield_default(L, 2, "item", 0); elem->dir = getintfield_default(L, 2, "direction", 0); // Deprecated, only for compatibility's sake if (elem->dir == 0) elem->dir = getintfield_default(L, 2, "dir", 0); lua_getfield(L, 2, "alignment"); elem->align = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "offset"); elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "world_pos"); elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f(); lua_pop(L, 1); /* check for known deprecated element usage */ if ((elem->type == HUD_ELEM_STATBAR) && (elem->size == v2s32())) { log_deprecated(L,"Deprecated usage of statbar without size!"); } u32 id = getServer(L)->hudAdd(player, elem); if (id == (u32)-1) { delete elem; return 0; } lua_pushnumber(L, id); return 1; }
// register_biome({lots of stuff}) int ModApiBasic::l_register_biome(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef; if (!bmgr) { verbosestream << "register_biome: BiomeDefManager not active" << std::endl; return 0; } enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index, "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL); Biome *b = bmgr->createBiome(terrain); b->name = getstringfield_default(L, index, "name", ""); b->top_nodename = getstringfield_default(L, index, "top_node", ""); b->top_depth = getintfield_default(L, index, "top_depth", 0); b->filler_nodename = getstringfield_default(L, index, "filler_node", ""); b->filler_height = getintfield_default(L, index, "filler_height", 0); b->height_min = getintfield_default(L, index, "height_min", 0); b->height_max = getintfield_default(L, index, "height_max", 0); b->heat_point = getfloatfield_default(L, index, "heat_point", 0.); b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.); b->flags = 0; //reserved b->c_top = CONTENT_IGNORE; b->c_filler = CONTENT_IGNORE; verbosestream << "register_biome: " << b->name << std::endl; bmgr->addBiome(b); return 0; }
int ModApiBasic::l_register_ore(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); EmergeManager *emerge = getServer(L)->getEmergeManager(); enum OreType oretype = (OreType)getenumfield(L, index, "ore_type", es_OreType, ORE_SCATTER); Ore *ore = createOre(oretype); if (!ore) { errorstream << "register_ore: ore_type " << oretype << " not implemented"; return 0; } ore->ore_name = getstringfield_default(L, index, "ore", ""); ore->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0); ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1); ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1); ore->clust_size = getintfield_default(L, index, "clust_size", 0); ore->height_min = getintfield_default(L, index, "height_min", 0); ore->height_max = getintfield_default(L, index, "height_max", 0); ore->flags = getflagsfield(L, index, "flags", flagdesc_ore); ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0.); lua_getfield(L, index, "wherein"); if (lua_istable(L, -1)) { int i = lua_gettop(L); lua_pushnil(L); while(lua_next(L, i) != 0) { ore->wherein_names.push_back(lua_tostring(L, -1)); lua_pop(L, 1); } } else if (lua_isstring(L, -1)) { ore->wherein_names.push_back(lua_tostring(L, -1)); } else { ore->wherein_names.push_back(""); } lua_pop(L, 1); lua_getfield(L, index, "noise_params"); ore->np = read_noiseparams(L, -1); lua_pop(L, 1); ore->noise = NULL; if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) { errorstream << "register_ore: clust_scarcity and clust_num_ores" "must be greater than 0" << std::endl; delete ore; return 0; } emerge->ores.push_back(ore); verbosestream << "register_ore: ore '" << ore->ore_name << "' registered" << std::endl; return 0; }
ItemDefinition read_item_definition(lua_State *L, int index, ItemDefinition default_def) { if(index < 0) index = lua_gettop(L) + 1 + index; // Read the item definition ItemDefinition def = default_def; def.type = (ItemType)getenumfield(L, index, "type", es_ItemType, ITEM_NONE); getstringfield(L, index, "name", def.name); getstringfield(L, index, "description", def.description); getstringfield(L, index, "inventory_image", def.inventory_image); getstringfield(L, index, "wield_image", def.wield_image); lua_getfield(L, index, "wield_scale"); if(lua_istable(L, -1)){ def.wield_scale = check_v3f(L, -1); } lua_pop(L, 1); def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max); if(def.stack_max == 0) def.stack_max = 1; lua_getfield(L, index, "on_use"); def.usable = lua_isfunction(L, -1); lua_pop(L, 1); getboolfield(L, index, "liquids_pointable", def.liquids_pointable); warn_if_field_exists(L, index, "tool_digging_properties", "deprecated: use tool_capabilities"); lua_getfield(L, index, "tool_capabilities"); if(lua_istable(L, -1)){ def.tool_capabilities = new ToolCapabilities( read_tool_capabilities(L, -1)); } // If name is "" (hand), ensure there are ToolCapabilities // because it will be looked up there whenever any other item has // no ToolCapabilities if(def.name == "" && def.tool_capabilities == NULL){ def.tool_capabilities = new ToolCapabilities(); } lua_getfield(L, index, "groups"); read_groups(L, -1, def.groups); lua_pop(L, 1); // Client shall immediately place this node when player places the item. // Server will update the precise end result a moment later. // "" = no prediction getstringfield(L, index, "node_placement_prediction", def.node_placement_prediction); return def; }
NodeBox read_nodebox(lua_State *L, int index) { NodeBox nodebox; if(lua_istable(L, -1)){ nodebox.type = (NodeBoxType)getenumfield(L, index, "type", ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR); #define NODEBOXREAD(n, s) \ do { \ lua_getfield(L, index, (s)); \ if (lua_istable(L, -1)) \ (n) = read_aabb3f(L, -1, BS); \ lua_pop(L, 1); \ } while (0) #define NODEBOXREADVEC(n, s) \ do { \ lua_getfield(L, index, (s)); \ if (lua_istable(L, -1)) \ (n) = read_aabb3f_vector(L, -1, BS); \ lua_pop(L, 1); \ } while (0) NODEBOXREADVEC(nodebox.fixed, "fixed"); NODEBOXREAD(nodebox.wall_top, "wall_top"); NODEBOXREAD(nodebox.wall_bottom, "wall_bottom"); NODEBOXREAD(nodebox.wall_side, "wall_side"); NODEBOXREADVEC(nodebox.connect_top, "connect_top"); NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom"); NODEBOXREADVEC(nodebox.connect_front, "connect_front"); NODEBOXREADVEC(nodebox.connect_left, "connect_left"); NODEBOXREADVEC(nodebox.connect_back, "connect_back"); NODEBOXREADVEC(nodebox.connect_right, "connect_right"); } return nodebox; }
NodeBox read_nodebox(lua_State *L, int index) { NodeBox nodebox; if(lua_istable(L, -1)){ nodebox.type = (NodeBoxType)getenumfield(L, index, "type", ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR); lua_getfield(L, index, "fixed"); if(lua_istable(L, -1)) nodebox.fixed = read_aabb3f_vector(L, -1, BS); lua_pop(L, 1); lua_getfield(L, index, "wall_top"); if(lua_istable(L, -1)) nodebox.wall_top = read_aabb3f(L, -1, BS); lua_pop(L, 1); lua_getfield(L, index, "wall_bottom"); if(lua_istable(L, -1)) nodebox.wall_bottom = read_aabb3f(L, -1, BS); lua_pop(L, 1); lua_getfield(L, index, "wall_side"); if(lua_istable(L, -1)) nodebox.wall_side = read_aabb3f(L, -1, BS); lua_pop(L, 1); } return nodebox; }
// clear_objects([options]) // clear all objects in the environment // where options = {mode = "full" or "quick"} int ModApiEnvMod::l_clear_objects(lua_State *L) { GET_ENV_PTR; ClearObjectsMode mode = CLEAR_OBJECTS_MODE_FULL; if (lua_istable(L, 1)) { mode = (ClearObjectsMode)getenumfield(L, 1, "mode", ModApiEnvMod::es_ClearObjectsMode, mode); } env->clearObjects(mode); return 0; }
// get_craft_result(input) int ModApiCraft::l_get_craft_result(lua_State *L) { NO_MAP_LOCK_REQUIRED; int input_i = 1; std::string method_s = getstringfield_default(L, input_i, "method", "normal"); enum CraftMethod method = (CraftMethod)getenumfield(L, input_i, "method", es_CraftMethod, CRAFT_METHOD_NORMAL); int width = 1; lua_getfield(L, input_i, "width"); if(lua_isnumber(L, -1)) width = luaL_checkinteger(L, -1); lua_pop(L, 1); lua_getfield(L, input_i, "items"); std::vector<ItemStack> items = read_items(L, -1,getServer(L)); lua_pop(L, 1); // items IGameDef *gdef = getServer(L); ICraftDefManager *cdef = gdef->cdef(); CraftInput input(method, width, items); CraftOutput output; std::vector<ItemStack> output_replacements; bool got = cdef->getCraftResult(input, output, output_replacements, true, gdef); lua_newtable(L); // output table if (got) { ItemStack item; item.deSerialize(output.item, gdef->idef()); LuaItemStack::create(L, item); lua_setfield(L, -2, "item"); setintfield(L, -1, "time", output.time); push_items(L, output_replacements); lua_setfield(L, -2, "replacements"); } else { LuaItemStack::create(L, ItemStack()); lua_setfield(L, -2, "item"); setintfield(L, -1, "time", 0); lua_newtable(L); lua_setfield(L, -2, "replacements"); } lua_newtable(L); // decremented input table lua_pushstring(L, method_s.c_str()); lua_setfield(L, -2, "method"); lua_pushinteger(L, width); lua_setfield(L, -2, "width"); push_items(L, input.items); lua_setfield(L, -2, "items"); return 2; }
// register_biome({lots of stuff}) int ModApiMapgen::l_register_biome(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; enum BiomeType biometype = (BiomeType)getenumfield(L, index, "type", es_BiomeTerrainType, BIOME_TYPE_NORMAL); Biome *b = bmgr->create(biometype); b->name = getstringfield_default(L, index, "name", ""); b->depth_top = getintfield_default(L, index, "depth_top", 1); b->depth_filler = getintfield_default(L, index, "depth_filler", 3); b->height_shore = getintfield_default(L, index, "height_shore", 3); b->depth_water_top = getintfield_default(L, index, "depth_water_top", 0); b->y_min = getintfield_default(L, index, "y_min", -31000); b->y_max = getintfield_default(L, index, "y_max", 31000); b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f); b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.f); b->flags = 0; //reserved u32 id = bmgr->add(b); if (id == (u32)-1) { delete b; return 0; } NodeResolveInfo *nri = new NodeResolveInfo(b); std::list<std::string> &nnames = nri->nodenames; nnames.push_back(getstringfield_default(L, index, "node_top", "")); nnames.push_back(getstringfield_default(L, index, "node_filler", "")); nnames.push_back(getstringfield_default(L, index, "node_shore_top", "")); nnames.push_back(getstringfield_default(L, index, "node_shore_filler", "")); nnames.push_back(getstringfield_default(L, index, "node_underwater", "")); nnames.push_back(getstringfield_default(L, index, "node_stone", "")); nnames.push_back(getstringfield_default(L, index, "node_water_top", "")); nnames.push_back(getstringfield_default(L, index, "node_water", "")); nnames.push_back(getstringfield_default(L, index, "node_dust", "")); ndef->pendNodeResolve(nri); verbosestream << "register_biome: " << b->name << std::endl; lua_pushinteger(L, id); return 1; }
// hud_add(self, form) int ObjectRef::l_hud_add(lua_State *L) { ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) return 0; HudElement *elem = new HudElement; elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type", es_HudElementType, HUD_ELEM_TEXT); lua_getfield(L, 2, "position"); elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "scale"); elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); elem->name = getstringfield_default(L, 2, "name", ""); elem->text = getstringfield_default(L, 2, "text", ""); elem->number = getintfield_default(L, 2, "number", 0); elem->item = getintfield_default(L, 2, "item", 0); elem->dir = getintfield_default(L, 2, "dir", 0); lua_getfield(L, 2, "alignment"); elem->align = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "offset"); elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "world_pos"); elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f(); lua_pop(L, 1); u32 id = getServer(L)->hudAdd(player, elem); if (id == (u32)-1) { delete elem; return 0; } lua_pushnumber(L, id); return 1; }
// register_biome({lots of stuff}) int ModApiMapgen::l_register_biome(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef; if (!bmgr) { verbosestream << "register_biome: BiomeDefManager not active" << std::endl; return 0; } enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index, "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL); Biome *b = bmgr->createBiome(terrain); b->name = getstringfield_default(L, index, "name", "<no name>"); b->nname_top = getstringfield_default(L, index, "node_top", "mapgen_dirt_with_grass"); b->nname_filler = getstringfield_default(L, index, "node_filler", "mapgen_dirt"); b->nname_water = getstringfield_default(L, index, "node_water", "mapgen_water_source"); b->nname_dust = getstringfield_default(L, index, "node_dust", "air"); b->nname_dust_water = getstringfield_default(L, index, "node_dust_water", "mapgen_water_source"); b->depth_top = getintfield_default(L, index, "depth_top", 1); b->depth_filler = getintfield_default(L, index, "depth_filler", 3); b->height_min = getintfield_default(L, index, "height_min", 0); b->height_max = getintfield_default(L, index, "height_max", 0); b->heat_point = getfloatfield_default(L, index, "heat_point", 0.); b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.); b->flags = 0; //reserved b->c_top = CONTENT_IGNORE; b->c_filler = CONTENT_IGNORE; b->c_water = CONTENT_IGNORE; b->c_dust = CONTENT_IGNORE; b->c_dust_water = CONTENT_IGNORE; verbosestream << "register_biome: " << b->name << std::endl; bmgr->addBiome(b); return 0; }
bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco) { int index = 1; deco->rotation = (Rotation)getenumfield(L, index, "rotation", ModApiMapgen::es_Rotation, ROTATE_0); StringMap replace_names; lua_getfield(L, index, "replacements"); if (lua_istable(L, -1)) read_schematic_replacements(L, -1, &replace_names); lua_pop(L, 1); lua_getfield(L, index, "schematic"); Schematic *schem = get_or_load_schematic(L, -1, schemmgr, &replace_names); lua_pop(L, 1); deco->schematic = schem; return schem != NULL; }
// serialize_schematic(schematic, format, options={...}) int ModApiMapgen::l_serialize_schematic(lua_State *L) { SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; //// Read options NodeResolveMethod resolve_method = (NodeResolveMethod)getenumfield(L, 3, "node_resolve_method", es_NodeResolveMethod, NODE_RESOLVE_NONE); bool register_on_load = getboolfield_default(L, 3, "register_on_load", false); bool use_comments = getboolfield_default(L, 3, "use_lua_comments", false); //// Read schematic Schematic *schem = get_or_load_schematic(L, 1, schemmgr, NULL, register_on_load, resolve_method); if (!schem) { errorstream << "serialize_schematic: failed to get schematic" << std::endl; return 0; } //// Read format of definition to save as int schem_format = SCHEM_FMT_MTS; const char *enumstr = lua_tostring(L, 2); if (enumstr) string_to_enum(es_SchematicFormatType, schem_format, std::string(enumstr)); //// Serialize to binary string std::ostringstream os(std::ios_base::binary); switch (schem_format) { case SCHEM_FMT_MTS: schem->serializeToMts(&os); break; case SCHEM_FMT_LUA: schem->serializeToLua(&os, use_comments); break; default: return 0; } std::string ser = os.str(); lua_pushlstring(L, ser.c_str(), ser.length()); return 1; }
TileDef read_tiledef(lua_State *L, int index) { if(index < 0) index = lua_gettop(L) + 1 + index; TileDef tiledef; // key at index -2 and value at index if(lua_isstring(L, index)){ // "default_lava.png" tiledef.name = lua_tostring(L, index); } else if(lua_istable(L, index)) { // {name="default_lava.png", animation={}} tiledef.name = ""; getstringfield(L, index, "name", tiledef.name); getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat. tiledef.backface_culling = getboolfield_default( L, index, "backface_culling", true); // animation = {} lua_getfield(L, index, "animation"); if(lua_istable(L, -1)){ // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} tiledef.animation.type = (TileAnimationType) getenumfield(L, -1, "type", es_TileAnimationType, TAT_NONE); tiledef.animation.aspect_w = getintfield_default(L, -1, "aspect_w", 16); tiledef.animation.aspect_h = getintfield_default(L, -1, "aspect_h", 16); tiledef.animation.length = getfloatfield_default(L, -1, "length", 1.0); } lua_pop(L, 1); } return tiledef; }
// register_decoration({lots of stuff}) int ModApiBasic::l_register_decoration(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); EmergeManager *emerge = getServer(L)->getEmergeManager(); BiomeDefManager *bdef = emerge->biomedef; enum DecorationType decotype = (DecorationType)getenumfield(L, index, "deco_type", es_DecorationType, -1); if (decotype == -1) { errorstream << "register_decoration: unrecognized " "decoration placement type"; return 0; } Decoration *deco = createDecoration(decotype); if (!deco) { errorstream << "register_decoration: decoration placement type " << decotype << " not implemented"; return 0; } deco->c_place_on = CONTENT_IGNORE; deco->place_on_name = getstringfield_default(L, index, "place_on", "ignore"); deco->sidelen = getintfield_default(L, index, "sidelen", 8); deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); lua_getfield(L, index, "noise_params"); deco->np = read_noiseparams(L, -1); lua_pop(L, 1); lua_getfield(L, index, "biomes"); if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2)) { const char *s = lua_tostring(L, -1); u8 biomeid = bdef->getBiomeIdByName(s); if (biomeid) deco->biomes.insert(biomeid); lua_pop(L, 1); } lua_pop(L, 1); } switch (decotype) { case DECO_SIMPLE: { DecoSimple *dsimple = (DecoSimple *)deco; dsimple->c_deco = CONTENT_IGNORE; dsimple->c_spawnby = CONTENT_IGNORE; dsimple->spawnby_name = getstringfield_default(L, index, "spawn_by", "air"); dsimple->deco_height = getintfield_default(L, index, "height", 1); dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0); dsimple->nspawnby = getintfield_default(L, index, "num_spawn_by", -1); lua_getfield(L, index, "decoration"); if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2)) { const char *s = lua_tostring(L, -1); std::string str(s); dsimple->decolist_names.push_back(str); lua_pop(L, 1); } } else if (lua_isstring(L, -1)) { dsimple->deco_name = std::string(lua_tostring(L, -1)); } else { dsimple->deco_name = std::string("air"); } lua_pop(L, 1); if (dsimple->deco_height <= 0) { errorstream << "register_decoration: simple decoration height" " must be greater than 0" << std::endl; delete dsimple; return 0; } break; } case DECO_SCHEMATIC: { //DecoSchematic *decoschematic = (DecoSchematic *)deco; break; } case DECO_LSYSTEM: { //DecoLSystem *decolsystem = (DecoLSystem *)deco; break; } } if (deco->sidelen <= 0) { errorstream << "register_decoration: sidelen must be " "greater than 0" << std::endl; delete deco; return 0; } emerge->decorations.push_back(deco); verbosestream << "register_decoration: decoration '" << deco->getName() << "' registered" << std::endl; return 0; }
ContentFeatures read_content_features(lua_State *L, int index) { if(index < 0) index = lua_gettop(L) + 1 + index; ContentFeatures f; /* Cache existence of some callbacks */ lua_getfield(L, index, "on_construct"); if(!lua_isnil(L, -1)) f.has_on_construct = true; lua_pop(L, 1); lua_getfield(L, index, "on_destruct"); if(!lua_isnil(L, -1)) f.has_on_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "after_destruct"); if(!lua_isnil(L, -1)) f.has_after_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "on_rightclick"); f.rightclickable = lua_isfunction(L, -1); lua_pop(L, 1); /* Name */ getstringfield(L, index, "name", f.name); /* Groups */ lua_getfield(L, index, "groups"); read_groups(L, -1, f.groups); lua_pop(L, 1); /* Visual definition */ f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", ScriptApiNode::es_DrawType,NDT_NORMAL); getfloatfield(L, index, "visual_scale", f.visual_scale); // tiles = {} lua_getfield(L, index, "tiles"); // If nil, try the deprecated name "tile_images" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "tile_images", "Deprecated; new name is \"tiles\"."); lua_getfield(L, index, "tile_images"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef[i] = read_tiledef(L, -1); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==6){ lua_pop(L, 1); break; } } // Copy last value to all remaining textures if(i >= 1){ TileDef lasttile = f.tiledef[i-1]; while(i < 6){ f.tiledef[i] = lasttile; i++; } } } lua_pop(L, 1); // special_tiles = {} lua_getfield(L, index, "special_tiles"); // If nil, try the deprecated name "special_materials" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "special_materials", "Deprecated; new name is \"special_tiles\"."); lua_getfield(L, index, "special_materials"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef_special[i] = read_tiledef(L, -1); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==6){ lua_pop(L, 1); break; } } } lua_pop(L, 1); f.alpha = getintfield_default(L, index, "alpha", 255); bool usealpha = getboolfield_default(L, index, "use_texture_alpha", false); if (usealpha) f.alpha = 0; /* Other stuff */ lua_getfield(L, index, "post_effect_color"); if(!lua_isnil(L, -1)) f.post_effect_color = readARGB8(L, -1); lua_pop(L, 1); f.param_type = (ContentParamType)getenumfield(L, index, "paramtype", ScriptApiNode::es_ContentParamType, CPT_NONE); f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2", ScriptApiNode::es_ContentParamType2, CPT2_NONE); // Warn about some deprecated fields warn_if_field_exists(L, index, "wall_mounted", "deprecated: use paramtype2 = 'wallmounted'"); warn_if_field_exists(L, index, "light_propagates", "deprecated: determined from paramtype"); warn_if_field_exists(L, index, "dug_item", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item_rarity", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "metadata_name", "deprecated: use on_add and metadata callbacks"); // True for all ground-like things like stone and mud, false for eg. trees getboolfield(L, index, "is_ground_content", f.is_ground_content); f.light_propagates = (f.param_type == CPT_LIGHT); getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates); // This is used for collision detection. // Also for general solidness queries. getboolfield(L, index, "walkable", f.walkable); // Player can point to these getboolfield(L, index, "pointable", f.pointable); // Player can dig these getboolfield(L, index, "diggable", f.diggable); // Player can climb these getboolfield(L, index, "climbable", f.climbable); // Player can build on these getboolfield(L, index, "buildable_to", f.buildable_to); // Whether the node is non-liquid, source liquid or flowing liquid f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype", ScriptApiNode::es_LiquidType, LIQUID_NONE); // If the content is liquid, this is the flowing version of the liquid. getstringfield(L, index, "liquid_alternative_flowing", f.liquid_alternative_flowing); // If the content is liquid, this is the source version of the liquid. getstringfield(L, index, "liquid_alternative_source", f.liquid_alternative_source); // Viscosity for fluid flow, ranging from 1 to 7, with // 1 giving almost instantaneous propagation and 7 being // the slowest possible f.liquid_viscosity = getintfield_default(L, index, "liquid_viscosity", f.liquid_viscosity); f.liquid_range = getintfield_default(L, index, "liquid_range", f.liquid_range); f.leveled = getintfield_default(L, index, "leveled", f.leveled); getboolfield(L, index, "liquid_renewable", f.liquid_renewable); getstringfield(L, index, "freezemelt", f.freezemelt); f.drowning = getintfield_default(L, index, "drowning", f.drowning); // Amount of light the node emits f.light_source = getintfield_default(L, index, "light_source", f.light_source); f.damage_per_second = getintfield_default(L, index, "damage_per_second", f.damage_per_second); lua_getfield(L, index, "node_box"); if(lua_istable(L, -1)) f.node_box = read_nodebox(L, -1); lua_pop(L, 1); lua_getfield(L, index, "selection_box"); if(lua_istable(L, -1)) f.selection_box = read_nodebox(L, -1); lua_pop(L, 1); // Set to true if paramtype used to be 'facedir_simple' getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple); // Set to true if wall_mounted used to be set to true getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted); // Sound table lua_getfield(L, index, "sounds"); if(lua_istable(L, -1)){ lua_getfield(L, -1, "footstep"); read_soundspec(L, -1, f.sound_footstep); lua_pop(L, 1); lua_getfield(L, -1, "dig"); read_soundspec(L, -1, f.sound_dig); lua_pop(L, 1); lua_getfield(L, -1, "dug"); read_soundspec(L, -1, f.sound_dug); lua_pop(L, 1); } lua_pop(L, 1); return f; }
// register_decoration({lots of stuff}) int ModApiMapgen::l_register_decoration(lua_State *L) { NO_MAP_LOCK_REQUIRED; int index = 1; luaL_checktype(L, index, LUA_TTABLE); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr; BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr; SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; enum DecorationType decotype = (DecorationType)getenumfield(L, index, "deco_type", es_DecorationType, -1); Decoration *deco = decomgr->create(decotype); if (!deco) { errorstream << "register_decoration: decoration placement type " << decotype << " not implemented" << std::endl; return 0; } deco->name = getstringfield_default(L, index, "name", ""); deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); deco->y_min = getintfield_default(L, index, "y_min", -31000); deco->y_max = getintfield_default(L, index, "y_max", 31000); deco->nspawnby = getintfield_default(L, index, "num_spawn_by", -1); deco->sidelen = getintfield_default(L, index, "sidelen", 8); if (deco->sidelen <= 0) { errorstream << "register_decoration: sidelen must be " "greater than 0" << std::endl; delete deco; return 0; } //// Get node name(s) to place decoration on size_t nread = getstringlistfield(L, index, "place_on", &deco->m_nodenames); deco->m_nnlistsizes.push_back(nread); //// Get decoration flags getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL); //// Get NoiseParams to define how decoration is placed lua_getfield(L, index, "noise_params"); if (read_noiseparams(L, -1, &deco->np)) deco->flags |= DECO_USE_NOISE; lua_pop(L, 1); //// Get biomes associated with this decoration (if any) lua_getfield(L, index, "biomes"); if (get_biome_list(L, -1, biomemgr, &deco->biomes)) errorstream << "register_decoration: couldn't get all biomes " << std::endl; lua_pop(L, 1); //// Get node name(s) to 'spawn by' size_t nnames = getstringlistfield(L, index, "spawn_by", &deco->m_nodenames); deco->m_nnlistsizes.push_back(nnames); if (nnames == 0 && deco->nspawnby != -1) { errorstream << "register_decoration: no spawn_by nodes defined," " but num_spawn_by specified" << std::endl; } //// Handle decoration type-specific parameters bool success = false; switch (decotype) { case DECO_SIMPLE: success = read_deco_simple(L, (DecoSimple *)deco); break; case DECO_SCHEMATIC: success = read_deco_schematic(L, schemmgr, (DecoSchematic *)deco); break; case DECO_LSYSTEM: break; } if (!success) { delete deco; return 0; } ndef->pendNodeResolve(deco); ObjDefHandle handle = decomgr->add(deco); if (handle == OBJDEF_INVALID_HANDLE) { delete deco; return 0; } lua_pushinteger(L, handle); return 1; }
// register_ore({lots of stuff}) int ModApiMapgen::l_register_ore(lua_State *L) { NO_MAP_LOCK_REQUIRED; int index = 1; luaL_checktype(L, index, LUA_TTABLE); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr; enum OreType oretype = (OreType)getenumfield(L, index, "ore_type", es_OreType, ORE_SCATTER); Ore *ore = oremgr->create(oretype); if (!ore) { errorstream << "register_ore: ore_type " << oretype << " not implemented\n"; return 0; } ore->name = getstringfield_default(L, index, "name", ""); ore->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0); ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1); ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1); ore->clust_size = getintfield_default(L, index, "clust_size", 0); ore->noise = NULL; ore->flags = 0; //// Get noise_threshold warn_if_field_exists(L, index, "noise_threshhold", "Deprecated: new name is \"noise_threshold\"."); float nthresh; if (!getfloatfield(L, index, "noise_threshold", nthresh) && !getfloatfield(L, index, "noise_threshhold", nthresh)) nthresh = 0; ore->nthresh = nthresh; //// Get y_min/y_max warn_if_field_exists(L, index, "height_min", "Deprecated: new name is \"y_min\"."); warn_if_field_exists(L, index, "height_max", "Deprecated: new name is \"y_max\"."); int ymin, ymax; if (!getintfield(L, index, "y_min", ymin) && !getintfield(L, index, "height_min", ymin)) ymin = -31000; if (!getintfield(L, index, "y_max", ymax) && !getintfield(L, index, "height_max", ymax)) ymax = 31000; ore->y_min = ymin; ore->y_max = ymax; if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) { errorstream << "register_ore: clust_scarcity and clust_num_ores" "must be greater than 0" << std::endl; delete ore; return 0; } //// Get flags getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL); //// Get biomes associated with this decoration (if any) lua_getfield(L, index, "biomes"); if (get_biome_list(L, -1, bmgr, &ore->biomes)) errorstream << "register_ore: couldn't get all biomes " << std::endl; lua_pop(L, 1); //// Get noise parameters if needed lua_getfield(L, index, "noise_params"); if (read_noiseparams(L, -1, &ore->np)) { ore->flags |= OREFLAG_USE_NOISE; } else if (ore->NEEDS_NOISE) { errorstream << "register_ore: specified ore type requires valid " "noise parameters" << std::endl; delete ore; return 0; } lua_pop(L, 1); //// Get type-specific parameters switch (oretype) { case ORE_SHEET: { OreSheet *oresheet = (OreSheet *)ore; oresheet->column_height_min = getintfield_default(L, index, "column_height_min", 1); oresheet->column_height_max = getintfield_default(L, index, "column_height_max", ore->clust_size); oresheet->column_midpoint_factor = getfloatfield_default(L, index, "column_midpoint_factor", 0.5f); break; } case ORE_PUFF: { OrePuff *orepuff = (OrePuff *)ore; lua_getfield(L, index, "np_puff_top"); read_noiseparams(L, -1, &orepuff->np_puff_top); lua_pop(L, 1); lua_getfield(L, index, "np_puff_bottom"); read_noiseparams(L, -1, &orepuff->np_puff_bottom); lua_pop(L, 1); break; } case ORE_VEIN: { OreVein *orevein = (OreVein *)ore; orevein->random_factor = getfloatfield_default(L, index, "random_factor", 1.f); break; } default: break; } ObjDefHandle handle = oremgr->add(ore); if (handle == OBJDEF_INVALID_HANDLE) { delete ore; return 0; } ore->m_nodenames.push_back(getstringfield_default(L, index, "ore", "")); size_t nnames = getstringlistfield(L, index, "wherein", &ore->m_nodenames); ore->m_nnlistsizes.push_back(nnames); ndef->pendNodeResolve(ore); lua_pushinteger(L, handle); return 1; }
// register_ore({lots of stuff}) int ModApiMapgen::l_register_ore(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr; enum OreType oretype = (OreType)getenumfield(L, index, "ore_type", es_OreType, ORE_TYPE_SCATTER); Ore *ore = oremgr->create(oretype); if (!ore) { errorstream << "register_ore: ore_type " << oretype << " not implemented"; return 0; } ore->name = getstringfield_default(L, index, "name", ""); ore->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0); ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1); ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1); ore->clust_size = getintfield_default(L, index, "clust_size", 0); ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0); ore->noise = NULL; ore->flags = 0; warn_if_field_exists(L, index, "height_min", "Deprecated: new name is \"y_min\"."); warn_if_field_exists(L, index, "height_max", "Deprecated: new name is \"y_max\"."); int ymin, ymax; if (!getintfield(L, index, "y_min", ymin) && !getintfield(L, index, "height_min", ymin)) ymin = -31000; if (!getintfield(L, index, "y_max", ymax) && !getintfield(L, index, "height_max", ymax)) ymax = 31000; ore->y_min = ymin; ore->y_max = ymax; if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) { errorstream << "register_ore: clust_scarcity and clust_num_ores" "must be greater than 0" << std::endl; delete ore; return 0; } getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL); lua_getfield(L, index, "noise_params"); if (read_noiseparams(L, -1, &ore->np)) { ore->flags |= OREFLAG_USE_NOISE; } else if (ore->NEEDS_NOISE) { errorstream << "register_ore: specified ore type requires valid " "noise parameters" << std::endl; delete ore; return 0; } lua_pop(L, 1); if (oretype == ORE_TYPE_VEIN) { OreVein *orevein = (OreVein *)ore; orevein->random_factor = getfloatfield_default(L, index, "random_factor", 1.f); } u32 id = oremgr->add(ore); if (id == (u32)-1) { delete ore; return 0; } NodeResolveInfo *nri = new NodeResolveInfo(ore); nri->nodenames.push_back(getstringfield_default(L, index, "ore", "")); std::vector<const char *> wherein_names; getstringlistfield(L, index, "wherein", wherein_names); nri->nodelistinfo.push_back(NodeListInfo(wherein_names.size())); for (size_t i = 0; i != wherein_names.size(); i++) nri->nodenames.push_back(wherein_names[i]); ndef->pendNodeResolve(nri); verbosestream << "register_ore: " << ore->name << std::endl; lua_pushinteger(L, id); return 1; }
// register_decoration({lots of stuff}) int ModApiMapgen::l_register_decoration(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); EmergeManager *emerge = getServer(L)->getEmergeManager(); BiomeDefManager *bdef = emerge->biomedef; enum DecorationType decotype = (DecorationType)getenumfield(L, index, "deco_type", es_DecorationType, -1); if (decotype == -1) { errorstream << "register_decoration: unrecognized " "decoration placement type"; return 0; } Decoration *deco = createDecoration(decotype); if (!deco) { errorstream << "register_decoration: decoration placement type " << decotype << " not implemented"; return 0; } deco->c_place_on = CONTENT_IGNORE; deco->place_on_name = getstringfield_default(L, index, "place_on", "ignore"); deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); deco->sidelen = getintfield_default(L, index, "sidelen", 8); if (deco->sidelen <= 0) { errorstream << "register_decoration: sidelen must be " "greater than 0" << std::endl; delete deco; return 0; } lua_getfield(L, index, "noise_params"); deco->np = read_noiseparams(L, -1); lua_pop(L, 1); lua_getfield(L, index, "biomes"); if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2)) { const char *s = lua_tostring(L, -1); u8 biomeid = bdef->getBiomeIdByName(s); if (biomeid) deco->biomes.insert(biomeid); lua_pop(L, 1); } lua_pop(L, 1); } switch (decotype) { case DECO_SIMPLE: { DecoSimple *dsimple = (DecoSimple *)deco; dsimple->c_deco = CONTENT_IGNORE; dsimple->c_spawnby = CONTENT_IGNORE; dsimple->spawnby_name = getstringfield_default(L, index, "spawn_by", "air"); dsimple->deco_height = getintfield_default(L, index, "height", 1); dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0); dsimple->nspawnby = getintfield_default(L, index, "num_spawn_by", -1); lua_getfield(L, index, "decoration"); if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2)) { const char *s = lua_tostring(L, -1); std::string str(s); dsimple->decolist_names.push_back(str); lua_pop(L, 1); } } else if (lua_isstring(L, -1)) { dsimple->deco_name = std::string(lua_tostring(L, -1)); } else { dsimple->deco_name = std::string("air"); } lua_pop(L, 1); if (dsimple->deco_height <= 0) { errorstream << "register_decoration: simple decoration height" " must be greater than 0" << std::endl; delete dsimple; return 0; } break; } case DECO_SCHEMATIC: { DecoSchematic *dschem = (DecoSchematic *)deco; dschem->flags = 0; getflagsfield(L, index, "flags", flagdesc_deco_schematic, &dschem->flags, NULL); dschem->rotation = (Rotation)getenumfield(L, index, "rotation", es_Rotation, ROTATE_0); lua_getfield(L, index, "replacements"); if (lua_istable(L, -1)) { int i = lua_gettop(L); lua_pushnil(L); while (lua_next(L, i) != 0) { // key at index -2 and value at index -1 lua_rawgeti(L, -1, 1); std::string replace_from = lua_tostring(L, -1); lua_pop(L, 1); lua_rawgeti(L, -1, 2); std::string replace_to = lua_tostring(L, -1); lua_pop(L, 1); dschem->replacements[replace_from] = replace_to; // removes value, keeps key for next iteration lua_pop(L, 1); } } lua_pop(L, 1); lua_getfield(L, index, "schematic"); if (!read_schematic(L, -1, dschem, getServer(L))) { delete dschem; return 0; } lua_pop(L, -1); if (!dschem->filename.empty() && !dschem->loadSchematicFile()) { errorstream << "register_decoration: failed to load schematic file '" << dschem->filename << "'" << std::endl; delete dschem; return 0; } break; } case DECO_LSYSTEM: { //DecoLSystem *decolsystem = (DecoLSystem *)deco; break; } } emerge->decorations.push_back(deco); verbosestream << "register_decoration: decoration '" << deco->getName() << "' registered" << std::endl; return 0; }
// register_decoration({lots of stuff}) int ModApiMapgen::l_register_decoration(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr; BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr; enum DecorationType decotype = (DecorationType)getenumfield(L, index, "deco_type", es_DecorationType, -1); Decoration *deco = decomgr->create(decotype); if (!deco) { errorstream << "register_decoration: decoration placement type " << decotype << " not implemented"; return 0; } deco->name = getstringfield_default(L, index, "name", ""); deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); deco->y_min = getintfield_default(L, index, "y_min", -31000); deco->y_max = getintfield_default(L, index, "y_max", 31000); deco->sidelen = getintfield_default(L, index, "sidelen", 8); if (deco->sidelen <= 0) { errorstream << "register_decoration: sidelen must be " "greater than 0" << std::endl; delete deco; return 0; } NodeResolveInfo *nri = new NodeResolveInfo(deco); //// Get node name(s) to place decoration on std::vector<const char *> place_on_names; getstringlistfield(L, index, "place_on", place_on_names); nri->nodelistinfo.push_back(NodeListInfo(place_on_names.size())); for (size_t i = 0; i != place_on_names.size(); i++) nri->nodenames.push_back(place_on_names[i]); getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL); //// Get NoiseParams to define how decoration is placed lua_getfield(L, index, "noise_params"); if (read_noiseparams(L, -1, &deco->np)) deco->flags |= DECO_USE_NOISE; lua_pop(L, 1); //// Get biomes associated with this decoration (if any) std::vector<const char *> biome_list; getstringlistfield(L, index, "biomes", biome_list); for (size_t i = 0; i != biome_list.size(); i++) { Biome *b = (Biome *)biomemgr->getByName(biome_list[i]); if (!b) continue; deco->biomes.insert(b->id); } //// Handle decoration type-specific parameters bool success = false; switch (decotype) { case DECO_SIMPLE: success = regDecoSimple(L, nri, (DecoSimple *)deco); break; case DECO_SCHEMATIC: success = regDecoSchematic(L, ndef, (DecoSchematic *)deco); break; case DECO_LSYSTEM: break; } ndef->pendNodeResolve(nri); if (!success) { delete deco; return 0; } u32 id = decomgr->add(deco); if (id == (u32)-1) { delete deco; return 0; } verbosestream << "register_decoration: " << deco->name << std::endl; lua_pushinteger(L, id); return 1; }
ContentFeatures read_content_features(lua_State *L, int index) { if(index < 0) index = lua_gettop(L) + 1 + index; ContentFeatures f; /* Cache existence of some callbacks */ lua_getfield(L, index, "on_construct"); if(!lua_isnil(L, -1)) f.has_on_construct = true; lua_pop(L, 1); lua_getfield(L, index, "on_destruct"); if(!lua_isnil(L, -1)) f.has_on_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "after_destruct"); if(!lua_isnil(L, -1)) f.has_after_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "on_activate"); if(!lua_isnil(L, -1)) { f.has_on_activate = true; f.is_circuit_element = true; } lua_pop(L, 1); lua_getfield(L, index, "on_deactivate"); if(!lua_isnil(L, -1)) { f.has_on_deactivate = true; f.is_circuit_element = true; } lua_pop(L, 1); lua_getfield(L, index, "on_rightclick"); f.rightclickable = lua_isfunction(L, -1); lua_pop(L, 1); /* Name */ getstringfield(L, index, "name", f.name); /* Groups */ lua_getfield(L, index, "groups"); read_groups(L, -1, f.groups); lua_pop(L, 1); /* Visual definition */ f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", ScriptApiNode::es_DrawType,NDT_NORMAL); getfloatfield(L, index, "visual_scale", f.visual_scale); /* Meshnode model filename */ getstringfield(L, index, "mesh", f.mesh); // tiles = {} lua_getfield(L, index, "tiles"); // If nil, try the deprecated name "tile_images" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "tile_images", "Deprecated; new name is \"tiles\"."); lua_getfield(L, index, "tile_images"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef[i] = read_tiledef(L, -1); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==6){ lua_pop(L, 1); break; } } // Copy last value to all remaining textures if(i >= 1){ TileDef lasttile = f.tiledef[i-1]; while(i < 6){ f.tiledef[i] = lasttile; i++; } } } lua_pop(L, 1); /* Circuit options */ lua_getfield(L, index, "is_wire"); if(!lua_isnil(L, -1)) { f.is_wire = true; } lua_pop(L, 1); lua_getfield(L, index, "is_wire_connector"); if(!lua_isnil(L, -1)) { f.is_wire_connector = true; } lua_pop(L, 1); lua_getfield(L, index, "wire_connections"); if(!lua_isnil(L, -1) && lua_istable(L, -1)) { // Both can't be set to true f.is_wire |= !f.is_wire_connector; int table = lua_gettop(L); lua_pushnil(L); int i; unsigned char current_shift = 1; for(i = 0; (i < 6) && (lua_next(L, table) != 0); ++i) { f.wire_connections[i] = lua_tonumber(L, -1); f.wire_connections[i] |= current_shift; current_shift <<= 1; lua_pop(L, 1); } if(i < 6) { luaL_error(L, "Wire connectins array must have exactly 6 integer numbers."); } // Convert to two-way wire (one-way may cause undefined behavior) for(i = 0; i < 6; ++i) { for(int j = 0; j < 6; ++j) { f.wire_connections[i] |= f.wire_connections[j] & (1 << i); f.wire_connections[j] |= f.wire_connections[i] & (1 << j); } } } else if(f.is_wire || f.is_wire_connector) { // Assuming that it's a standart wire or wire connector for(int i = 0; i < 6; ++i) { f.wire_connections[i] = 0x3F; } } lua_pop(L, 1); lua_getfield(L, index, "circuit_states"); if(!lua_isnil(L, -1) && lua_istable(L, -1)) { f.is_circuit_element = true; int table = lua_gettop(L); lua_pushnil(L); int i; for(i = 0; (i < 64) && (lua_next(L, table) != 0); ++i) { f.circuit_element_func[i] = lua_tonumber(L, -1); lua_pop(L, 1); } if(i < 64) { luaL_error(L, "Circuit element states table must have exactly 64 integer numbers."); } } lua_pop(L, 1); f.circuit_element_delay = getintfield_default(L, index, "circuit_element_delay", f.circuit_element_delay + 1) - 1; if(f.circuit_element_delay > 100) { luaL_error(L, "\"circuit_element_delay\" must be a positive integer number less than 101"); } // special_tiles = {} lua_getfield(L, index, "special_tiles"); // If nil, try the deprecated name "special_materials" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "special_materials", "Deprecated; new name is \"special_tiles\"."); lua_getfield(L, index, "special_materials"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef_special[i] = read_tiledef(L, -1); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==CF_SPECIAL_COUNT){ lua_pop(L, 1); break; } } } lua_pop(L, 1); f.alpha = getintfield_default(L, index, "alpha", 255); bool usealpha = getboolfield_default(L, index, "use_texture_alpha", false); if (usealpha) f.alpha = 0; /* Other stuff */ lua_getfield(L, index, "post_effect_color"); if(!lua_isnil(L, -1)) f.post_effect_color = readARGB8(L, -1); lua_pop(L, 1); f.param_type = (ContentParamType)getenumfield(L, index, "paramtype", ScriptApiNode::es_ContentParamType, CPT_NONE); f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2", ScriptApiNode::es_ContentParamType2, CPT2_NONE); // Warn about some deprecated fields warn_if_field_exists(L, index, "wall_mounted", "deprecated: use paramtype2 = 'wallmounted'"); warn_if_field_exists(L, index, "light_propagates", "deprecated: determined from paramtype"); warn_if_field_exists(L, index, "dug_item", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item_rarity", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "metadata_name", "deprecated: use on_add and metadata callbacks"); // True for all ground-like things like stone and mud, false for eg. trees getboolfield(L, index, "is_ground_content", f.is_ground_content); f.light_propagates = (f.param_type == CPT_LIGHT); getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates); // This is used for collision detection. // Also for general solidness queries. getboolfield(L, index, "walkable", f.walkable); // Player can point to these getboolfield(L, index, "pointable", f.pointable); // Player can dig these getboolfield(L, index, "diggable", f.diggable); // Player can climb these getboolfield(L, index, "climbable", f.climbable); // Player can build on these getboolfield(L, index, "buildable_to", f.buildable_to); // Whether the node is non-liquid, source liquid or flowing liquid f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype", ScriptApiNode::es_LiquidType, LIQUID_NONE); // If the content is liquid, this is the flowing version of the liquid. getstringfield(L, index, "liquid_alternative_flowing", f.liquid_alternative_flowing); // If the content is liquid, this is the source version of the liquid. getstringfield(L, index, "liquid_alternative_source", f.liquid_alternative_source); // Viscosity for fluid flow, ranging from 1 to 7, with // 1 giving almost instantaneous propagation and 7 being // the slowest possible f.liquid_viscosity = getintfield_default(L, index, "liquid_viscosity", f.liquid_viscosity); f.leveled = getintfield_default(L, index, "leveled", f.leveled); getboolfield(L, index, "liquid_renewable", f.liquid_renewable); getstringfield(L, index, "freeze", f.freeze); getstringfield(L, index, "melt", f.melt); f.drowning = getintfield_default(L, index, "drowning", f.drowning); // Amount of light the node emits f.light_source = getintfield_default(L, index, "light_source", f.light_source); f.damage_per_second = getintfield_default(L, index, "damage_per_second", f.damage_per_second); lua_getfield(L, index, "node_box"); if(lua_istable(L, -1)) f.node_box = read_nodebox(L, -1); lua_pop(L, 1); lua_getfield(L, index, "selection_box"); if(lua_istable(L, -1)) f.selection_box = read_nodebox(L, -1); lua_pop(L, 1); lua_getfield(L, index, "collision_box"); if(lua_istable(L, -1)) f.collision_box = read_nodebox(L, -1); lua_pop(L, 1); f.waving = getintfield_default(L, index, "waving", f.waving); // Set to true if paramtype used to be 'facedir_simple' getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple); // Set to true if wall_mounted used to be set to true getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted); // Sound table lua_getfield(L, index, "sounds"); if(lua_istable(L, -1)){ lua_getfield(L, -1, "footstep"); read_soundspec(L, -1, f.sound_footstep); lua_pop(L, 1); lua_getfield(L, -1, "dig"); read_soundspec(L, -1, f.sound_dig); lua_pop(L, 1); lua_getfield(L, -1, "dug"); read_soundspec(L, -1, f.sound_dug); lua_pop(L, 1); } lua_pop(L, 1); return f; }
TileDef read_tiledef(lua_State *L, int index, u8 drawtype) { if(index < 0) index = lua_gettop(L) + 1 + index; TileDef tiledef; bool default_tiling = true; bool default_culling = true; switch (drawtype) { case NDT_PLANTLIKE: case NDT_FIRELIKE: default_tiling = false; // "break" is omitted here intentionaly, as PLANTLIKE // FIRELIKE drawtype both should default to having // backface_culling to false. case NDT_MESH: case NDT_LIQUID: default_culling = false; break; default: break; } // key at index -2 and value at index if(lua_isstring(L, index)){ // "default_lava.png" tiledef.name = lua_tostring(L, index); tiledef.tileable_vertical = default_tiling; tiledef.tileable_horizontal = default_tiling; tiledef.backface_culling = default_culling; } else if(lua_istable(L, index)) { // {name="default_lava.png", animation={}} tiledef.name = ""; getstringfield(L, index, "name", tiledef.name); getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat. tiledef.backface_culling = getboolfield_default( L, index, "backface_culling", default_culling); tiledef.tileable_horizontal = getboolfield_default( L, index, "tileable_horizontal", default_tiling); tiledef.tileable_vertical = getboolfield_default( L, index, "tileable_vertical", default_tiling); // animation = {} lua_getfield(L, index, "animation"); if(lua_istable(L, -1)){ // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} tiledef.animation.type = (TileAnimationType) getenumfield(L, -1, "type", es_TileAnimationType, TAT_NONE); tiledef.animation.aspect_w = getintfield_default(L, -1, "aspect_w", 16); tiledef.animation.aspect_h = getintfield_default(L, -1, "aspect_h", 16); tiledef.animation.length = getfloatfield_default(L, -1, "length", 1.0); } lua_pop(L, 1); } return tiledef; }
// register_ore({lots of stuff}) int ModApiMapgen::l_register_ore(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr; enum OreType oretype = (OreType)getenumfield(L, index, "ore_type", es_OreType, ORE_SCATTER); Ore *ore = oremgr->create(oretype); if (!ore) { errorstream << "register_ore: ore_type " << oretype << " not implemented"; return 0; } ore->name = getstringfield_default(L, index, "name", ""); ore->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0); ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1); ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1); ore->clust_size = getintfield_default(L, index, "clust_size", 0); ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0); ore->noise = NULL; ore->flags = 0; warn_if_field_exists(L, index, "height_min", "Deprecated: new name is \"y_min\"."); warn_if_field_exists(L, index, "height_max", "Deprecated: new name is \"y_max\"."); int ymin, ymax; if (!getintfield(L, index, "y_min", ymin) && !getintfield(L, index, "height_min", ymin)) ymin = -31000; if (!getintfield(L, index, "y_max", ymax) && !getintfield(L, index, "height_max", ymax)) ymax = 31000; ore->y_min = ymin; ore->y_max = ymax; if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) { errorstream << "register_ore: clust_scarcity and clust_num_ores" "must be greater than 0" << std::endl; delete ore; return 0; } getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL); lua_getfield(L, index, "noise_params"); if (read_noiseparams(L, -1, &ore->np)) { ore->flags |= OREFLAG_USE_NOISE; } else if (ore->NEEDS_NOISE) { errorstream << "register_ore: specified ore type requires valid " "noise parameters" << std::endl; delete ore; return 0; } lua_pop(L, 1); if (oretype == ORE_VEIN) { OreVein *orevein = (OreVein *)ore; orevein->random_factor = getfloatfield_default(L, index, "random_factor", 1.f); } ObjDefHandle handle = oremgr->add(ore); if (handle == OBJDEF_INVALID_HANDLE) { delete ore; return 0; } ore->m_nodenames.push_back(getstringfield_default(L, index, "ore", "")); size_t nnames = getstringlistfield(L, index, "wherein", &ore->m_nodenames); ore->m_nnlistsizes.push_back(nnames); ndef->pendNodeResolve(ore, NODE_RESOLVE_DEFERRED); lua_pushinteger(L, handle); return 1; }
ContentFeatures read_content_features(lua_State *L, int index) { if(index < 0) index = lua_gettop(L) + 1 + index; ContentFeatures f; /* Cache existence of some callbacks */ lua_getfield(L, index, "on_construct"); if(!lua_isnil(L, -1)) f.has_on_construct = true; lua_pop(L, 1); lua_getfield(L, index, "on_destruct"); if(!lua_isnil(L, -1)) f.has_on_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "after_destruct"); if(!lua_isnil(L, -1)) f.has_after_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "on_rightclick"); f.rightclickable = lua_isfunction(L, -1); lua_pop(L, 1); /* Name */ getstringfield(L, index, "name", f.name); /* Groups */ lua_getfield(L, index, "groups"); read_groups(L, -1, f.groups); lua_pop(L, 1); /* Visual definition */ f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", ScriptApiNode::es_DrawType,NDT_NORMAL); getfloatfield(L, index, "visual_scale", f.visual_scale); /* Meshnode model filename */ getstringfield(L, index, "mesh", f.mesh); // tiles = {} lua_getfield(L, index, "tiles"); // If nil, try the deprecated name "tile_images" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "tile_images", "Deprecated; new name is \"tiles\"."); lua_getfield(L, index, "tile_images"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef[i] = read_tiledef(L, -1, f.drawtype); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==6){ lua_pop(L, 1); break; } } // Copy last value to all remaining textures if(i >= 1){ TileDef lasttile = f.tiledef[i-1]; while(i < 6){ f.tiledef[i] = lasttile; i++; } } } lua_pop(L, 1); // special_tiles = {} lua_getfield(L, index, "special_tiles"); // If nil, try the deprecated name "special_materials" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "special_materials", "Deprecated; new name is \"special_tiles\"."); lua_getfield(L, index, "special_materials"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef_special[i] = read_tiledef(L, -1, f.drawtype); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==CF_SPECIAL_COUNT){ lua_pop(L, 1); break; } } } lua_pop(L, 1); f.alpha = getintfield_default(L, index, "alpha", 255); bool usealpha = getboolfield_default(L, index, "use_texture_alpha", false); if (usealpha) f.alpha = 0; // Read node color. lua_getfield(L, index, "color"); read_color(L, -1, &f.color); lua_pop(L, 1); getstringfield(L, index, "palette", f.palette_name); /* Other stuff */ lua_getfield(L, index, "post_effect_color"); read_color(L, -1, &f.post_effect_color); lua_pop(L, 1); f.param_type = (ContentParamType)getenumfield(L, index, "paramtype", ScriptApiNode::es_ContentParamType, CPT_NONE); f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2", ScriptApiNode::es_ContentParamType2, CPT2_NONE); if (f.palette_name != "" && !(f.param_type_2 == CPT2_COLOR || f.param_type_2 == CPT2_COLORED_FACEDIR || f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) warningstream << "Node " << f.name.c_str() << " has a palette, but not a suitable paramtype2." << std::endl; // Warn about some deprecated fields warn_if_field_exists(L, index, "wall_mounted", "Deprecated; use paramtype2 = 'wallmounted'"); warn_if_field_exists(L, index, "light_propagates", "Deprecated; determined from paramtype"); warn_if_field_exists(L, index, "dug_item", "Deprecated; use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item", "Deprecated; use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item_rarity", "Deprecated; use 'drop' field"); warn_if_field_exists(L, index, "metadata_name", "Deprecated; use on_add and metadata callbacks"); // True for all ground-like things like stone and mud, false for eg. trees getboolfield(L, index, "is_ground_content", f.is_ground_content); f.light_propagates = (f.param_type == CPT_LIGHT); getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates); // This is used for collision detection. // Also for general solidness queries. getboolfield(L, index, "walkable", f.walkable); // Player can point to these getboolfield(L, index, "pointable", f.pointable); // Player can dig these getboolfield(L, index, "diggable", f.diggable); // Player can climb these getboolfield(L, index, "climbable", f.climbable); // Player can build on these getboolfield(L, index, "buildable_to", f.buildable_to); // Liquids flow into and replace node getboolfield(L, index, "floodable", f.floodable); // Whether the node is non-liquid, source liquid or flowing liquid f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype", ScriptApiNode::es_LiquidType, LIQUID_NONE); // If the content is liquid, this is the flowing version of the liquid. getstringfield(L, index, "liquid_alternative_flowing", f.liquid_alternative_flowing); // If the content is liquid, this is the source version of the liquid. getstringfield(L, index, "liquid_alternative_source", f.liquid_alternative_source); // Viscosity for fluid flow, ranging from 1 to 7, with // 1 giving almost instantaneous propagation and 7 being // the slowest possible f.liquid_viscosity = getintfield_default(L, index, "liquid_viscosity", f.liquid_viscosity); f.liquid_range = getintfield_default(L, index, "liquid_range", f.liquid_range); f.leveled = getintfield_default(L, index, "leveled", f.leveled); getboolfield(L, index, "liquid_renewable", f.liquid_renewable); f.drowning = getintfield_default(L, index, "drowning", f.drowning); // Amount of light the node emits f.light_source = getintfield_default(L, index, "light_source", f.light_source); if (f.light_source > LIGHT_MAX) { warningstream << "Node " << f.name.c_str() << " had greater light_source than " << LIGHT_MAX << ", it was reduced." << std::endl; f.light_source = LIGHT_MAX; } f.damage_per_second = getintfield_default(L, index, "damage_per_second", f.damage_per_second); lua_getfield(L, index, "node_box"); if(lua_istable(L, -1)) f.node_box = read_nodebox(L, -1); lua_pop(L, 1); lua_getfield(L, index, "connects_to"); if (lua_istable(L, -1)) { int table = lua_gettop(L); lua_pushnil(L); while (lua_next(L, table) != 0) { // Value at -1 f.connects_to.push_back(lua_tostring(L, -1)); lua_pop(L, 1); } } lua_pop(L, 1); lua_getfield(L, index, "connect_sides"); if (lua_istable(L, -1)) { int table = lua_gettop(L); lua_pushnil(L); while (lua_next(L, table) != 0) { // Value at -1 std::string side(lua_tostring(L, -1)); // Note faces are flipped to make checking easier if (side == "top") f.connect_sides |= 2; else if (side == "bottom") f.connect_sides |= 1; else if (side == "front") f.connect_sides |= 16; else if (side == "left") f.connect_sides |= 32; else if (side == "back") f.connect_sides |= 4; else if (side == "right") f.connect_sides |= 8; else warningstream << "Unknown value for \"connect_sides\": " << side << std::endl; lua_pop(L, 1); } } lua_pop(L, 1); lua_getfield(L, index, "selection_box"); if(lua_istable(L, -1)) f.selection_box = read_nodebox(L, -1); lua_pop(L, 1); lua_getfield(L, index, "collision_box"); if(lua_istable(L, -1)) f.collision_box = read_nodebox(L, -1); lua_pop(L, 1); f.waving = getintfield_default(L, index, "waving", f.waving); // Set to true if paramtype used to be 'facedir_simple' getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple); // Set to true if wall_mounted used to be set to true getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted); // Sound table lua_getfield(L, index, "sounds"); if(lua_istable(L, -1)){ lua_getfield(L, -1, "footstep"); read_soundspec(L, -1, f.sound_footstep); lua_pop(L, 1); lua_getfield(L, -1, "dig"); read_soundspec(L, -1, f.sound_dig); lua_pop(L, 1); lua_getfield(L, -1, "dug"); read_soundspec(L, -1, f.sound_dug); lua_pop(L, 1); } lua_pop(L, 1); return f; }