From da692355e84f8d1e5210c3c89daf775cf23ec38b Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Sat, 18 Jun 2011 00:46:50 +0300
Subject: [PATCH] Created and moved stuff to content_nodemeta.{h,cpp}

---
 src/CMakeLists.txt       |   2 +
 src/content_craft.cpp    | 480 +++++++++++++++++++++++++++++++++++++
 src/content_craft.h      |  38 +++
 src/content_mapnode.cpp  |   2 +-
 src/content_nodemeta.cpp | 305 ++++++++++++++++++++++++
 src/content_nodemeta.h   |  91 +++++++
 src/game.cpp             |  13 +-
 src/nodemetadata.cpp     | 296 +----------------------
 src/nodemetadata.h       |  64 -----
 src/server.cpp           | 498 +--------------------------------------
 10 files changed, 938 insertions(+), 851 deletions(-)
 create mode 100644 src/content_craft.cpp
 create mode 100644 src/content_craft.h
 create mode 100644 src/content_nodemeta.cpp
 create mode 100644 src/content_nodemeta.h

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 10ed8c4af..3ee49f327 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -50,6 +50,8 @@ configure_file(
 )
 
 set(common_SRCS
+	content_nodemeta.cpp
+	content_craft.cpp
 	content_mapblock.cpp
 	content_mapnode.cpp
 	auth.cpp
diff --git a/src/content_craft.cpp b/src/content_craft.cpp
new file mode 100644
index 000000000..32d2e6d48
--- /dev/null
+++ b/src/content_craft.cpp
@@ -0,0 +1,480 @@
+/*
+Minetest-c55
+Copyright (C) 2010-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 "content_craft.h"
+#include "inventory.h"
+#include "content_mapnode.h"
+#include "player.h"
+
+/*
+	items: actually *items[9]
+	return value: allocates a new item, or returns NULL.
+*/
+InventoryItem *craft_get_result(InventoryItem **items)
+{
+	// Wood
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
+		if(checkItemCombination(items, specs))
+		{
+			return new MaterialItem(CONTENT_WOOD, 4);
+		}
+	}
+
+	// Stick
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		if(checkItemCombination(items, specs))
+		{
+			return new CraftItem("Stick", 4);
+		}
+	}
+
+	// Fence
+	{
+		ItemSpec specs[9];
+		specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[5] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[6] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[8] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new MaterialItem(CONTENT_FENCE, 2);
+		}
+	}
+
+	// Sign
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			//return new MapBlockObjectItem("Sign");
+			return new MaterialItem(CONTENT_SIGN_WALL, 1);
+		}
+	}
+
+	// Torch
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal");
+		specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new MaterialItem(CONTENT_TORCH, 4);
+		}
+	}
+
+	// Wooden pick
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("WPick", 0);
+		}
+	}
+
+	// Stone pick
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("STPick", 0);
+		}
+	}
+
+	// Steel pick
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("SteelPick", 0);
+		}
+	}
+
+	// Mese pick
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
+		specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("MesePick", 0);
+		}
+	}
+
+	// Wooden shovel
+	{
+		ItemSpec specs[9];
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("WShovel", 0);
+		}
+	}
+
+	// Stone shovel
+	{
+		ItemSpec specs[9];
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("STShovel", 0);
+		}
+	}
+
+	// Steel shovel
+	{
+		ItemSpec specs[9];
+		specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("SteelShovel", 0);
+		}
+	}
+
+	// Wooden axe
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("WAxe", 0);
+		}
+	}
+
+	// Stone axe
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("STAxe", 0);
+		}
+	}
+
+	// Steel axe
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("SteelAxe", 0);
+		}
+	}
+
+	// Wooden sword
+	{
+		ItemSpec specs[9];
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("WSword", 0);
+		}
+	}
+
+	// Stone sword
+	{
+		ItemSpec specs[9];
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("STSword", 0);
+		}
+	}
+
+	// Steel sword
+	{
+		ItemSpec specs[9];
+		specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+		if(checkItemCombination(items, specs))
+		{
+			return new ToolItem("SteelSword", 0);
+		}
+	}
+
+	// Chest
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+		if(checkItemCombination(items, specs))
+		{
+			return new MaterialItem(CONTENT_CHEST, 1);
+		}
+	}
+
+	// Furnace
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+		if(checkItemCombination(items, specs))
+		{
+			return new MaterialItem(CONTENT_FURNACE, 1);
+		}
+	}
+
+	// Steel block
+	{
+		ItemSpec specs[9];
+		specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+		if(checkItemCombination(items, specs))
+		{
+			return new MaterialItem(CONTENT_STEEL, 1);
+		}
+	}
+
+	return NULL;
+}
+
+void craft_set_creative_inventory(Player *player)
+{
+	player->resetInventory();
+	
+	// Give some good tools
+	{
+		InventoryItem *item = new ToolItem("MesePick", 0);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new ToolItem("SteelPick", 0);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new ToolItem("SteelAxe", 0);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new ToolItem("SteelShovel", 0);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+
+	/*
+		Give materials
+	*/
+	
+	// CONTENT_IGNORE-terminated list
+	u8 material_items[] = {
+		CONTENT_TORCH,
+		CONTENT_COBBLE,
+		CONTENT_MUD,
+		CONTENT_STONE,
+		CONTENT_SAND,
+		CONTENT_TREE,
+		CONTENT_LEAVES,
+		CONTENT_GLASS,
+		CONTENT_FENCE,
+		CONTENT_MESE,
+		CONTENT_WATERSOURCE,
+		CONTENT_CLOUD,
+		CONTENT_CHEST,
+		CONTENT_FURNACE,
+		CONTENT_SIGN_WALL,
+		CONTENT_IGNORE
+	};
+	
+	u8 *mip = material_items;
+	for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
+	{
+		if(*mip == CONTENT_IGNORE)
+			break;
+
+		InventoryItem *item = new MaterialItem(*mip, 1);
+		player->inventory.addItem("main", item);
+
+		mip++;
+	}
+
+#if 0
+	assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
+	
+	// add torch first
+	InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
+	player->inventory.addItem("main", item);
+	
+	// Then others
+	for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
+	{
+		// Skip some materials
+		if(i == CONTENT_WATER || i == CONTENT_TORCH
+			|| i == CONTENT_COALSTONE)
+			continue;
+
+		InventoryItem *item = new MaterialItem(i, 1);
+		player->inventory.addItem("main", item);
+	}
+#endif
+
+	/*// Sign
+	{
+		InventoryItem *item = new MapBlockObjectItem("Sign Example text");
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}*/
+}
+
+void craft_give_initial_stuff(Player *player)
+{
+	{
+		InventoryItem *item = new ToolItem("SteelPick", 0);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new MaterialItem(CONTENT_TORCH, 99);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new ToolItem("SteelAxe", 0);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new ToolItem("SteelShovel", 0);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new MaterialItem(CONTENT_COBBLE, 99);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	/*{
+		InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new CraftItem("Stick", 4);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new ToolItem("WPick", 32000);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}
+	{
+		InventoryItem *item = new ToolItem("STPick", 32000);
+		void* r = player->inventory.addItem("main", item);
+		assert(r == NULL);
+	}*/
+	/*// and some signs
+	for(u16 i=0; i<4; i++)
+	{
+		InventoryItem *item = new MapBlockObjectItem("Sign Example text");
+		bool r = player->inventory.addItem("main", item);
+		assert(r == true);
+	}*/
+	/*// Give some other stuff
+	{
+		InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
+		bool r = player->inventory.addItem("main", item);
+		assert(r == true);
+	}*/
+}
+
diff --git a/src/content_craft.h b/src/content_craft.h
new file mode 100644
index 000000000..7a8b4659a
--- /dev/null
+++ b/src/content_craft.h
@@ -0,0 +1,38 @@
+/*
+Minetest-c55
+Copyright (C) 2010-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.
+*/
+
+#ifndef CONTENT_CRAFT_HEADER
+#define CONTENT_CRAFT_HEADER
+
+class InventoryItem;
+class Player;
+
+/*
+	items: actually *items[9]
+	return value: allocates a new item, or returns NULL.
+*/
+InventoryItem *craft_get_result(InventoryItem **items);
+
+void craft_set_creative_inventory(Player *player);
+
+// Called when give_initial_stuff setting is used
+void craft_give_initial_stuff(Player *player);
+
+#endif
+
diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp
index 1f1c8e30a..ec236c63d 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "content_mapnode.h"
 #include "mapnode.h"
-#include "nodemetadata.h"
+#include "content_nodemeta.h"
 
 // TODO: Get rid of these and set up some attributes like toughness,
 //       fluffyness, and a funciton to calculate time and durability loss
diff --git a/src/content_nodemeta.cpp b/src/content_nodemeta.cpp
new file mode 100644
index 000000000..8627e18d0
--- /dev/null
+++ b/src/content_nodemeta.cpp
@@ -0,0 +1,305 @@
+/*
+Minetest-c55
+Copyright (C) 2010-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 "content_nodemeta.h"
+#include "inventory.h"
+#include "content_mapnode.h"
+
+/*
+	SignNodeMetadata
+*/
+
+// Prototype
+SignNodeMetadata proto_SignNodeMetadata("");
+
+SignNodeMetadata::SignNodeMetadata(std::string text):
+	m_text(text)
+{
+	NodeMetadata::registerType(typeId(), create);
+}
+u16 SignNodeMetadata::typeId() const
+{
+	return CONTENT_SIGN_WALL;
+}
+NodeMetadata* SignNodeMetadata::create(std::istream &is)
+{
+	std::string text = deSerializeString(is);
+	return new SignNodeMetadata(text);
+}
+NodeMetadata* SignNodeMetadata::clone()
+{
+	return new SignNodeMetadata(m_text);
+}
+void SignNodeMetadata::serializeBody(std::ostream &os)
+{
+	os<<serializeString(m_text);
+}
+std::string SignNodeMetadata::infoText()
+{
+	return std::string("\"")+m_text+"\"";
+}
+
+/*
+	ChestNodeMetadata
+*/
+
+// Prototype
+ChestNodeMetadata proto_ChestNodeMetadata;
+
+ChestNodeMetadata::ChestNodeMetadata()
+{
+	NodeMetadata::registerType(typeId(), create);
+	
+	m_inventory = new Inventory();
+	m_inventory->addList("0", 8*4);
+}
+ChestNodeMetadata::~ChestNodeMetadata()
+{
+	delete m_inventory;
+}
+u16 ChestNodeMetadata::typeId() const
+{
+	return CONTENT_CHEST;
+}
+NodeMetadata* ChestNodeMetadata::create(std::istream &is)
+{
+	ChestNodeMetadata *d = new ChestNodeMetadata();
+	d->m_inventory->deSerialize(is);
+	return d;
+}
+NodeMetadata* ChestNodeMetadata::clone()
+{
+	ChestNodeMetadata *d = new ChestNodeMetadata();
+	*d->m_inventory = *m_inventory;
+	return d;
+}
+void ChestNodeMetadata::serializeBody(std::ostream &os)
+{
+	m_inventory->serialize(os);
+}
+std::string ChestNodeMetadata::infoText()
+{
+	return "Chest";
+}
+bool ChestNodeMetadata::nodeRemovalDisabled()
+{
+	/*
+		Disable removal if chest contains something
+	*/
+	InventoryList *list = m_inventory->getList("0");
+	if(list == NULL)
+		return false;
+	if(list->getUsedSlots() == 0)
+		return false;
+	return true;
+}
+
+/*
+	FurnaceNodeMetadata
+*/
+
+// Prototype
+FurnaceNodeMetadata proto_FurnaceNodeMetadata;
+
+FurnaceNodeMetadata::FurnaceNodeMetadata()
+{
+	NodeMetadata::registerType(typeId(), create);
+	
+	m_inventory = new Inventory();
+	m_inventory->addList("fuel", 1);
+	m_inventory->addList("src", 1);
+	m_inventory->addList("dst", 4);
+
+	m_step_accumulator = 0;
+	m_fuel_totaltime = 0;
+	m_fuel_time = 0;
+	m_src_totaltime = 0;
+	m_src_time = 0;
+}
+FurnaceNodeMetadata::~FurnaceNodeMetadata()
+{
+	delete m_inventory;
+}
+u16 FurnaceNodeMetadata::typeId() const
+{
+	return CONTENT_FURNACE;
+}
+NodeMetadata* FurnaceNodeMetadata::clone()
+{
+	FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
+	*d->m_inventory = *m_inventory;
+	return d;
+}
+NodeMetadata* FurnaceNodeMetadata::create(std::istream &is)
+{
+	FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
+
+	d->m_inventory->deSerialize(is);
+
+	int temp;
+	is>>temp;
+	d->m_fuel_totaltime = (float)temp/10;
+	is>>temp;
+	d->m_fuel_time = (float)temp/10;
+
+	return d;
+}
+void FurnaceNodeMetadata::serializeBody(std::ostream &os)
+{
+	m_inventory->serialize(os);
+	os<<itos(m_fuel_totaltime*10)<<" ";
+	os<<itos(m_fuel_time*10)<<" ";
+}
+std::string FurnaceNodeMetadata::infoText()
+{
+	//return "Furnace";
+	if(m_fuel_time >= m_fuel_totaltime)
+	{
+		InventoryList *src_list = m_inventory->getList("src");
+		assert(src_list);
+		InventoryItem *src_item = src_list->getItem(0);
+
+		if(src_item)
+			return "Furnace is out of fuel";
+		else
+			return "Furnace is inactive";
+	}
+	else
+	{
+		std::string s = "Furnace is active (";
+		s += itos(m_fuel_time/m_fuel_totaltime*100);
+		s += "%)";
+		return s;
+	}
+}
+void FurnaceNodeMetadata::inventoryModified()
+{
+	dstream<<"Furnace inventory modification callback"<<std::endl;
+}
+bool FurnaceNodeMetadata::step(float dtime)
+{
+	if(dtime > 60.0)
+		dstream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
+	// Update at a fixed frequency
+	const float interval = 2.0;
+	m_step_accumulator += dtime;
+	bool changed = false;
+	while(m_step_accumulator > interval)
+	{
+		m_step_accumulator -= interval;
+		dtime = interval;
+
+		//dstream<<"Furnace step dtime="<<dtime<<std::endl;
+		
+		InventoryList *dst_list = m_inventory->getList("dst");
+		assert(dst_list);
+
+		InventoryList *src_list = m_inventory->getList("src");
+		assert(src_list);
+		InventoryItem *src_item = src_list->getItem(0);
+		
+		// Start only if there are free slots in dst, so that it can
+		// accomodate any result item
+		if(dst_list->getFreeSlots() > 0 && src_item && src_item->isCookable())
+		{
+			m_src_totaltime = 3;
+		}
+		else
+		{
+			m_src_time = 0;
+			m_src_totaltime = 0;
+		}
+		
+		/*
+			If fuel is burning, increment the burn counters.
+			If item finishes cooking, move it to result.
+		*/
+		if(m_fuel_time < m_fuel_totaltime)
+		{
+			//dstream<<"Furnace is active"<<std::endl;
+			m_fuel_time += dtime;
+			m_src_time += dtime;
+			if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
+					&& src_item)
+			{
+				InventoryItem *cookresult = src_item->createCookResult();
+				dst_list->addItem(cookresult);
+				src_list->decrementMaterials(1);
+				m_src_time = 0;
+				m_src_totaltime = 0;
+			}
+			changed = true;
+			continue;
+		}
+		
+		/*
+			If there is no source item or source item is not cookable, stop loop.
+		*/
+		if(src_item == NULL || m_src_totaltime < 0.001)
+		{
+			m_step_accumulator = 0;
+			break;
+		}
+		
+		//dstream<<"Furnace is out of fuel"<<std::endl;
+
+		InventoryList *fuel_list = m_inventory->getList("fuel");
+		assert(fuel_list);
+		InventoryItem *fuel_item = fuel_list->getItem(0);
+
+		if(ItemSpec(ITEM_MATERIAL, CONTENT_TREE).checkItem(fuel_item))
+		{
+			m_fuel_totaltime = 30;
+			m_fuel_time = 0;
+			fuel_list->decrementMaterials(1);
+			changed = true;
+		}
+		else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
+		{
+			m_fuel_totaltime = 30/4;
+			m_fuel_time = 0;
+			fuel_list->decrementMaterials(1);
+			changed = true;
+		}
+		else if(ItemSpec(ITEM_CRAFT, "Stick").checkItem(fuel_item))
+		{
+			m_fuel_totaltime = 30/4/4;
+			m_fuel_time = 0;
+			fuel_list->decrementMaterials(1);
+			changed = true;
+		}
+		else if(ItemSpec(ITEM_CRAFT, "lump_of_coal").checkItem(fuel_item))
+		{
+			m_fuel_totaltime = 40;
+			m_fuel_time = 0;
+			fuel_list->decrementMaterials(1);
+			changed = true;
+		}
+		else
+		{
+			//dstream<<"No fuel found"<<std::endl;
+			// No fuel, stop loop.
+			m_step_accumulator = 0;
+			break;
+		}
+	}
+	return changed;
+}
+
+
diff --git a/src/content_nodemeta.h b/src/content_nodemeta.h
new file mode 100644
index 000000000..ed5d5f24e
--- /dev/null
+++ b/src/content_nodemeta.h
@@ -0,0 +1,91 @@
+/*
+Minetest-c55
+Copyright (C) 2010-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.
+*/
+
+#ifndef CONTENT_NODEMETA_HEADER
+#define CONTENT_NODEMETA_HEADER
+
+#include "nodemetadata.h"
+
+class Inventory;
+
+class SignNodeMetadata : public NodeMetadata
+{
+public:
+	SignNodeMetadata(std::string text);
+	//~SignNodeMetadata();
+	
+	virtual u16 typeId() const;
+	static NodeMetadata* create(std::istream &is);
+	virtual NodeMetadata* clone();
+	virtual void serializeBody(std::ostream &os);
+	virtual std::string infoText();
+
+	std::string getText(){ return m_text; }
+	void setText(std::string t){ m_text = t; }
+
+private:
+	std::string m_text;
+};
+
+class ChestNodeMetadata : public NodeMetadata
+{
+public:
+	ChestNodeMetadata();
+	~ChestNodeMetadata();
+	
+	virtual u16 typeId() const;
+	static NodeMetadata* create(std::istream &is);
+	virtual NodeMetadata* clone();
+	virtual void serializeBody(std::ostream &os);
+	virtual std::string infoText();
+	virtual Inventory* getInventory() {return m_inventory;}
+
+	virtual bool nodeRemovalDisabled();
+	
+private:
+	Inventory *m_inventory;
+};
+
+class FurnaceNodeMetadata : public NodeMetadata
+{
+public:
+	FurnaceNodeMetadata();
+	~FurnaceNodeMetadata();
+	
+	virtual u16 typeId() const;
+	virtual NodeMetadata* clone();
+	static NodeMetadata* create(std::istream &is);
+	virtual void serializeBody(std::ostream &os);
+	virtual std::string infoText();
+	virtual Inventory* getInventory() {return m_inventory;}
+	virtual void inventoryModified();
+	virtual bool step(float dtime);
+
+private:
+	Inventory *m_inventory;
+	float m_step_accumulator;
+	float m_fuel_totaltime;
+	float m_fuel_time;
+	float m_src_totaltime;
+	float m_src_time;
+};
+
+
+#endif
+
diff --git a/src/game.cpp b/src/game.cpp
index 09f06f4f6..b11547679 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 // TODO: Move content-aware stuff to separate file
 #include "content_mapnode.h"
+#include "content_nodemeta.h"
 
 /*
 	Setting this to 1 enables a special camera mode that forces
@@ -1730,7 +1731,11 @@ void the_game(
 					dstream<<"Chest node right-clicked"<<std::endl;
 					
 					//ChestNodeMetadata *chestmeta = (ChestNodeMetadata*)meta;
-
+					
+					/*
+						Construct the unique identification string of this
+						chest's inventory
+					*/
 					std::string chest_inv_id;
 					chest_inv_id += "nodemeta:";
 					chest_inv_id += itos(nodepos.X);
@@ -1738,7 +1743,11 @@ void the_game(
 					chest_inv_id += itos(nodepos.Y);
 					chest_inv_id += ",";
 					chest_inv_id += itos(nodepos.Z);
-					
+
+					/*
+						Create a menu with the player's inventory and the
+						chest's inventory
+					*/
 					GUIInventoryMenu *menu =
 						new GUIInventoryMenu(guienv, guiroot, -1,
 							&g_menumgr, v2s16(8,9),
diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp
index 1fc4c93a1..3edf6d3c2 100644
--- a/src/nodemetadata.cpp
+++ b/src/nodemetadata.cpp
@@ -97,288 +97,7 @@ void NodeMetadata::registerType(u16 id, Factory f)
 }
 
 /*
-	SignNodeMetadata
-*/
-
-// Prototype
-SignNodeMetadata proto_SignNodeMetadata("");
-
-SignNodeMetadata::SignNodeMetadata(std::string text):
-	m_text(text)
-{
-	NodeMetadata::registerType(typeId(), create);
-}
-u16 SignNodeMetadata::typeId() const
-{
-	return CONTENT_SIGN_WALL;
-}
-NodeMetadata* SignNodeMetadata::create(std::istream &is)
-{
-	std::string text = deSerializeString(is);
-	return new SignNodeMetadata(text);
-}
-NodeMetadata* SignNodeMetadata::clone()
-{
-	return new SignNodeMetadata(m_text);
-}
-void SignNodeMetadata::serializeBody(std::ostream &os)
-{
-	os<<serializeString(m_text);
-}
-std::string SignNodeMetadata::infoText()
-{
-	return std::string("\"")+m_text+"\"";
-}
-
-/*
-	ChestNodeMetadata
-*/
-
-// Prototype
-ChestNodeMetadata proto_ChestNodeMetadata;
-
-ChestNodeMetadata::ChestNodeMetadata()
-{
-	NodeMetadata::registerType(typeId(), create);
-	
-	m_inventory = new Inventory();
-	m_inventory->addList("0", 8*4);
-}
-ChestNodeMetadata::~ChestNodeMetadata()
-{
-	delete m_inventory;
-}
-u16 ChestNodeMetadata::typeId() const
-{
-	return CONTENT_CHEST;
-}
-NodeMetadata* ChestNodeMetadata::create(std::istream &is)
-{
-	ChestNodeMetadata *d = new ChestNodeMetadata();
-	d->m_inventory->deSerialize(is);
-	return d;
-}
-NodeMetadata* ChestNodeMetadata::clone()
-{
-	ChestNodeMetadata *d = new ChestNodeMetadata();
-	*d->m_inventory = *m_inventory;
-	return d;
-}
-void ChestNodeMetadata::serializeBody(std::ostream &os)
-{
-	m_inventory->serialize(os);
-}
-std::string ChestNodeMetadata::infoText()
-{
-	return "Chest";
-}
-bool ChestNodeMetadata::nodeRemovalDisabled()
-{
-	/*
-		Disable removal if chest contains something
-	*/
-	InventoryList *list = m_inventory->getList("0");
-	if(list == NULL)
-		return false;
-	if(list->getUsedSlots() == 0)
-		return false;
-	return true;
-}
-
-/*
-	FurnaceNodeMetadata
-*/
-
-// Prototype
-FurnaceNodeMetadata proto_FurnaceNodeMetadata;
-
-FurnaceNodeMetadata::FurnaceNodeMetadata()
-{
-	NodeMetadata::registerType(typeId(), create);
-	
-	m_inventory = new Inventory();
-	m_inventory->addList("fuel", 1);
-	m_inventory->addList("src", 1);
-	m_inventory->addList("dst", 4);
-
-	m_step_accumulator = 0;
-	m_fuel_totaltime = 0;
-	m_fuel_time = 0;
-	m_src_totaltime = 0;
-	m_src_time = 0;
-}
-FurnaceNodeMetadata::~FurnaceNodeMetadata()
-{
-	delete m_inventory;
-}
-u16 FurnaceNodeMetadata::typeId() const
-{
-	return CONTENT_FURNACE;
-}
-NodeMetadata* FurnaceNodeMetadata::clone()
-{
-	FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
-	*d->m_inventory = *m_inventory;
-	return d;
-}
-NodeMetadata* FurnaceNodeMetadata::create(std::istream &is)
-{
-	FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
-
-	d->m_inventory->deSerialize(is);
-
-	int temp;
-	is>>temp;
-	d->m_fuel_totaltime = (float)temp/10;
-	is>>temp;
-	d->m_fuel_time = (float)temp/10;
-
-	return d;
-}
-void FurnaceNodeMetadata::serializeBody(std::ostream &os)
-{
-	m_inventory->serialize(os);
-	os<<itos(m_fuel_totaltime*10)<<" ";
-	os<<itos(m_fuel_time*10)<<" ";
-}
-std::string FurnaceNodeMetadata::infoText()
-{
-	//return "Furnace";
-	if(m_fuel_time >= m_fuel_totaltime)
-	{
-		InventoryList *src_list = m_inventory->getList("src");
-		assert(src_list);
-		InventoryItem *src_item = src_list->getItem(0);
-
-		if(src_item)
-			return "Furnace is out of fuel";
-		else
-			return "Furnace is inactive";
-	}
-	else
-	{
-		std::string s = "Furnace is active (";
-		s += itos(m_fuel_time/m_fuel_totaltime*100);
-		s += "%)";
-		return s;
-	}
-}
-void FurnaceNodeMetadata::inventoryModified()
-{
-	dstream<<"Furnace inventory modification callback"<<std::endl;
-}
-bool FurnaceNodeMetadata::step(float dtime)
-{
-	if(dtime > 60.0)
-		dstream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
-	// Update at a fixed frequency
-	const float interval = 2.0;
-	m_step_accumulator += dtime;
-	bool changed = false;
-	while(m_step_accumulator > interval)
-	{
-		m_step_accumulator -= interval;
-		dtime = interval;
-
-		//dstream<<"Furnace step dtime="<<dtime<<std::endl;
-		
-		InventoryList *dst_list = m_inventory->getList("dst");
-		assert(dst_list);
-
-		InventoryList *src_list = m_inventory->getList("src");
-		assert(src_list);
-		InventoryItem *src_item = src_list->getItem(0);
-		
-		// Start only if there are free slots in dst, so that it can
-		// accomodate any result item
-		if(dst_list->getFreeSlots() > 0 && src_item && src_item->isCookable())
-		{
-			m_src_totaltime = 3;
-		}
-		else
-		{
-			m_src_time = 0;
-			m_src_totaltime = 0;
-		}
-		
-		/*
-			If fuel is burning, increment the burn counters.
-			If item finishes cooking, move it to result.
-		*/
-		if(m_fuel_time < m_fuel_totaltime)
-		{
-			//dstream<<"Furnace is active"<<std::endl;
-			m_fuel_time += dtime;
-			m_src_time += dtime;
-			if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
-					&& src_item)
-			{
-				InventoryItem *cookresult = src_item->createCookResult();
-				dst_list->addItem(cookresult);
-				src_list->decrementMaterials(1);
-				m_src_time = 0;
-				m_src_totaltime = 0;
-			}
-			changed = true;
-			continue;
-		}
-		
-		/*
-			If there is no source item or source item is not cookable, stop loop.
-		*/
-		if(src_item == NULL || m_src_totaltime < 0.001)
-		{
-			m_step_accumulator = 0;
-			break;
-		}
-		
-		//dstream<<"Furnace is out of fuel"<<std::endl;
-
-		InventoryList *fuel_list = m_inventory->getList("fuel");
-		assert(fuel_list);
-		InventoryItem *fuel_item = fuel_list->getItem(0);
-
-		if(ItemSpec(ITEM_MATERIAL, CONTENT_TREE).checkItem(fuel_item))
-		{
-			m_fuel_totaltime = 30;
-			m_fuel_time = 0;
-			fuel_list->decrementMaterials(1);
-			changed = true;
-		}
-		else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
-		{
-			m_fuel_totaltime = 30/4;
-			m_fuel_time = 0;
-			fuel_list->decrementMaterials(1);
-			changed = true;
-		}
-		else if(ItemSpec(ITEM_CRAFT, "Stick").checkItem(fuel_item))
-		{
-			m_fuel_totaltime = 30/4/4;
-			m_fuel_time = 0;
-			fuel_list->decrementMaterials(1);
-			changed = true;
-		}
-		else if(ItemSpec(ITEM_CRAFT, "lump_of_coal").checkItem(fuel_item))
-		{
-			m_fuel_totaltime = 40;
-			m_fuel_time = 0;
-			fuel_list->decrementMaterials(1);
-			changed = true;
-		}
-		else
-		{
-			//dstream<<"No fuel found"<<std::endl;
-			// No fuel, stop loop.
-			m_step_accumulator = 0;
-			break;
-		}
-	}
-	return changed;
-}
-
-/*
-	NodeMetadatalist
+	NodeMetadataList
 */
 
 void NodeMetadataList::serialize(std::ostream &os)
@@ -505,19 +224,6 @@ bool NodeMetadataList::step(float dtime)
 		bool changed = meta->step(dtime);
 		if(changed)
 			something_changed = true;
-		/*if(res.inventory_changed)
-		{
-			std::string inv_id;
-			inv_id += "nodemeta:";
-			inv_id += itos(p.X);
-			inv_id += ",";
-			inv_id += itos(p.Y);
-			inv_id += ",";
-			inv_id += itos(p.Z);
-			InventoryContext c;
-			c.current_player = NULL;
-			inv_mgr->inventoryModified(&c, inv_id);
-		}*/
 	}
 	return something_changed;
 }
