浏览代码

players can now craft items using a basic shaped crafter

Kolja Strohm 2 年之前
父节点
当前提交
ab403e6da4

+ 116 - 8
FactoryCraft/CraftingStorage.cpp

@@ -1,7 +1,15 @@
+#include <InMemoryBuffer.h>
+
 #include "CraftingStorage.h"
+#include "Game.h"
+#include "Inventory.h"
+#include "Item.h"
+
 
-BasicShapedCrafter::BasicShapedCrafter(int width, int height, Inventory* zInventory)
+BasicShapedCrafter::BasicShapedCrafter(int width, int height, Inventory* zInventory, Framework::Text recipieList)
 	: zInventory(zInventory),
+	currentRecipie(0),
+	recipieList(recipieList),
 	width(width),
 	height(height)
 {
@@ -11,6 +19,67 @@ BasicShapedCrafter::BasicShapedCrafter(int width, int height, Inventory* zInvent
 		zInventory->addSlot(slot);
 		craftingInput.add(slot);
 	}
+	std::function<void(ItemSlot* zSlot, Direction dir, const Item* zItem, int count)> onChange = [this, recipieList](ItemSlot* zSlot, Direction dir, const Item* zItem, int count)
+	{
+		if (!zSlot->getName().istGleich("CraftingGrid"))
+			return;
+		calculateOutputPreview();
+	};
+	zInventory->registerAfterPullStackCall(onChange);
+	zInventory->registerAfterPushStackCall(onChange);
+	zInventory->registerObserverAddedCall([this](Entity* zSource, Framework::Text id)
+		{
+			ShapedRecipie* old = currentRecipie;
+			calculateOutputPreview();
+			if (old == currentRecipie)
+			{
+				NetworkMessage message;
+				getOutputPreview(message);
+				message.adressGui(id);
+				Game::INSTANCE->sendMessage(&message, zSource);
+			}
+		});
+}
+
+void BasicShapedCrafter::getOutputPreview(NetworkMessage& message)
+{
+	if (currentRecipie)
+	{
+		Framework::Array<ItemInfo> output = currentRecipie->getOutput(this);
+		Framework::InMemoryBuffer buffer;
+		int count = 0;
+		for (ItemInfo slot : output)
+		{
+			count++;
+			int itemCount = slot.count;
+			buffer.schreibe((char*)&itemCount, 4);
+			if (itemCount > 0)
+			{
+				float f = slot.damage;
+				buffer.schreibe((char*)&f, 4);
+				f = slot.maxDamage;
+				buffer.schreibe((char*)&f, 4);
+				f = slot.durability;
+				buffer.schreibe((char*)&f, 4);
+				f = slot.maxDurability;
+				buffer.schreibe((char*)&f, 4);
+				int id = slot.type;
+				buffer.schreibe((char*)&id, 4);
+			}
+		}
+		char* msg = new char[5 + buffer.getSize()];
+		msg[0] = 100; // set crafting result
+		*(int*)(msg + 1) = count;
+		buffer.lese(msg + 5, (int)buffer.getSize());
+		message.setMessage(msg, 5 + (int)buffer.getSize(), 1);
+	}
+	else
+	{
+		char msg[5];
+		msg[0] = 100; // set crafting result
+		*(int*)(msg + 1) = 0;
+		message.setMessage(msg, 5, 0);
+	}
 }
 
 bool BasicShapedCrafter::isAllAvailable(Framework::RCArray<ItemFilter>& filters, int width, int height)
