Exemplo n.º 1
0
	virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
			bool decrementInput, IGameDef *gamedef) const
	{
		output.item = "";
		output.time = 0;

		// If all input items are empty, abort.
		bool all_empty = true;
		for (std::vector<ItemStack>::const_iterator
				it = input.items.begin();
				it != input.items.end(); it++) {
			if (!it->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.
			std::map<u64, std::vector<CraftDefinition*> >::const_iterator
				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*>::const_reverse_iterator
					it = hash_collisions.rbegin();
					it != hash_collisions.rend(); it++) {
				CraftDefinition *def = *it;

				/*errorstream << "Checking " << input.dump() << std::endl
					<< " against " << def->dump() << std::endl;*/

				if (def->check(input, gamedef)) {
					// Get output, then decrement input (if requested)
					output = def->getOutput(input, gamedef);
					if (decrementInput)
						def->decrementInput(input, gamedef);
					/*errorstream << "Check RETURNS TRUE" << std::endl;*/
					return true;
				}
			}
		}
		return false;
	}
Exemplo n.º 2
0
CraftDefinition* CraftDefinition::deSerialize(std::istream &is)
{
	int version = readU8(is);
	if(version != 1) throw SerializationError(
			"unsupported CraftDefinition version");
	std::string name = deSerializeString(is);
	CraftDefinition *def = NULL;
	if(name == "shaped")
	{
		def = new CraftDefinitionShaped;
	}
	else if(name == "shapeless")
	{
		def = new CraftDefinitionShapeless;
	}
	else if(name == "toolrepair")
	{
		def = new CraftDefinitionToolRepair;
	}
	else if(name == "cooking")
	{
		def = new CraftDefinitionCooking;
	}
	else if(name == "fuel")
	{
		def = new CraftDefinitionFuel;
	}
	else
	{
		infostream<<"Unknown CraftDefinition name=\""<<name<<"\""<<std::endl;
                throw SerializationError("Unknown CraftDefinition name");
	}
	def->deSerializeBody(is, version);
	return def;
}
Exemplo n.º 3
0
	virtual bool clearCraftRecipesByInput(CraftMethod craft_method, unsigned int craft_grid_width,
		const std::vector<std::string> &recipe, IGameDef *gamedef)
	{
		bool all_empty = true;
		for (const auto &i : recipe) {
			if (!i.empty()) {
				all_empty = false;
				break;
			}
		}
		if (all_empty)
			return false;

		CraftInput input(craft_method, craft_grid_width, craftGetItems(recipe, gamedef));
		// Recipes are not yet hashed at this point
		std::vector<CraftDefinition*> &unhashed_inputs_vec = m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0];
		std::vector<CraftDefinition*> new_vec_by_input;
		bool got_hit = false;
		for (std::vector<CraftDefinition*>::size_type
				i = unhashed_inputs_vec.size(); i > 0; i--) {
			CraftDefinition *def = unhashed_inputs_vec[i - 1];
			/* If the input doesn't match the recipe definition, this recipe definition later
				will be added back in source map. */
			if (!def->check(input, gamedef)) {
				new_vec_by_input.push_back(def);
				continue;
			}
			CraftOutput output = def->getOutput(input, gamedef);
			got_hit = true;
			auto vec_iter = m_output_craft_definitions.find(output.item);
			if (vec_iter == m_output_craft_definitions.end())
				continue;
			std::vector<CraftDefinition*> &vec = vec_iter->second;
			std::vector<CraftDefinition*> new_vec_by_output;
			/* We will preallocate necessary memory addresses, so we don't need
				to reallocate them later. This would save us some performance. */
			new_vec_by_output.reserve(vec.size());
			for (auto &vec_i : vec) {
				/* If pointers from map by input and output are not same,
					we will add 'CraftDefinition*' to a new vector. */
				if (def != vec_i) {
					/* Adding dereferenced iterator value (which are
						'CraftDefinition' reference) to a new vector. */
					new_vec_by_output.push_back(vec_i);
				}
			}
			// Swaps assigned to current key value with new vector for output map.
			m_output_craft_definitions[output.item].swap(new_vec_by_output);
		}
		if (got_hit)
			// Swaps value with new vector for input map.
			m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].swap(new_vec_by_input);

		return got_hit;
	}