diff --git a/src/nodemetadata.h b/src/nodemetadata.h
index ae02cfc3c..8471e1d97 100644
--- a/src/nodemetadata.h
+++ b/src/nodemetadata.h
@@ -69,74 +69,10 @@ class NodeMetadata
 	static core::map<u16, Factory> m_types;
 };
 
-class SignNodeMetadata : public NodeMetadata
-{
-public:
-	SignNodeMetadata(std::string text);
-	//~SignNodeMetadata();
-	
-	virtual u16 typeId() const;
-	static NodeMetadata* create(std::istream &is);
-	virtual NodeMetadata* clone();
-	virtual void serializeBody(std::ostream &os);
-	virtual std::string infoText();
-
-	std::string getText(){ return m_text; }
-	void setText(std::string t){ m_text = t; }
-
-private:
-	std::string m_text;
-};
-
-class ChestNodeMetadata : public NodeMetadata
-{
-public:
-	ChestNodeMetadata();
-	~ChestNodeMetadata();
-	
-	virtual u16 typeId() const;
-	static NodeMetadata* create(std::istream &is);
-	virtual NodeMetadata* clone();
-	virtual void serializeBody(std::ostream &os);
-	virtual std::string infoText();
-	virtual Inventory* getInventory() {return m_inventory;}
-
-	virtual bool nodeRemovalDisabled();
-	
-private:
-	Inventory *m_inventory;
-};
-
-class FurnaceNodeMetadata : public NodeMetadata
-{
-public:
-	FurnaceNodeMetadata();
-	~FurnaceNodeMetadata();
-	
-	virtual u16 typeId() const;
-	virtual NodeMetadata* clone();
-	static NodeMetadata* create(std::istream &is);
-	virtual void serializeBody(std::ostream &os);
-	virtual std::string infoText();
-	virtual Inventory* getInventory() {return m_inventory;}
-	virtual void inventoryModified();
-	virtual bool step(float dtime);
-
-private:
-	Inventory *m_inventory;
-	float m_step_accumulator;
-	float m_fuel_totaltime;
-	float m_fuel_time;
-	float m_src_totaltime;
-	float m_src_time;
-};
-
 /*
 	List of metadata of all the nodes of a block
 */
 