@@ -19,28 +88,45 @@ bool BasicShapedCrafter::isAllAvailable(Framework::RCArray<ItemFilter>& filters,
 	{
 		for (int y = 0; y <= this->height - height; y++)
 		{
+			bool wrong = 0;
 			for (int w = 0; w < width; w++)
 			{
 				for (int h = 0; h < height; h++)
 				{
-					ItemFilter* f = filters.z(w * width + h);
-					ItemSlot* s = craftingInput.get(w * 2 + h);
+					ItemFilter* f = filters.z(h * width + w);
+					ItemSlot* s = craftingInput.get((h + y) * this->width + (x + w));
 					const Item* item = 0;
 					if (s && s->zStack())
 						item = s->zStack()->zItem();
-					if ((item && !f) || (!item && f)) return 0;
-					if (item && f && !f->matchItem(item))
-						return 0;
+					wrong |= (item && !f) || (!item && f);
+					wrong |= item && f && !f->matchItem(item);
+					if (wrong)
+						break;
+				}
+				if (wrong)
+					break;
+			}
+			if (!wrong)
+			{
+				int i = 0;
+				for (ItemSlot* slot : craftingInput)
+				{
+					int w = i % this->width;
+					int h = i / this->width;
+					if ((w < x || w >= x + width || h < y || h >= y + height) && slot->zStack())
+						return 0; // more items then needed are in crafting grid
+					i++;
 				}
+				return 1;
 			}
 		}
 	}
-	return 1;
+	return 0;
 }
 
 bool BasicShapedCrafter::hasFreeSpace(const Item* zItem, int amount)
 {
-	ItemStack* stack = new ItemStack((Item*)zItem, amount);
+	ItemStack* stack = new ItemStack(zItem->zItemType()->cloneItem(zItem), amount);
 	int addable = zInventory->numberOfAddableItems(stack, NO_DIRECTION);
 	stack->release();
 	return addable >= amount;
@@ -77,4 +163,26 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters, int wi
 void BasicShapedCrafter::addCraftingResult(ItemStack* stack)
 {
 	zInventory->addItems(stack, NO_DIRECTION);
+}
+
+void BasicShapedCrafter::applyCurrentRecipie()
+{
+	if (currentRecipie && currentRecipie->testApplicability(this))
+		currentRecipie->apply(this);
+}
+
+void BasicShapedCrafter::calculateOutputPreview()
+{
+	ShapedRecipieList* recipies = Game::INSTANCE->getRecipies().zShapedRecipieList(recipieList);
+	if (recipies)
+	{
+		ShapedRecipie* recipie = recipies->zFirstRecipie(this);
+		if (recipie != currentRecipie)
+		{
+			currentRecipie = recipie;
+			NetworkMessage message;
+			getOutputPreview(message);
+			zInventory->notyObservers(message);
+		}
+	}
 }

+ 8 - 1
FactoryCraft/CraftingStorage.h

@@ -5,6 +5,7 @@
 #include "ItemFilter.h"
 #include "ItemSlot.h"
 #include "Inventory.h"
+#include "Recipie.h"
 
 
 class CraftingStorage
@@ -30,13 +31,19 @@ class BasicShapedCrafter : public ShapedCraftingStorage
 private:
 	Framework::Array<ItemSlot*> craftingInput;
 	Inventory* zInventory;
+	ShapedRecipie* currentRecipie;
+	Framework::Text recipieList;
 	int width;
 	int height;
 
+	void getOutputPreview(NetworkMessage& msg);
+
 public:
-	BasicShapedCrafter(int width, int height, Inventory* zInventory);
+	BasicShapedCrafter(int width, int height, Inventory* zInventory, Framework::Text recipieList);
 	virtual bool isAllAvailable(Framework::RCArray<ItemFilter>& filters, int width, int height);
 	virtual bool hasFreeSpace(const Item* zItem, int amount);
 	virtual bool consume(Framework::RCArray<ItemFilter>& filters, int width, int height);
 	virtual void addCraftingResult(ItemStack* stack);
+	void applyCurrentRecipie();
+	void calculateOutputPreview();
 };

+ 23 - 1
FactoryCraft/Game.cpp

@@ -256,7 +256,9 @@ Game::Game(Framework::Text name, Framework::Text worldsDir)
 	tickId(0),
 	nextEntityId(0),
 	generator(0),
