mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 01:05:48 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			239 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
Minetest-c55
 | 
						|
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
 | 
						|
 | 
						|
This program is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2 of the License, or
 | 
						|
(at your option) any later version.
 | 
						|
 | 
						|
This program is distributed in the hope that it will be useful,
 | 
						|
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
GNU General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License along
 | 
						|
with this program; if not, write to the Free Software Foundation, Inc.,
 | 
						|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
						|
*/
 | 
						|
 | 
						|
#include "craftdef.h"
 | 
						|
 | 
						|
#include "irrlichttypes.h"
 | 
						|
#include "log.h"
 | 
						|
#include <sstream>
 | 
						|
#include "utility.h"
 | 
						|
#include "gamedef.h"
 | 
						|
#include "inventory.h"
 | 
						|
 | 
						|
CraftPointerInput::~CraftPointerInput()
 | 
						|
{
 | 
						|
	for(u32 i=0; i<items.size(); i++)
 | 
						|
		delete items[i];
 | 
						|
}
 | 
						|
 | 
						|
CraftPointerInput createPointerInput(const CraftInput &ci, IGameDef *gamedef)
 | 
						|
{
 | 
						|
	std::vector<InventoryItem*> items;
 | 
						|
	for(u32 i=0; i<ci.items.size(); i++){
 | 
						|
		InventoryItem *item = NULL;
 | 
						|
		if(ci.items[i] != ""){
 | 
						|
			std::istringstream iss(ci.items[i], std::ios::binary);
 | 
						|
			item = InventoryItem::deSerialize(iss, gamedef);
 | 
						|
		}
 | 
						|
		items.push_back(item);
 | 
						|
	}
 | 
						|
	return CraftPointerInput(ci.width, items);
 | 
						|
}
 | 
						|
 | 
						|
CraftInput createInput(const CraftPointerInput &cpi)
 | 
						|
{
 | 
						|
	std::vector<std::string> items;
 | 
						|
	for(u32 i=0; i<cpi.items.size(); i++){
 | 
						|
		if(cpi.items[i] == NULL)
 | 
						|
			items.push_back("");
 | 
						|
		else{
 | 
						|
			std::ostringstream oss(std::ios::binary);
 | 
						|
			cpi.items[i]->serialize(oss);
 | 
						|
			items.push_back(oss.str());
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return CraftInput(cpi.width, items);
 | 
						|
}
 | 
						|
 | 
						|
std::string CraftInput::dump() const
 | 
						|
{
 | 
						|
	std::ostringstream os(std::ios::binary);
 | 
						|
	os<<"(width="<<width<<"){";
 | 
						|
	for(u32 i=0; i<items.size(); i++)
 | 
						|
		os<<"\""<<items[i]<<"\",";
 | 
						|
	os<<"}";
 | 
						|
	return os.str();
 | 
						|
}
 | 
						|
 | 
						|
std::string CraftDefinition::dump() const
 | 
						|
{
 | 
						|
	std::ostringstream os(std::ios::binary);
 | 
						|
	os<<"{output=\""<<output<<"\", input={";
 | 
						|
	for(u32 i=0; i<input.items.size(); i++)
 | 
						|
		os<<"\""<<input.items[i]<<"\",";
 | 
						|
	os<<"}, (input.width="<<input.width<<")}";
 | 
						|
	return os.str();
 | 
						|
}
 | 
						|
 | 
						|
void CraftDefinition::serialize(std::ostream &os) const
 | 
						|
{
 | 
						|
	writeU8(os, 0); // version
 | 
						|
	os<<serializeString(output);
 | 
						|
	writeU8(os, input.width);
 | 
						|
	writeU16(os, input.items.size());
 | 
						|
	for(u32 i=0; i<input.items.size(); i++)
 | 
						|
		os<<serializeString(input.items[i]);
 | 
						|
}
 | 
						|
 | 
						|
void CraftDefinition::deSerialize(std::istream &is)
 | 
						|
{
 | 
						|
	int version = readU8(is);
 | 
						|
	if(version != 0) throw SerializationError(
 | 
						|
			"unsupported CraftDefinition version");
 | 
						|
	output = deSerializeString(is);
 | 
						|
	input.width = readU8(is);
 | 
						|
	u32 count = readU16(is);
 | 
						|
	for(u32 i=0; i<count; i++)
 | 
						|
		input.items.push_back(deSerializeString(is));
 | 
						|
}
 | 
						|
 | 
						|
class CCraftDefManager: public IWritableCraftDefManager
 | 
						|
{
 | 
						|
public:
 | 
						|
	virtual ~CCraftDefManager()
 | 
						|
	{
 | 
						|
		clear();
 | 
						|
	}
 | 
						|
	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;
 | 
						|
	}
 | 
						|
	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));
 | 
						|
	}
 | 
						|
	virtual void clear()
 | 
						|
	{
 | 
						|
		for(core::list<CraftDefinition*>::Iterator
 | 
						|
				i = m_craft_definitions.begin();
 | 
						|
				i != m_craft_definitions.end(); i++){
 | 
						|
			delete *i;
 | 
						|
		}
 | 
						|
		m_craft_definitions.clear();
 | 
						|
	}
 | 
						|
	virtual void serialize(std::ostream &os)
 | 
						|
	{
 | 
						|
		writeU8(os, 0); // version
 | 
						|
		u16 count = m_craft_definitions.size();
 | 
						|
		writeU16(os, count);
 | 
						|
		for(core::list<CraftDefinition*>::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());
 | 
						|
		}
 | 
						|
	}
 | 
						|
	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);
 | 
						|
		}
 | 
						|
	}
 | 
						|
private:
 | 
						|
	core::list<CraftDefinition*> m_craft_definitions;
 | 
						|
};
 | 
						|
 | 
						|
IWritableCraftDefManager* createCraftDefManager()
 | 
						|
{
 | 
						|
	return new CCraftDefManager();
 | 
						|
}
 | 
						|
 |