-class InventoryManager;
-
 class NodeMetadataList
 {
 public:
diff --git a/src/server.cpp b/src/server.cpp
index 70448fbf6..9fa957c2a 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -32,6 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "servercommand.h"
 #include "filesys.h"
 #include "content_mapnode.h"
+#include "content_craft.h"
+#include "content_nodemeta.h"
 
 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
 
@@ -3828,334 +3830,10 @@ void Server::UpdateCrafting(u16 peer_id)
 				items[i] = clist->getItem(i);
 			}
 			
-			bool found = false;
-
-			// Wood
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new MaterialItem(CONTENT_WOOD, 4));
-					found = true;
-				}
-			}
-
-			// Stick
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new CraftItem("Stick", 4));
-					found = true;
-				}
-			}
-
-			// Fence
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[5] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[6] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[8] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new MaterialItem(CONTENT_FENCE, 2));
-					found = true;
-				}
-			}
-
-			// Sign
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					//rlist->addItem(new MapBlockObjectItem("Sign"));
-					rlist->addItem(new MaterialItem(CONTENT_SIGN_WALL, 1));
-					found = true;
-				}
-			}
-
-			// Torch
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal");
-				specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new MaterialItem(CONTENT_TORCH, 4));
-					found = true;
-				}
-			}
-
-			// Wooden pick
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("WPick", 0));
-					found = true;
-				}
-			}
-
-			// Stone pick
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("STPick", 0));
-					found = true;
-				}
-			}
-
-			// Steel pick
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("SteelPick", 0));
-					found = true;
-				}
-			}
-
-			// Mese pick
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
-				specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("MesePick", 0));
-					found = true;
-				}
-			}
-
-			// Wooden shovel
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("WShovel", 0));
-					found = true;
-				}
-			}
-
-			// Stone shovel
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("STShovel", 0));
-					found = true;
-				}
-			}
-
-			// Steel shovel
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("SteelShovel", 0));
-					found = true;
-				}
-			}
-
-			// Wooden axe
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("WAxe", 0));
-					found = true;
-				}
-			}
-
-			// Stone axe
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("STAxe", 0));
-					found = true;
-				}
-			}
-
-			// Steel axe
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("SteelAxe", 0));
-					found = true;
-				}
-			}
-
-			// Wooden sword
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("WSword", 0));
-					found = true;
-				}
-			}
-
-			// Stone sword
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("STSword", 0));
-					found = true;
-				}
-			}
-
-			// Steel sword
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new ToolItem("SteelSword", 0));
-					found = true;
-				}
-			}
-
-			// Chest
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new MaterialItem(CONTENT_CHEST, 1));
-					found = true;
-				}
-			}
-
-			// Furnace
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new MaterialItem(CONTENT_FURNACE, 1));
-					found = true;
-				}
-			}
-
-			// Steel block
-			if(!found)
-			{
-				ItemSpec specs[9];
-				specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot");
-				if(checkItemCombination(items, specs))
-				{
-					rlist->addItem(new MaterialItem(CONTENT_STEEL, 1));
-					found = true;
-				}
-			}
+			// Get result of crafting grid
+			InventoryItem *result = craft_get_result(items);
+			if(result)
+				rlist->addItem(result);
 		}
 	
 	} // if creative_mode == false