-	loader(0)
+	loader(0),
+	totalTickTime(0),
+	tickCounter(0)
 {
 	if (!DateiExistiert(worldsDir + "/" + name))
 		DateiPfadErstellen(worldsDir + "/" + name + "/");
@@ -338,6 +340,22 @@ void Game::thread()
 		cs.unlock();
 		m.messungEnde();
 		double sec = m.getSekunden();
+		tickCounter++;
+		totalTickTime += sec;
+		if (tickCounter >= 1000)
+		{
+			std::cout << "Average Tick time: " << (totalTickTime / 1000) << "\n";
+			if ((totalTickTime / 1000) * 30 > 1)
+			{
+				std::cout << "The game runns slower than normal.\n";
+			}
+			else
+			{
+				std::cout << "No performance issues detected.\n";
+			}
+			totalTickTime = 0;
+			tickCounter = 0;
+		}
 		if (sec < 0.05)
 			Sleep((int)((0.05 - sec) * 1000));
 		else
@@ -642,3 +660,7 @@ Entity* Game::zNearestEntity(int dimensionId, Framework::Vec3<float> pos, std::f
 	return d->zNearestEntity(pos, filter);
 }
 
+const RecipieLoader& Game::getRecipies() const
+{
+	return recipies;
+}

+ 3 - 0
FactoryCraft/Game.h

@@ -75,6 +75,8 @@ private:
 	WorldGenerator* generator;
 	WorldLoader* loader;
 	RecipieLoader recipies;
+	double totalTickTime;
+	int tickCounter;
 
 	void thread() override;
 
@@ -104,6 +106,7 @@ public:
 	Entity* zEntity(int id, int dimensionId) const;
 	Entity* zEntity(int id) const;
 	Entity* zNearestEntity(int dimensionId, Framework::Vec3<float> pos, std::function<bool(Entity*)> filter);
+	const RecipieLoader& getRecipies() const;
 
 	static Game* INSTANCE;
 	static void initialize(Framework::Text name, Framework::Text worldsDir);

+ 2 - 0
FactoryCraft/GrasslandBiom.cpp

@@ -23,6 +23,8 @@ GrasslandBiom::~GrasslandBiom()
 
 Framework::Either<Block*, int> GrasslandBiom::generateSurfaceBlock(int x, int y, int z)
 {
+	if (((float)rand() / (float)RAND_MAX) < 0.05f) // TODO: use random noise
+		return CobbleBlockType::ID;
 	return DirtBlockType::ID;
 }
 

+ 90 - 22
FactoryCraft/Inventory.cpp

@@ -97,7 +97,8 @@ void InventoryInteraction::transaction(Inventory* zSource, Inventory* zTarget, I
 		while (sourceSlot && (sourceSlot->getNumberOfItems() == 0 || (zFilter && !zFilter->matchSourceSlot(sourceSlot))))
 			sourceSlot++;
 		if (!sourceSlot) break;
-		// TODO: use target cache ot get list of slots that already contains the source item
+		// TODO: use target cache ot get list of slots that already contains the source ite
+		bool needNext = 1;
 		for (auto targetSlot = zTarget->pushSlotsOrder->begin(); targetSlot; )
 		{
 			while (targetSlot && (targetSlot->isFull() || (zFilter && !zFilter->matchTargetSlot(targetSlot))))
@@ -124,7 +125,8 @@ void InventoryInteraction::transaction(Inventory* zSource, Inventory* zTarget, I
 							stack->release();
 							count -= number;
 							if (count == 0)
-								break;
+								return;
+							needNext = 0;
 						}
 						else
 							targetSlot++;
@@ -158,6 +160,7 @@ void InventoryInteraction::transaction(Inventory* zSource, Inventory* zTarget, I
 							count -= number;
 							if (count == 0)
 								return;
+							needNext = 0;
 						}
 						else
 							targetSlot++;
@@ -171,6 +174,8 @@ void InventoryInteraction::transaction(Inventory* zSource, Inventory* zTarget, I
 			if (sourceSlot->getNumberOfItems() == 0)
 				break;
 		}
+		if (needNext)
+			sourceSlot++;
 	}
 }
 
@@ -305,6 +310,8 @@ void Inventory::afterPullStack(ItemSlot* zSlot, Direction dir, const Item* zItem
 	*(int*)(message + 5) = zSlot->getNumberOfItems();
 	msg.setMessage(message, 9, 0);
 	notyObservers(msg);
+	for (auto call : afterPullStackCalls)
+		call(zSlot, dir, zItem, count);
 }
 
 void Inventory::afterPushStack(ItemSlot* zSlot, Direction dir, const Item* zItem, int count)
@@ -335,6 +342,8 @@ void Inventory::afterPushStack(ItemSlot* zSlot, Direction dir, const Item* zItem
 		msg.setMessage(message, 29, 0);
 		notyObservers(msg);
 	}
+	for (auto call : afterPushStackCalls)
+		call(zSlot, dir, zItem, count);
 }
 
 void Inventory::loadInventory(Framework::StreamReader* zReader)