Exemplo n.º 4
0
	virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
			bool decrementInput, IGameDef *gamedef) const
	{
		output.item = "";
		output.time = 0;

		// If all input items are empty, abort.
		bool all_empty = true;
		for(std::vector<ItemStack>::const_iterator
				i = input.items.begin();
				i != input.items.end(); i++)
		{
			if(!i->empty())
			{
				all_empty = false;
				break;
			}
		}
		if(all_empty)
			return false;

		// Walk crafting definitions from back to front, so that later
		// definitions can override earlier ones.
		for(std::vector<CraftDefinition*>::const_reverse_iterator
				i = m_craft_definitions.rbegin();
				i != m_craft_definitions.rend(); i++)
		{
			CraftDefinition *def = *i;

			/*infostream<<"Checking "<<input.dump()<<std::endl
					<<" against "<<def->dump()<<std::endl;*/

			try {
				if(def->check(input, gamedef))
				{
					// Get output, then decrement input (if requested)
					output = def->getOutput(input, gamedef);
					if(decrementInput)
						def->decrementInput(input, gamedef);
					return true;
				}
			}
			catch(SerializationError &e)
			{
				errorstream<<"getCraftResult: ERROR: "
						<<"Serialization error in recipe "
						<<def->dump()<<std::endl;
				// then go on with the next craft definition
			}
		}
		return false;
	}
Exemplo n.º 5
0
	virtual void serialize(std::ostream &os) const
	{
		writeU8(os, 0); // version
		u16 count = m_craft_definitions.size();
		writeU16(os, count);
		for(std::vector<CraftDefinition*>::const_iterator
				i = m_craft_definitions.begin();
				i != m_craft_definitions.end(); i++){
			CraftDefinition *def = *i;
			// Serialize wrapped in a string
			std::ostringstream tmp_os(std::ios::binary);
			def->serialize(tmp_os);
			os<<serializeString(tmp_os.str());
		}
	}
Exemplo n.º 6
0
	virtual void initHashes(IGameDef *gamedef)
	{
		// Move the CraftDefs from the unhashed layer into layers higher up.
		for (std::vector<CraftDefinition*>::iterator
			it = (m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0]).begin();
			it != (m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0]).end(); it++) {
			CraftDefinition *def = *it;

			// Initialize and get the definition's hash
			def->initHash(gamedef);
			CraftHashType type = def->getHashType();
			u64 hash = def->getHash(type);

			// Enter the definition
			m_craft_defs[type][hash].push_back(def);
		}
		m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].clear();
	}
Exemplo n.º 7
0
	virtual void deSerialize(std::istream &is)
	{
		// Clear everything
		clear();
		// Deserialize
		int version = readU8(is);
		if(version != 0) throw SerializationError(
				"unsupported CraftDefManager version");
		u16 count = readU16(is);
		for(u16 i=0; i<count; i++){
			// Deserialize a string and grab a CraftDefinition from it
			std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
			CraftDefinition def;
			def.deSerialize(tmp_is);
			// Register
			registerCraft(def);
		}
	}
Exemplo n.º 8
0
	virtual void registerCraft(const CraftDefinition &def)
	{
		infostream<<"registerCraft: registering craft definition: "
				<<def.dump()<<std::endl;
		if(def.input.width > 3 || def.input.height() > 3){
			errorstream<<"registerCraft: input size is larger than 3x3,"
					<<" ignoring"<<std::endl;
			return;
		}
		m_craft_definitions.push_back(new CraftDefinition(def));
	}
Exemplo n.º 9
0
	virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
			IGameDef *gamedef) const
	{
		CraftOutput tmpout;
		tmpout.item = "";
		tmpout.time = 0;

		// If output item is empty, abort.
		if(output.item.empty())
			return false;

		// Walk crafting definitions from back to front, so that later
		// definitions can override earlier ones.
		for(std::vector<CraftDefinition*>::const_reverse_iterator
				i = m_craft_definitions.rbegin();
				i != m_craft_definitions.rend(); i++)
		{
			CraftDefinition *def = *i;

			/*infostream<<"Checking "<<input.dump()<<std::endl
					<<" against "<<def->dump()<<std::endl;*/

			try {
				tmpout = def->getOutput(input, gamedef);
				if(tmpout.item.substr(0,output.item.length()) == output.item)
				{
					// Get output, then decrement input (if requested)
					input = def->getInput(output, gamedef);
					return true;
				}
			}
			catch(SerializationError &e)
			{
				errorstream<<"getCraftResult: ERROR: "
						<<"Serialization error in recipe "
						<<def->dump()<<std::endl;
				// then go on with the next craft definition
			}
		}
		return false;
	}
Exemplo n.º 10
0
	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;
	}
