bool PlayerDatabaseSQLite3::loadPlayer(RemotePlayer *player, PlayerSAO *sao) { verifyDatabase(); str_to_sqlite(m_stmt_player_load, 1, player->getName()); if (sqlite3_step(m_stmt_player_load) != SQLITE_ROW) { sqlite3_reset(m_stmt_player_load); return false; } sao->setPitch(sqlite_to_float(m_stmt_player_load, 0)); sao->setYaw(sqlite_to_float(m_stmt_player_load, 1)); sao->setBasePosition(sqlite_to_v3f(m_stmt_player_load, 2)); sao->setHPRaw((s16) MYMIN(sqlite_to_int(m_stmt_player_load, 5), S16_MAX)); sao->setBreath((u16) MYMIN(sqlite_to_int(m_stmt_player_load, 6), U16_MAX), false); sqlite3_reset(m_stmt_player_load); // Load inventory str_to_sqlite(m_stmt_player_load_inventory, 1, player->getName()); while (sqlite3_step(m_stmt_player_load_inventory) == SQLITE_ROW) { InventoryList *invList = player->inventory.addList( sqlite_to_string(m_stmt_player_load_inventory, 2), sqlite_to_uint(m_stmt_player_load_inventory, 3)); invList->setWidth(sqlite_to_uint(m_stmt_player_load_inventory, 1)); u32 invId = sqlite_to_uint(m_stmt_player_load_inventory, 0); str_to_sqlite(m_stmt_player_load_inventory_items, 1, player->getName()); int_to_sqlite(m_stmt_player_load_inventory_items, 2, invId); while (sqlite3_step(m_stmt_player_load_inventory_items) == SQLITE_ROW) { const std::string itemStr = sqlite_to_string(m_stmt_player_load_inventory_items, 1); if (itemStr.length() > 0) { ItemStack stack; stack.deSerialize(itemStr); invList->addItem(sqlite_to_uint(m_stmt_player_load_inventory_items, 0), stack); } } sqlite3_reset(m_stmt_player_load_inventory_items); } sqlite3_reset(m_stmt_player_load_inventory); str_to_sqlite(m_stmt_player_metadata_load, 1, sao->getPlayer()->getName()); while (sqlite3_step(m_stmt_player_metadata_load) == SQLITE_ROW) { std::string attr = sqlite_to_string(m_stmt_player_metadata_load, 0); std::string value = sqlite_to_string(m_stmt_player_metadata_load, 1); sao->setExtendedAttribute(attr, value); } sqlite3_reset(m_stmt_player_metadata_load); return true; }
// 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; }
ItemStack read_item(lua_State *L, int index) { if(index < 0) index = lua_gettop(L) + 1 + index; if(lua_isnil(L, index)) { return ItemStack(); } else if(lua_isuserdata(L, index)) { // Convert from LuaItemStack LuaItemStack *o = LuaItemStack::checkobject(L, index); return o->getItem(); } else if(lua_isstring(L, index)) { // Convert from itemstring std::string itemstring = lua_tostring(L, index); IItemDefManager *idef = get_server(L)->idef(); try { ItemStack item; item.deSerialize(itemstring, idef); return item; } catch(SerializationError &e) { infostream<<"WARNING: unable to create item from itemstring" <<": "<<itemstring<<std::endl; return ItemStack(); } } else if(lua_istable(L, index)) { // Convert from table IItemDefManager *idef = get_server(L)->idef(); std::string name = getstringfield_default(L, index, "name", ""); int count = getintfield_default(L, index, "count", 1); int wear = getintfield_default(L, index, "wear", 0); std::string metadata = getstringfield_default(L, index, "metadata", ""); return ItemStack(name, count, wear, metadata, idef); } else { throw LuaError(L, "Expecting itemstack, itemstring, table or nil"); } }
ItemStack createItemStack() { try{ IItemDefManager *idef = m_env->getGameDef()->idef(); ItemStack item; item.deSerialize(m_itemstring, idef); infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring <<"\" -> item=\""<<item.getItemString()<<"\"" <<std::endl; return item; } catch(SerializationError &e) { infostream<<__FUNCTION_NAME<<": serialization error: " <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl; return ItemStack(); } }
// Removes 1 from each item stack with replacement support // Example: if replacements contains the pair ("bucket:bucket_water", "bucket:bucket_empty"), // a water bucket will not be removed but replaced by an empty bucket. static void craftDecrementOrReplaceInput(CraftInput &input, std::vector<ItemStack> &output_replacements, const CraftReplacements &replacements, IGameDef *gamedef) { if (replacements.pairs.empty()) { craftDecrementInput(input, gamedef); return; } // Make a copy of the replacements pair list std::vector<std::pair<std::string, std::string> > pairs = replacements.pairs; for (auto &item : input.items) { // Find an appropriate replacement bool found_replacement = false; for (auto j = pairs.begin(); j != pairs.end(); ++j) { if (inputItemMatchesRecipe(item.name, j->first, gamedef->idef())) { if (item.count == 1) { item.deSerialize(j->second, gamedef->idef()); found_replacement = true; pairs.erase(j); break; } ItemStack rep; rep.deSerialize(j->second, gamedef->idef()); item.remove(1); found_replacement = true; output_replacements.push_back(rep); break; } } // No replacement was found, simply decrement count by one if (!found_replacement && item.count > 0) item.remove(1); } }
// Crafting helper bool getCraftingResult(Inventory *inv, ItemStack& result, std::vector<ItemStack> &output_replacements, bool decrementInput, IGameDef *gamedef) { DSTACK(__FUNCTION_NAME); result.clear(); // Get the InventoryList in which we will operate InventoryList *clist = inv->getList("craft"); if(!clist) return false; // Mangle crafting grid to an another format CraftInput ci; ci.method = CRAFT_METHOD_NORMAL; ci.width = clist->getWidth() ? clist->getWidth() : 3; for(u16 i=0; i<clist->getSize(); i++) ci.items.push_back(clist->getItem(i)); // Find out what is crafted and add it to result item slot CraftOutput co; bool found = gamedef->getCraftDefManager()->getCraftResult( ci, co, output_replacements, decrementInput, gamedef); if(found) result.deSerialize(co.item, gamedef->getItemDefManager()); if(found && decrementInput) { // CraftInput has been changed, apply changes in clist for(u16 i=0; i<clist->getSize(); i++) { clist->changeItem(i, ci.items[i]); } } return found; }
// Deserialize an itemstring then return the name of the item static std::string craftGetItemName(const std::string &itemstring, IGameDef *gamedef) { ItemStack item; item.deSerialize(itemstring, gamedef->idef()); return item.name; }
virtual bool getCraftResult(CraftInput &input, CraftOutput &output, std::vector<ItemStack> &output_replacement, bool decrementInput, IGameDef *gamedef) const { output.item = ""; output.time = 0; // If all input items are empty, abort. bool all_empty = true; for (const auto &item : input.items) { if (!item.empty()) { all_empty = false; break; } } if (all_empty) return false; std::vector<std::string> input_names; input_names = craftGetItemNames(input.items, gamedef); std::sort(input_names.begin(), input_names.end()); // Try hash types with increasing collision rate, and return if found. for (int type = 0; type <= craft_hash_type_max; type++) { u64 hash = getHashForGrid((CraftHashType) type, input_names); /*errorstream << "Checking type " << type << " with hash " << hash << std::endl;*/ // We'd like to do "const [...] hash_collisions = m_craft_defs[type][hash];" // but that doesn't compile for some reason. This does. auto col_iter = (m_craft_defs[type]).find(hash); if (col_iter == (m_craft_defs[type]).end()) continue; const std::vector<CraftDefinition*> &hash_collisions = col_iter->second; // Walk crafting definitions from back to front, so that later // definitions can override earlier ones. for (std::vector<CraftDefinition*>::size_type i = hash_collisions.size(); i > 0; i--) { CraftDefinition *def = hash_collisions[i - 1]; /*errorstream << "Checking " << input.dump() << std::endl << " against " << def->dump() << std::endl;*/ if (def->check(input, gamedef)) { // Check if the crafted node/item exists CraftOutput out = def->getOutput(input, gamedef); ItemStack is; is.deSerialize(out.item, gamedef->idef()); if (!is.isKnown(gamedef->idef())) { infostream << "trying to craft non-existent " << out.item << ", ignoring recipe" << std::endl; continue; } // Get output, then decrement input (if requested) output = out; if (decrementInput) def->decrementInput(input, output_replacement, gamedef); /*errorstream << "Check RETURNS TRUE" << std::endl;*/ return true; } } } return false; }
ItemStack read_item(lua_State* L, int index,Server* srv) { if(index < 0) index = lua_gettop(L) + 1 + index; if(lua_isnil(L, index)) { return ItemStack(); } else if(lua_isuserdata(L, index)) { // Convert from LuaItemStack LuaItemStack *o = LuaItemStack::checkobject(L, index); return o->getItem(); } else if(lua_isstring(L, index)) { // Convert from itemstring std::string itemstring = lua_tostring(L, index); IItemDefManager *idef = srv->idef(); try { ItemStack item; item.deSerialize(itemstring, idef); return item; } catch(SerializationError &e) { warningstream<<"unable to create item from itemstring" <<": "<<itemstring<<std::endl; return ItemStack(); } } else if(lua_istable(L, index)) { // Convert from table IItemDefManager *idef = srv->idef(); std::string name = getstringfield_default(L, index, "name", ""); int count = getintfield_default(L, index, "count", 1); int wear = getintfield_default(L, index, "wear", 0); ItemStack istack(name, count, wear, idef); lua_getfield(L, index, "metadata"); // Support old metadata format by checking type int fieldstable = lua_gettop(L); if (lua_istable(L, fieldstable)) { lua_pushnil(L); while (lua_next(L, fieldstable) != 0) { // key at index -2 and value at index -1 std::string key = lua_tostring(L, -2); size_t value_len; const char *value_cs = lua_tolstring(L, -1, &value_len); std::string value(value_cs, value_len); istack.metadata.setString(name, value); lua_pop(L, 1); // removes value, keeps key for next iteration } } else { // BACKWARDS COMPATIBLITY std::string value = getstringfield_default(L, index, "metadata", ""); istack.metadata.setString("", value); } lua_getfield(L, index, "meta"); fieldstable = lua_gettop(L); if (lua_istable(L, fieldstable)) { lua_pushnil(L); while (lua_next(L, fieldstable) != 0) { // key at index -2 and value at index -1 std::string key = lua_tostring(L, -2); size_t value_len; const char *value_cs = lua_tolstring(L, -1, &value_len); std::string value(value_cs, value_len); istack.metadata.setString(name, value); lua_pop(L, 1); // removes value, keeps key for next iteration } } return istack; } else { throw LuaError("Expecting itemstack, itemstring, table or nil"); } }
bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gamedef) const { try{ switch(type){ case TYPE_NOTHING: return true; case TYPE_SET_NODE: { INodeDefManager *ndef = gamedef->ndef(); // Make sure position is loaded from disk map->emergeBlock(getContainerPos(p, MAP_BLOCKSIZE), false); // Check current node MapNode current_node = map->getNodeNoEx(p); std::string current_name = ndef->get(current_node).name; // If current node not the new node, it's bad if(current_name != n_new.name) return false; /*// If current node not the new node and not ignore, it's bad if(current_name != n_new.name && current_name != "ignore") return false;*/ // Create rollback node MapNode n(ndef, n_old.name, n_old.param1, n_old.param2); // Set rollback node try{ if(!map->addNodeWithEvent(p, n)){ infostream<<"RollbackAction::applyRevert(): " <<"AddNodeWithEvent failed at " <<PP(p)<<" for "<<n_old.name<<std::endl; return false; } NodeMetadata *meta = map->getNodeMetadata(p); if(n_old.meta != ""){ if(!meta){ meta = new NodeMetadata(gamedef); if(!map->setNodeMetadata(p, meta)){ delete meta; infostream<<"RollbackAction::applyRevert(): " <<"setNodeMetadata failed at " <<PP(p)<<" for "<<n_old.name<<std::endl; return false; } } std::istringstream is(n_old.meta, std::ios::binary); meta->deSerialize(is); } else { map->removeNodeMetadata(p); } // NOTE: This same code is in scriptapi.cpp // Inform other things that the metadata has changed v3s16 blockpos = getContainerPos(p, MAP_BLOCKSIZE); MapEditEvent event; event.type = MEET_BLOCK_NODE_METADATA_CHANGED; event.p = blockpos; map->dispatchEvent(&event); // Set the block to be saved MapBlock *block = map->getBlockNoCreateNoEx(blockpos); if(block) block->raiseModified(MOD_STATE_WRITE_NEEDED, "NodeMetaRef::reportMetadataChange"); }catch(InvalidPositionException &e){ infostream<<"RollbackAction::applyRevert(): " <<"InvalidPositionException: "<<e.what()<<std::endl; return false; } // Success return true; } case TYPE_MODIFY_INVENTORY_STACK: { InventoryLocation loc; loc.deSerialize(inventory_location); ItemStack stack; stack.deSerialize(inventory_stack, gamedef->idef()); Inventory *inv = imgr->getInventory(loc); if(!inv){ infostream<<"RollbackAction::applyRevert(): Could not get " "inventory at "<<inventory_location<<std::endl; return false; } InventoryList *list = inv->getList(inventory_list); if(!list){ infostream<<"RollbackAction::applyRevert(): Could not get " "inventory list \""<<inventory_list<<"\" in " <<inventory_location<<std::endl; return false; } if(list->getSize() <= inventory_index){ infostream<<"RollbackAction::applyRevert(): List index " <<inventory_index<<" too large in " <<"inventory list \""<<inventory_list<<"\" in " <<inventory_location<<std::endl; } // If item was added, take away item, otherwise add removed item if(inventory_add){ // Silently ignore different current item if(list->getItem(inventory_index).name != stack.name) return false; list->takeItem(inventory_index, stack.count); } else { list->addItem(inventory_index, stack); } // Inventory was modified; send to clients imgr->setInventoryModified(loc); return true; } default: errorstream<<"RollbackAction::applyRevert(): type not handled" <<std::endl; return false; } }catch(SerializationError &e){ errorstream<<"RollbackAction::applyRevert(): n_old.name="<<n_old.name <<", SerializationError: "<<e.what()<<std::endl; } return false; }
void FallingSAO::step(float dtime, bool send_recommended) { // Object pending removal, skip if (m_removed || !m_env) { return; } // If no texture, remove it if (m_prop.textures.empty()) { m_removed = true; return; } LuaEntitySAO::step(dtime, send_recommended); INodeDefManager* ndef = m_env->getGameDef()->getNodeDefManager(); m_acceleration = v3f(0,-10*BS,0); // Under node, center v3f p_under(m_base_position.X, m_base_position.Y - 7, m_base_position.Z); v3s16 p = floatToInt(m_base_position, BS); /* bool cur_exists = false, under_exists = false; */ MapNode n = m_env->getMap().getNode(p), n_under = m_env->getMap().getNode(floatToInt(p_under, BS)); const ContentFeatures &f = ndef->get(n), &f_under = ndef->get(n_under); bool cur_exists = n, under_exists = n_under; // Mapblock current or under is not loaded, stop there if (!n || !cur_exists || !under_exists) { return; } if ((f_under.walkable || (itemgroup_get(f_under.groups, "float") && f_under.liquid_type == LIQUID_NONE))) { if (f_under.leveled && f_under.name.compare(f.name) == 0) { u8 addLevel = n.getLevel(ndef); if (addLevel == 0) { addLevel = n_under.getLevel(ndef); } if (n_under.addLevel(ndef, addLevel)) { m_removed = true; return; } } else if (f_under.buildable_to && (itemgroup_get(f.groups,"float") == 0 || f_under.liquid_type == LIQUID_NONE)) { m_env->removeNode(floatToInt(p_under, BS), fast); return; } if (n.getContent() != CONTENT_AIR && (f.liquid_type == LIQUID_NONE)) { m_env->removeNode(p); if (!f.buildable_to) { ItemStack stack; std::string n_name = ndef->get(m_node).name; stack.deSerialize(n_name); m_env->spawnItemActiveObject(n_name, m_base_position, stack); } } m_env->setNode(p, m_node, fast); m_removed = true; m_env->nodeUpdate(p, 2, fast); return; } }
bool PlayerDatabasePostgreSQL::loadPlayer(RemotePlayer *player, PlayerSAO *sao) { sanity_check(sao); verifyDatabase(); const char *values[] = { player->getName() }; PGresult *results = execPrepared("load_player", 1, values, false, false); // Player not found, return not found if (!PQntuples(results)) { PQclear(results); return false; } sao->setPitch(pg_to_float(results, 0, 0)); sao->setYaw(pg_to_float(results, 0, 1)); sao->setBasePosition(v3f( pg_to_float(results, 0, 2), pg_to_float(results, 0, 3), pg_to_float(results, 0, 4)) ); sao->setHPRaw((s16) pg_to_int(results, 0, 5)); sao->setBreath((u16) pg_to_int(results, 0, 6), false); PQclear(results); // Load inventory results = execPrepared("load_player_inventories", 1, values, false, false); int resultCount = PQntuples(results); for (int row = 0; row < resultCount; ++row) { InventoryList* invList = player->inventory. addList(PQgetvalue(results, row, 2), pg_to_uint(results, row, 3)); invList->setWidth(pg_to_uint(results, row, 1)); u32 invId = pg_to_uint(results, row, 0); std::string invIdStr = itos(invId); const char* values2[] = { player->getName(), invIdStr.c_str() }; PGresult *results2 = execPrepared("load_player_inventory_items", 2, values2, false, false); int resultCount2 = PQntuples(results2); for (int row2 = 0; row2 < resultCount2; row2++) { const std::string itemStr = PQgetvalue(results2, row2, 1); if (itemStr.length() > 0) { ItemStack stack; stack.deSerialize(itemStr); invList->changeItem(pg_to_uint(results2, row2, 0), stack); } } PQclear(results2); } PQclear(results); results = execPrepared("load_player_metadata", 1, values, false); int numrows = PQntuples(results); for (int row = 0; row < numrows; row++) { sao->getMeta().setString(PQgetvalue(results, row, 0), PQgetvalue(results, row, 1)); } sao->getMeta().setModified(false); PQclear(results); return true; }