@@ -418,6 +427,23 @@ void Inventory::removeObserver(Entity* zSource, Framework::Text id)
 	cs.unlock();
 }
 
+void Inventory::addObserver(Entity* zSource, Framework::Text id)
+{
+	cs.lock();
+	for (auto observer : observers)
+	{
+		if (observer.getFirst() == zSource->getId() && observer.getSecond().istGleich(id))
+		{
+			cs.unlock();
+			return;
+		}
+	}
+	observers.add(ImmutablePair<int, Text>(zSource->getId(), id));
+	cs.unlock();
+	for (auto call : observerAddedCalls)
+		call(zSource, id);
+}
+
 const ItemSlot* Inventory::zSlot(int id) const
 {
 	if (itemCache)
@@ -527,9 +553,9 @@ void Inventory::localTransaction(Array< ItemSlot* >* zSourceSlots, Array< ItemSl
 	}
 }
 
-void Inventory::addItems(ItemStack* items, Direction dir)
+void Inventory::addItems(ItemStack* zItems, Direction dir)
 {
-	if (itemCache && items && items->getSize() > 0)
+	if (itemCache && zItems && zItems->getSize() > 0)
 	{
 		cs.lock();
 		for (auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++)
@@ -538,32 +564,35 @@ void Inventory::addItems(ItemStack* items, Direction dir)
 			{
 				if (targetSlot->zStack())
 				{
-					int number = MIN(targetSlot->numberOfAddableItems(items, dir), items->getSize());
-					int tmp = number;
-					if (number > 0 && allowPushStack(targetSlot, dir, items->zItem(), tmp))
+					if (targetSlot->zStack()->zItem()->canBeStackedWith(zItems->zItem()))
 					{
-						number = MIN(number, tmp);
-						ItemStack* stack = items->split(number);
-						if (stack)
+						int number = MIN(targetSlot->numberOfAddableItems(zItems, dir), zItems->getSize());
+						int tmp = number;
+						if (number > 0 && allowPushStack(targetSlot, dir, zItems->zItem(), tmp))
 						{
-							targetSlot->addItems(stack, dir);
-							afterPushStack(targetSlot, dir, targetSlot->zStack()->zItem(), number);
-							if (stack->getSize())
-								throw stack;
-							stack->release();
-							if (!items->getSize())
-								break;
+							number = MIN(number, tmp);
+							ItemStack* stack = zItems->split(number);
+							if (stack)
+							{
+								targetSlot->addItems(stack, dir);
+								afterPushStack(targetSlot, dir, targetSlot->zStack()->zItem(), number);
+								if (stack->getSize())
+									throw stack;
+								stack->release();
+								if (!zItems->getSize())
+									break;
+							}
 						}
 					}
 				}
 				else
 				{
-					int number = MIN(targetSlot->numberOfAddableItems(items, dir), items->getSize());
+					int number = MIN(targetSlot->numberOfAddableItems(zItems, dir), zItems->getSize());
 					int tmp = number;
-					if (number > 0 && allowPushStack(targetSlot, dir, items->zItem(), tmp))
+					if (number > 0 && allowPushStack(targetSlot, dir, zItems->zItem(), tmp))
 					{
 						number = MIN(number, tmp);
-						ItemStack* stack = items->split(number);
+						ItemStack* stack = zItems->split(number);
 						if (stack)
 						{
 							targetSlot->addItems(stack, dir);
@@ -572,7 +601,7 @@ void Inventory::addItems(ItemStack* items, Direction dir)
 							if (stack->getSize())
 								throw stack;
 							stack->release();
-							if (!items->getSize())
+							if (!zItems->getSize())
 								break;
 						}
 					}
@@ -583,6 +612,30 @@ void Inventory::addItems(ItemStack* items, Direction dir)
 	}
 }
 
+void Inventory::addItems(ItemSlot* zSlot, ItemStack* zItems, Direction dir)
+{
+	if (zSlot->zStack() && !zSlot->zStack()->zItem()->canBeStackedWith(zItems->zItem()))
+		return;
+	bool needUpdate = !zSlot->zStack();
+	int number = MIN(zSlot->numberOfAddableItems(zItems, dir), zItems->getSize());
+	int tmp = number;
+	if (number > 0 && allowPushStack(zSlot, dir, zItems->zItem(), tmp))
+	{
+		number = MIN(number, tmp);
+		ItemStack* stack = zItems->split(number);
+		if (stack)
+		{
+			zSlot->addItems(stack, dir);
+			if (needUpdate)
+				updateCache(zSlot, -1);
+			afterPushStack(zSlot, dir, zSlot->zStack()->zItem(), number);
+			if (stack->getSize())
+				throw stack;
+			stack->release();
+		}
+	}
+}
+
 ItemStack* Inventory::takeItemsOut(ItemSlot* zSlot, int count, Direction dir)
 {
 	if (allowPullStack(zSlot, dir))
@@ -646,7 +699,7 @@ void Inventory::inventoryApi(Framework::StreamReader* zRequest, NetworkMessage*
 		zRequest->lese(id, idLen);
 		id[(int)idLen] = 0;
 		zResponse->adressGui(id);
-		observers.add(ImmutablePair<int, Text>(zSource->getId(), id));
+		addObserver(zSource, id);
 		delete[] id;
 		char filterLen;
 		zRequest->lese(&filterLen, 1);
@@ -697,4 +750,19 @@ void Inventory::inventoryApi(Framework::StreamReader* zRequest, NetworkMessage*
 		delete[] id;
 		break;
 	}
+}
+
+void Inventory::registerAfterPullStackCall(std::function<void(ItemSlot* zSlot, Direction dir, const Item* zItem, int count)> call)
+{
+	afterPullStackCalls.add(call);
+}
+
+void Inventory::registerAfterPushStackCall(std::function<void(ItemSlot* zSlot, Direction dir, const Item* zItem, int count)> call)
+{
+	afterPushStackCalls.add(call);
+}
+
+void Inventory::registerObserverAddedCall(std::function<void(Entity* zSource, Framework::Text id)> call)
+{
+	observerAddedCalls.add(call);
 }

+ 11 - 3
FactoryCraft/Inventory.h

@@ -42,6 +42,9 @@ private:
 	Framework::RCArray<ItemSlot>* pushSlotsOrder;
 	Framework::HashMap<int, Framework::Array<ItemSlot*>*>* itemCache;
 	Framework::Critical cs;
+	Framework::Array<std::function<void(ItemSlot* zSlot, Direction dir, const Item* zItem, int count)>> afterPullStackCalls;
+	Framework::Array<std::function<void(ItemSlot* zSlot, Direction dir, const Item* zItem, int count)>> afterPushStackCalls;
+	Framework::Array<std::function<void(Entity* zSource, Framework::Text id)>> observerAddedCalls;
 	int nextSlotId;
 
 	void updateCache(ItemSlot* zSlot, int beforeKey);
@@ -55,23 +58,28 @@ protected:
 	virtual void afterPushStack(ItemSlot* zSlot, Direction dir, const Item* zItem, int count);
 	virtual void loadInventory(Framework::StreamReader* zReader);
 	virtual void saveInventory(Framework::StreamWriter* zWriter);
-	void notyObservers(NetworkMessage& msg);
 	void removeObserver(Entity* zSource, Framework::Text id);
+	void addObserver(Entity* zSource, Framework::Text id);
 
 public:
 	Inventory(const Framework::Vec3<float> location, bool hasInventory);
 	virtual ~Inventory();
+	void notyObservers(NetworkMessage& msg);
 	const ItemSlot* zSlot(int id) const;
 	void addSlot(ItemSlot* slot);
-	void localTransaction(Framework::Array< ItemSlot* >* zSourceSlots, Framework::Array< ItemSlot* >* zTargetSlots, ItemFilter* zFilter, int count, Direction outDir, Direction inDir);
+	void localTransaction(Framework::Array< ItemSlot* >* zSourceSlots, Framework::Array<ItemSlot*>* zTargetSlots, ItemFilter* zFilter, int count, Direction outDir, Direction inDir);
 	ItemStack* takeItemsOut(ItemSlot* zSlot, int count, Direction dir);
-	virtual void addItems(ItemStack* items, Direction dir);
+	virtual void addItems(ItemStack* zItems, Direction dir);
+	virtual void addItems(ItemSlot* zSlot, ItemStack* zItems, Direction dir);
 	InventoryInteraction interactWith(Inventory* zInventory, Direction dir);
 	void unsaveAddItem(ItemStack* zStack, Direction dir);
 	int numberOfAddableItems(const ItemStack* zStack, Direction dir) const;
 	Framework::Iterator<ItemSlot*> begin();
 	Framework::Iterator<ItemSlot*> end();
 	void inventoryApi(Framework::StreamReader* zRequest, NetworkMessage* zResponse, Entity* zSource);
+	void registerAfterPullStackCall(std::function<void(ItemSlot* zSlot, Direction dir, const Item* zItem, int count)> call);
+	void registerAfterPushStackCall(std::function<void(ItemSlot* zSlot, Direction dir, const Item* zItem, int count)> call);
+	void registerObserverAddedCall(std::function<void(Entity* zSource, Framework::Text id)> call);
 
 	friend InventoryInteraction;
 };

+ 2 - 2
FactoryCraft/ItemType.cpp

@@ -48,7 +48,7 @@ void ItemType::saveSuperItem(const Item* zItem, Framework::StreamWriter* zWriter
 	zWriter->schreibe((char*)&zItem->maxDamage, 4);
 	zWriter->schreibe((char*)&zItem->durability, 4);
 	zWriter->schreibe((char*)&zItem->maxDurability, 4);
-	unsigned char flags = (unsigned char)(((((zItem->usable << 1) | zItem->solid << 1) | zItem->equippable << 1) | zItem->placeable << 1) | zItem->eatable);
+	unsigned char flags = (unsigned char)((zItem->usable << 4) | (zItem->solid << 3) | (zItem->equippable << 2) | (zItem->placeable << 1) | zItem->eatable);
 	zWriter->schreibe((char*)&flags, 1);
 	zWriter->schreibe((char*)&zItem->maxStackSize, 1);
 	unsigned char len = (unsigned char)zItem->name.getLength();
@@ -128,7 +128,7 @@ void ItemType::saveItem(const Item* zItem, Framework::StreamWriter* zWriter) con
 	saveSuperItem(zItem, zWriter);
 }
 
-Item* ItemType::cloneItem(Item* zItem) const
+Item* ItemType::cloneItem(const Item* zItem) const
 {
 	Framework::InMemoryBuffer buffer;
 	saveItem(zItem, &buffer);

+ 1 - 1
FactoryCraft/ItemType.h

@@ -45,7 +45,7 @@ public:
 	virtual void saveItem(const Item* zItem, Framework::StreamWriter* zWriter) const;
 	virtual ItemSkill* loadItemSkill(Framework::StreamReader* zReader) const;
 	virtual void saveItemSkill(const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const;
-	virtual Item* cloneItem(Item* zItem) const;
+	virtual Item* cloneItem(const Item* zItem) const;
 	virtual Item* breakItem(Item* zItem) const;
 	const ModelInfo& getModel() const;
 };

+ 32 - 6
FactoryCraft/Player.cpp

@@ -3,9 +3,10 @@
 #include "PlayerHand.h"
 #include "ItemFilter.h"
 
+
 Player::Player(Framework::Vec3<float> location, int dimensionId, int entityId)
 	: Entity(PlayerEntityType::INSTANCE, location, dimensionId, entityId),
-	BasicShapedCrafter(3, 3, this)
+	BasicShapedCrafter(3, 3, this, "inventory")
 {
 	for (int i = 0; i < 10; i++)
 	{
@@ -44,7 +45,7 @@ Framework::Text Player::getInventoryUIML()
 {
 	Framework::Text result = "<dialog id=\"player_inventory\" title=\"Inventory\" width=\"610\" height=\"450\">";
 
-	result += "<craftingGrid id=\"crafting\" margin-top=\"9\" align-top=\"start\" align-left=\"start\" margin-left=\"9\" width=\"272\" height=\"172\" rowSize=\"3\" colSize=\"3\" numOutputSlots=\"1\" target=\"";
+	result += "<craftingGrid id=\"crafting\" margin-top=\"9\" align-top=\"start\" align-left=\"start\" margin-left=\"9\" width=\"282\" height=\"172\" rowSize=\"3\" colSize=\"3\" numOutputSlots=\"1\" target=\"";
 	result += getId();
 	result += "\"/>";
 
@@ -81,14 +82,14 @@ void Player::useItemSlot(ItemSlot* zSlot)
 		{
 			Item* item = stack->extractFromStack();
 			Entity::useItem(item->zItemType(), item);
-			if (item->getDurability() > 0 && item->getDamage() < item->getMaxDamage())
+			if (item->getDurability() > 0)
 			{ // put used item back
 				stack->addToStack(item);
 				// TODO: use inventory wrapper to update the cache of the inventory
 				if (!zSlot->numberOfAddableItems(stack, NO_DIRECTION))
 				{ // move other items to other space
-					ItemStack* oldItems = zSlot->takeItemsOut(zSlot->zStack()->getSize(), NO_DIRECTION);
-					zSlot->addItems(stack, NO_DIRECTION);
+					ItemStack* oldItems = takeItemsOut(zSlot, zSlot->zStack()->getSize(), NO_DIRECTION);
+					addItems(zSlot, stack, NO_DIRECTION);
 					addItems(oldItems, NO_DIRECTION);
 					if (oldItems->getSize() > 0)
 					{
@@ -96,7 +97,7 @@ void Player::useItemSlot(ItemSlot* zSlot)
 					}
 				}
 				else
-					zSlot->addItems(stack, NO_DIRECTION);
+					addItems(zSlot, stack, NO_DIRECTION);
 			}
 			else
 			{ // item is broken
@@ -378,6 +379,31 @@ void Player::playerApi(Framework::StreamReader* zRequest, NetworkMessage* zRespo
 		}
 		break;
 	}
+	case 7: // craft action
+	{
+		bool isEntity;
+		zRequest->lese((char*)&isEntity, 1);
+		BasicShapedCrafter* target;
+		if (isEntity)
+		{
+			int id;
+			zRequest->lese((char*)&id, 4);
+			target = dynamic_cast<BasicShapedCrafter*>(Game::INSTANCE->zEntity(id, getCurrentDimensionId()));
+		}
+		else
+		{
+			int dim;
+			Framework::Vec3<int> pos;
+			zRequest->lese((char*)&dim, 4);
+			zRequest->lese((char*)&pos.x, 4);
+			zRequest->lese((char*)&pos.y, 4);
+			zRequest->lese((char*)&pos.z, 4);
+			target = dynamic_cast<BasicShapedCrafter*>(Game::INSTANCE->zRealBlockInstance(pos, dim));
+		}
+		if (target)
+			target->applyCurrentRecipie();
+		break;
+	}
 	}
 }
 

+ 15 - 0
FactoryCraft/Recipie.cpp

@@ -1,4 +1,5 @@
 #include "Recipie.h"
+#include "CraftingStorage.h"
 
 Recipie::Recipie()
 	: ReferenceCounter()
@@ -79,4 +80,18 @@ void ShapedRecipie::apply(ShapedCraftingStorage* zStorage)
 	ItemStack* stack = new ItemStack(output->zItemType()->cloneItem(output), outputAmount);
 	zStorage->addCraftingResult(stack);
 	stack->release();
+}
+
+Framework::Array<ItemInfo> ShapedRecipie::getOutput(ShapedCraftingStorage* zStorage)
+{
+	Framework::Array<ItemInfo> result;
+	ItemInfo info;
+	info.count = outputAmount;
+	info.type = output->zItemType()->getId();
+	info.damage = output->getDamage();
+	info.durability = output->getDurability();
+	info.maxDamage = output->getMaxDamage();
+	info.maxDurability = output->getMaxDurability();
+	result.add(info);
+	return result;
 }

+ 15 - 1
FactoryCraft/Recipie.h

@@ -3,7 +3,20 @@
 #include <JSON.h>
 
 #include "ItemFilter.h"
-#include "CraftingStorage.h"
+
+
+class CraftingStorage;
+class ShapedCraftingStorage;
+
+struct ItemInfo
+{
+	int type;
+	int count;
+	float damage;
+	float maxDamage;
+	float durability;
+	float maxDurability;
+};
 
 class Recipie : public virtual Framework::ReferenceCounter
 {
@@ -37,4 +50,5 @@ public:
 	void setOutput(Item* item, int amount);
 	bool testApplicability(ShapedCraftingStorage* zStorage);
 	void apply(ShapedCraftingStorage* zStorage);
+	Framework::Array<ItemInfo> getOutput(ShapedCraftingStorage* zStorage);
 };

+ 1 - 0
FactoryCraft/RecipieList.h

@@ -27,6 +27,7 @@ public:
 			if (recipie->testApplicability(zStorage))
 				return recipie;
 		}
+		return 0;
 	}
 
 	const Framework::Text& getName() const

+ 4 - 2
FactoryCraft/RecipieLoader.cpp

@@ -1,7 +1,9 @@
 #include <stdexcept>
 #include <Datei.h>
 #include <iostream>
+
 #include "RecipieLoader.h"
+#include "ItemType.h"
 
 using namespace Framework::JSON;
 using namespace Validator;
@@ -118,7 +120,7 @@ ItemFilter* RecipieLoader::loadFilter(JSONObject* zFilter)
 	return 0;
 }
 
-RecipieList* RecipieLoader::zRecipieList(const char* name)
+RecipieList* RecipieLoader::zRecipieList(const char* name) const
 {
 	for (RecipieList* l : lists)
 	{
@@ -128,7 +130,7 @@ RecipieList* RecipieLoader::zRecipieList(const char* name)
 	return 0;
 }
 
-ShapedRecipieList* RecipieLoader::zShapedRecipieList(const char* name)
+ShapedRecipieList* RecipieLoader::zShapedRecipieList(const char* name) const
 {
 	for (ShapedRecipieList* l : shapedLists)
 	{

+ 2 - 2
FactoryCraft/RecipieLoader.h

@@ -13,8 +13,8 @@ public:
 	RecipieLoader();
 	~RecipieLoader();
 	void loadRecipies(const char* path);
-	RecipieList* zRecipieList(const char* name);
-	ShapedRecipieList* zShapedRecipieList(const char* name);
+	RecipieList* zRecipieList(const char* name) const;
+	ShapedRecipieList* zShapedRecipieList(const char* name) const;
 	void registerRecipieList(const char* name);
 	void registerShapedRecipieList(const char* name);