Exemplo n.º 11
0
// get_all_craft_recipes(result item)
int ModApiCraft::l_get_all_craft_recipes(lua_State *L)
{
	NO_MAP_LOCK_REQUIRED;

	std::string o_item = luaL_checkstring(L,1);
	IGameDef *gdef = getServer(L);
	ICraftDefManager *cdef = gdef->cdef();
	CraftInput input;
	CraftOutput output(o_item,0);
	std::vector<CraftDefinition*> recipes_list = cdef->getCraftRecipes(output, gdef);
	if (recipes_list.empty())
	{
		lua_pushnil(L);
		return 1;
	}
	// Get the table insert function
	lua_getglobal(L, "table");
	lua_getfield(L, -1, "insert");
	int table_insert = lua_gettop(L);
	lua_newtable(L);
	int table = lua_gettop(L);
	for (std::vector<CraftDefinition*>::const_iterator
		i = recipes_list.begin();
		i != recipes_list.end(); i++)
	{
		CraftOutput tmpout;
		tmpout.item = "";
		tmpout.time = 0;
		CraftDefinition *def = *i;
		tmpout = def->getOutput(input, gdef);
		std::string query = tmpout.item;
		char *fmtpos, *fmt = &query[0];
		if (strtok_r(fmt, " ", &fmtpos) == output.item)
		{
			input = def->getInput(output, gdef);
			lua_pushvalue(L, table_insert);
			lua_pushvalue(L, table);
			lua_newtable(L);
			int k = 1;
			lua_newtable(L);
			for(std::vector<ItemStack>::const_iterator
				i = input.items.begin();
				i != input.items.end(); i++, k++)
			{
				if (i->empty())
					continue;
				lua_pushinteger(L,k);
				lua_pushstring(L,i->name.c_str());
				lua_settable(L, -3);
			}
			lua_setfield(L, -2, "items");
			setintfield(L, -1, "width", input.width);
			switch (input.method) {
				case CRAFT_METHOD_NORMAL:
					lua_pushstring(L,"normal");
					break;
				case CRAFT_METHOD_COOKING:
					lua_pushstring(L,"cooking");
					break;
				case CRAFT_METHOD_FUEL:
					lua_pushstring(L,"fuel");
					break;
				default:
					lua_pushstring(L,"unknown");
				}
			lua_setfield(L, -2, "type");
			lua_pushstring(L, &tmpout.item[0]);
			lua_setfield(L, -2, "output");
			if (lua_pcall(L, 2, 0, 0))
				script_error(L);
		}
	}
	return 1;
}
Exemplo n.º 12
0
	virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
			IGameDef *gamedef) const
	{
		if(input_cpi.width > 3){
			errorstream<<"getCraftResult(): ERROR: "
					<<"input_cpi.width > 3; Failing to craft."<<std::endl;
			return NULL;
		}
		InventoryItem *input_items[9];
		for(u32 y=0; y<3; y++)
		for(u32 x=0; x<3; x++)
		{
			u32 i=y*3+x;
			if(x >= input_cpi.width || y >= input_cpi.height())
				input_items[i] = NULL;
			else
				input_items[i] = input_cpi.items[y*input_cpi.width+x];
		}
		for(core::list<CraftDefinition*>::ConstIterator
				i = m_craft_definitions.begin();
				i != m_craft_definitions.end(); i++)
		{
			CraftDefinition *def = *i;

			/*infostream<<"Checking "<<createInput(input_cpi).dump()<<std::endl
					<<" against "<<def->input.dump()
					<<" (output=\""<<def->output<<"\")"<<std::endl;*/

			try {
				CraftPointerInput spec_cpi = createPointerInput(def->input, gamedef);
				if(spec_cpi.width > 3){
					errorstream<<"getCraftResult: ERROR: "
							<<"spec_cpi.width > 3 in recipe "
							<<def->dump()<<std::endl;
					continue;
				}
				InventoryItem *spec_items[9];
				for(u32 y=0; y<3; y++)
				for(u32 x=0; x<3; x++)
				{
					u32 i=y*3+x;
					if(x >= spec_cpi.width || y >= spec_cpi.height())
						spec_items[i] = NULL;
					else
						spec_items[i] = spec_cpi.items[y*spec_cpi.width+x];
				}

				bool match = checkItemCombination(input_items, spec_items);

				if(match){
					std::istringstream iss(def->output, std::ios::binary);
					return InventoryItem::deSerialize(iss, gamedef);
				}
			}
			catch(SerializationError &e)
			{
				errorstream<<"getCraftResult: ERROR: "
						<<"Serialization error in recipe "
						<<def->dump()<<std::endl;
				// then go on with the next craft definition
			}
		}
		return NULL;
	}