@@ -4206,97 +3884,6 @@ std::wstring Server::getStatusString()
 	return os.str();
 }
 
-
-void setCreativeInventory(Player *player)
-{
-	player->resetInventory();
-	
-	// Give some good tools
-	{
-		InventoryItem *item = new ToolItem("MesePick", 0);
-		void* r = player->inventory.addItem("main", item);
-		assert(r == NULL);
-	}
-	{
-		InventoryItem *item = new ToolItem("SteelPick", 0);
-		void* r = player->inventory.addItem("main", item);
-		assert(r == NULL);
-	}
-	{
-		InventoryItem *item = new ToolItem("SteelAxe", 0);
-		void* r = player->inventory.addItem("main", item);
-		assert(r == NULL);
-	}
-	{
-		InventoryItem *item = new ToolItem("SteelShovel", 0);
-		void* r = player->inventory.addItem("main", item);
-		assert(r == NULL);
-	}
-
-	/*
-		Give materials
-	*/
-	
-	// CONTENT_IGNORE-terminated list
-	u8 material_items[] = {
-		CONTENT_TORCH,
-		CONTENT_COBBLE,
-		CONTENT_MUD,
-		CONTENT_STONE,
-		CONTENT_SAND,
-		CONTENT_TREE,
-		CONTENT_LEAVES,
-		CONTENT_GLASS,
-		CONTENT_FENCE,
-		CONTENT_MESE,
-		CONTENT_WATERSOURCE,
-		CONTENT_CLOUD,
-		CONTENT_CHEST,
-		CONTENT_FURNACE,
-		CONTENT_SIGN_WALL,
-		CONTENT_IGNORE
-	};
-	
-	u8 *mip = material_items;
-	for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
-	{
-		if(*mip == CONTENT_IGNORE)
-			break;
-
-		InventoryItem *item = new MaterialItem(*mip, 1);
-		player->inventory.addItem("main", item);
-
-		mip++;
-	}
-
-#if 0
-	assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
-	
-	// add torch first
-	InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
-	player->inventory.addItem("main", item);
-	
-	// Then others
-	for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
-	{
-		// Skip some materials
-		if(i == CONTENT_WATER || i == CONTENT_TORCH
-			|| i == CONTENT_COALSTONE)
-			continue;
-
-		InventoryItem *item = new MaterialItem(i, 1);
-		player->inventory.addItem("main", item);
-	}
-#endif
-
-	/*// Sign
-	{
-		InventoryItem *item = new MapBlockObjectItem("Sign Example text");
-		void* r = player->inventory.addItem("main", item);
-		assert(r == NULL);
-	}*/
-}
-
 v3f findSpawnPos(ServerMap &map)
 {
 	//return v3f(50,50,50)*BS;
@@ -4366,7 +3953,7 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
 		// Reset inventory to creative if in creative mode
 		if(g_settings.getBool("creative_mode"))
 		{
-			setCreativeInventory(player);
+			craft_set_creative_inventory(player);
 		}
 
 		return player;
@@ -4419,78 +4006,11 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
 		
 		if(g_settings.getBool("creative_mode"))
 		{
-			setCreativeInventory(player);
+			craft_set_creative_inventory(player);
 		}
 		else if(g_settings.getBool("give_initial_stuff"))
 		{
-			{
-				InventoryItem *item = new ToolItem("SteelPick", 0);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			{
-				InventoryItem *item = new MaterialItem(CONTENT_TORCH, 99);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			{
-				InventoryItem *item = new ToolItem("SteelAxe", 0);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			{
-				InventoryItem *item = new ToolItem("SteelShovel", 0);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			{
-				InventoryItem *item = new MaterialItem(CONTENT_COBBLE, 99);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			/*{
-				InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			{
-				InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			{
-				InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			{
-				InventoryItem *item = new CraftItem("Stick", 4);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			{
-				InventoryItem *item = new ToolItem("WPick", 32000);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}
-			{
-				InventoryItem *item = new ToolItem("STPick", 32000);
-				void* r = player->inventory.addItem("main", item);
-				assert(r == NULL);
-			}*/
-			/*// and some signs
-			for(u16 i=0; i<4; i++)
-			{
-				InventoryItem *item = new MapBlockObjectItem("Sign Example text");
-				bool r = player->inventory.addItem("main", item);
-				assert(r == true);
-			}*/
-			/*// Give some other stuff
-			{
-				InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
-				bool r = player->inventory.addItem("main", item);
-				assert(r == true);
-			}*/
+			craft_give_initial_stuff(player);
 		}
 
 		return player;
-- 
GitLab