Crafting definition in scripts
authorPerttu Ahola <celeron55@gmail.com>
Thu, 17 Nov 2011 00:28:46 +0000 (02:28 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Tue, 29 Nov 2011 17:13:48 +0000 (19:13 +0200)
12 files changed:
data/mods/default/init.lua
src/CMakeLists.txt
src/client.cpp
src/client.h
src/craftdef.cpp [new file with mode: 0644]
src/craftdef.h [new file with mode: 0644]
src/gamedef.h
src/inventory.cpp
src/inventory.h
src/scriptapi.cpp
src/server.cpp
src/server.h

index c2e1d330014acce700d82a68634e30a469923df9..a0b381fb179a96c5f61f68240ed0f77be16c4878 100644 (file)
@@ -321,6 +321,29 @@ minetest.register_node("somenode", {
        inventory_image = "treeprop.png"
 })
 
+minetest.register_node("TNT", {
+       tile_images = {"tnt_top.png", "tnt_bottom.png", "tnt_side.png", "tnt_side.png", "tnt_side.png", "tnt_side.png"},
+       inventory_image = "tnt_side.png"
+})
+
+minetest.register_craft({
+       output = 'ToolItem "STPick" 4',
+       recipe = {
+               {'NodeItem "cobble" 1', 'NodeItem "cobble" 1', 'NodeItem "cobble" 1'},
+               {'', 'CraftItem "Stick"', ''},
+               {'', 'CraftItem "Stick"', ''},
+       }
+})
+
+minetest.register_craft({
+       output = 'NodeItem "TNT" 4',
+       recipe = {
+               {'NodeItem "wood" 1'},
+               {'CraftItem "lump_of_coal" 1'},
+               {'NodeItem "wood" 1'}
+       }
+})
+
 local TNT = {
        -- Maybe handle gravity and collision this way? dunno
        physical = true,
index 9c6419fcbef4fceccae257c62b6c28bbbf187796..9d699e976bcf887388f0d1779faa17ef91e0ec11 100644 (file)
@@ -94,6 +94,7 @@ configure_file(
 )
 
 set(common_SRCS
+       craftdef.cpp
        nameidmapping.cpp
        tooldef.cpp
        nodedef.cpp
index 716dac9318e7afdc53661c48e4ac7b5bd201ccdb..2326ff35db6735adb96e555f6bc37c18d2fa91d6 100644 (file)
@@ -2317,6 +2317,11 @@ INodeDefManager* Client::getNodeDefManager()
 {
        return m_nodedef;
 }
+ICraftDefManager* Client::getCraftDefManager()
+{
+       return NULL;
+       //return m_craftdef;
+}
 ITextureSource* Client::getTextureSource()
 {
        return m_tsrc;
index cd36c4858ab4cd6288a619248fb6c90894a73e66..e5368b17a0ff0d3d48da3d4f1aaaf62f33a49052 100644 (file)
@@ -36,6 +36,7 @@ class IGameDef;
 class IWritableTextureSource;
 class IWritableToolDefManager;
 class IWritableNodeDefManager;
+//class IWritableCraftDefManager;
 
 class ClientNotReadyException : public BaseException
 {
@@ -326,6 +327,7 @@ public:
        // IGameDef interface
        virtual IToolDefManager* getToolDefManager();
        virtual INodeDefManager* getNodeDefManager();
+       virtual ICraftDefManager* getCraftDefManager();
        virtual ITextureSource* getTextureSource();
        virtual u16 allocateUnknownNodeId(const std::string &name);
 
diff --git a/src/craftdef.cpp b/src/craftdef.cpp
new file mode 100644 (file)
index 0000000..79761b8
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+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: IGNORING ERROR: "
+                                       <<"input_cpi.width > 3"<<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;
+
+                       CraftPointerInput spec_cpi = createPointerInput(def->input, gamedef);
+                       if(spec_cpi.width > 3){
+                               errorstream<<"getCraftResult: IGNORING ERROR: "
+                                               <<"spec_cpi.width > 3"<<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];
+                               infostream<<"spec_items["<<i<<"] = "<<spec_items[i]<<std::endl;
+                       }
+
+                       bool match = checkItemCombination(input_items, spec_items);
+
+                       if(match){
+                               std::istringstream iss(def->output, std::ios::binary);
+                               return InventoryItem::deSerialize(iss, gamedef);
+                       }
+               }
+               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();
+}
+
diff --git a/src/craftdef.h b/src/craftdef.h
new file mode 100644 (file)
index 0000000..cfd58ad
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+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.
+*/
+
+#ifndef CRAFTDEF_HEADER
+#define CRAFTDEF_HEADER
+
+#include <string>
+#include <iostream>
+#include <vector>
+class IGameDef;
+class InventoryItem;
+
+struct CraftPointerInput
+{
+       unsigned int width;
+       std::vector<InventoryItem*> items;
+
+       CraftPointerInput(unsigned int width_, const std::vector<InventoryItem*> &items_):
+               width(width_),
+               items(items_)
+       {}
+       CraftPointerInput():
+               width(0)
+       {}
+       ~CraftPointerInput();
+       unsigned int height() const{
+               return (items.size() + width - 1) / width;
+       }
+};
+
+struct CraftInput
+{
+       unsigned int width;
+       std::vector<std::string> items;
+
+       CraftInput(unsigned int width_, const std::vector<std::string> &items_):
+               width(width_),
+               items(items_)
+       {}
+       CraftInput():
+               width(0)
+       {}
+       unsigned int height() const{
+               return (items.size() + width - 1) / width;
+       }
+       std::string dump() const;
+};
+
+struct CraftDefinition
+{
+       std::string output;
+       CraftInput input;
+
+       CraftDefinition(){}
+       CraftDefinition(const std::string &output_, unsigned int width_,
+                       const std::vector<std::string> &input_):
+               output(output_),
+               input(width_, input_)
+       {}
+       
+       std::string dump() const;
+       void serialize(std::ostream &os) const;
+       void deSerialize(std::istream &is);
+};
+
+class ICraftDefManager
+{
+public:
+       ICraftDefManager(){}
+       virtual ~ICraftDefManager(){}
+       virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
+                       IGameDef *gamedef) const=0;
+       
+       virtual void serialize(std::ostream &os)=0;
+};
+
+class IWritableCraftDefManager : public ICraftDefManager
+{
+public:
+       IWritableCraftDefManager(){}
+       virtual ~IWritableCraftDefManager(){}
+       virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
+                       IGameDef *gamedef) const=0;
+                       
+       virtual void registerCraft(const CraftDefinition &def)=0;
+       virtual void clear()=0;
+
+       virtual void serialize(std::ostream &os)=0;
+       virtual void deSerialize(std::istream &is)=0;
+};
+
+IWritableCraftDefManager* createCraftDefManager();
+
+#endif
+
index 6708f887db314ac61b1bae0290a953a9a801714e..bca27a21a426de68ea073475b9267d77badc0ce6 100644 (file)
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 class IToolDefManager;
 class INodeDefManager;
+class ICraftDefManager;
 //class IItemDefManager; //TODO
 // Mineral too?
 class ITextureSource;
@@ -40,6 +41,7 @@ public:
        // Thus, first they are set up and then they are only read.
        virtual IToolDefManager* getToolDefManager()=0;
        virtual INodeDefManager* getNodeDefManager()=0;
+       virtual ICraftDefManager* getCraftDefManager()=0;
        //virtual IItemDefManager* getItemDefManager()=0;
 
        // This is always thread-safe, but referencing the irrlicht texture
@@ -52,6 +54,7 @@ public:
        // Shorthands
        IToolDefManager* tdef(){return getToolDefManager();}
        INodeDefManager* ndef(){return getNodeDefManager();}
+       ICraftDefManager* cdef(){return getCraftDefManager();}
        ITextureSource* tsrc(){return getTextureSource();}
 };
 
index 3868686637b8f91588c6e3af78f2ecf64fe898d9..c7dd2a87b92325c12469f55b3257a6cd51cebed6 100644 (file)
@@ -1153,5 +1153,85 @@ bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *sp
 
        return true;
 }
+
+bool checkItemCombination(const InventoryItem * const * items,
+               const InventoryItem * const * specs)
+{
+       u16 items_min_x = 100;
+       u16 items_max_x = 100;
+       u16 items_min_y = 100;
+       u16 items_max_y = 100;
+       for(u16 y=0; y<3; y++)
+       for(u16 x=0; x<3; x++)
+       {
+               if(items[y*3 + x] == NULL)
+                       continue;
+               if(items_min_x == 100 || x < items_min_x)
+                       items_min_x = x;
+               if(items_min_y == 100 || y < items_min_y)
+                       items_min_y = y;
+               if(items_max_x == 100 || x > items_max_x)
+                       items_max_x = x;
+               if(items_max_y == 100 || y > items_max_y)
+                       items_max_y = y;
+       }
+       // No items at all, just return false
+       if(items_min_x == 100)
+               return false;
        
+       u16 items_w = items_max_x - items_min_x + 1;
+       u16 items_h = items_max_y - items_min_y + 1;
+
+       u16 specs_min_x = 100;
+       u16 specs_max_x = 100;
+       u16 specs_min_y = 100;
+       u16 specs_max_y = 100;
+       for(u16 y=0; y<3; y++)
+       for(u16 x=0; x<3; x++)
+       {
+               if(specs[y*3 + x] == NULL)
+                       continue;
+               if(specs_min_x == 100 || x < specs_min_x)
+                       specs_min_x = x;
+               if(specs_min_y == 100 || y < specs_min_y)
+                       specs_min_y = y;
+               if(specs_max_x == 100 || x > specs_max_x)
+                       specs_max_x = x;
+               if(specs_max_y == 100 || y > specs_max_y)
+                       specs_max_y = y;
+       }
+       // No specs at all, just return false
+       if(specs_min_x == 100)
+               return false;
+
+       u16 specs_w = specs_max_x - specs_min_x + 1;
+       u16 specs_h = specs_max_y - specs_min_y + 1;
+
+       // Different sizes
+       if(items_w != specs_w || items_h != specs_h)
+               return false;
+
+       for(u16 y=0; y<specs_h; y++)
+       for(u16 x=0; x<specs_w; x++)
+       {
+               u16 items_x = items_min_x + x;
+               u16 items_y = items_min_y + y;
+               u16 specs_x = specs_min_x + x;
+               u16 specs_y = specs_min_y + y;
+               const InventoryItem *item = items[items_y * 3 + items_x];
+               const InventoryItem *spec = specs[specs_y * 3 + specs_x];
+               
+               if(item == NULL && spec == NULL)
+                       continue;
+               if(item == NULL && spec != NULL)
+                       return false;
+               if(item != NULL && spec == NULL)
+                       return false;
+               if(!spec->isSubsetOf(item))
+                       return false;
+       }
+
+       return true;
+}
+
 //END
index 9c6a967a2140476f82e2edddaa2249532172e338..d6049f52fd9ca0fb943da77b8fd0c5453413dfeb 100644 (file)
@@ -70,25 +70,26 @@ public:
                Quantity methods
        */
 
-       // Shall return true if the item can be add()ed to the other
+       // Return true if the item can be add()ed to the other
        virtual bool addableTo(const InventoryItem *other) const
-       {
-               return false;
-       }
+       { return false; }
+       // Return true if the other item contains this item
+       virtual bool isSubsetOf(const InventoryItem *other) const
+       { return false; }
+       // Remove the other item from this one if possible and return true
+       // Return false if not possible
+       virtual bool removeOther(const InventoryItem *other)
+       { return false; }
        
        u16 getCount() const
-       {
-               return m_count;
-       }
+       { return m_count; }
        void setCount(u16 count)
-       {
-               m_count = count;
-       }
+       { m_count = count; }
+
        // This should return something else for stackable items
        virtual u16 freeSpace() const
-       {
-               return 0;
-       }
+       { return 0; }
+
        void add(u16 count)
        {
                assert(m_count + count <= QUANTITY_ITEM_MAX_COUNT);
@@ -168,6 +169,24 @@ public:
                        return false;
                return true;
        }
+       virtual bool isSubsetOf(const InventoryItem *other) const
+       {
+               if(std::string(other->getName()) != "MaterialItem")
+                       return false;
+               MaterialItem *m = (MaterialItem*)other;
+               if(m->m_nodename != m_nodename)
+                       return false;
+               return m_count <= m->m_count;
+       }
+       virtual bool removeOther(const InventoryItem *other)
+       {
+               if(!other->isSubsetOf(this))
+                       return false;
+               MaterialItem *m = (MaterialItem*)other;
+               m_count += m->m_count;
+               return true;
+       }
+
        u16 freeSpace() const
        {
                if(m_count > QUANTITY_ITEM_MAX_COUNT)
@@ -245,6 +264,24 @@ public:
                        return false;
                return true;
        }
+       virtual bool isSubsetOf(const InventoryItem *other) const
+       {
+               if(std::string(other->getName()) != "CraftItem")
+                       return false;
+               CraftItem *m = (CraftItem*)other;
+               if(m->m_subname != m_subname)
+                       return false;
+               return m_count <= m->m_count;
+       }
+       virtual bool removeOther(const InventoryItem *other)
+       {
+               if(!other->isSubsetOf(this))
+                       return false;
+               CraftItem *m = (CraftItem*)other;
+               m_count += m->m_count;
+               return true;
+       }
+
        u16 freeSpace() const
        {
                if(m_count > QUANTITY_ITEM_MAX_COUNT)
@@ -312,23 +349,26 @@ public:
        std::string getText()
        {
                return "";
-               
-               /*std::ostringstream os;
-               u16 f = 4;
-               u16 d = 65535/f;
-               u16 i;
-               for(i=0; i<(65535-m_wear)/d; i++)
-                       os<<'X';
-               for(; i<f; i++)
-                       os<<'-';
-               return os.str();*/
-               
-               /*std::ostringstream os;
-               os<<m_toolname;
-               os<<" ";
-               os<<(m_wear/655);
-               return os.str();*/
        }
+
+       virtual bool isSubsetOf(const InventoryItem *other) const
+       {
+               if(std::string(other->getName()) != "ToolItem")
+                       return false;
+               ToolItem *m = (ToolItem*)other;
+               if(m->m_toolname != m_toolname)
+                       return false;
+               return m_wear <= m->m_wear;
+       }
+       virtual bool removeOther(const InventoryItem *other)
+       {
+               if(!other->isSubsetOf(this))
+                       return false;
+               ToolItem *m = (ToolItem*)other;
+               m_wear -= m->m_wear;
+               return true;
+       }
+
        /*
                Special methods
        */
@@ -591,5 +631,12 @@ struct ItemSpec
 */
 bool checkItemCombination(const InventoryItem * const*items, const ItemSpec *specs);
 
+/*
+       items: a pointer to an array of 9 pointers to items
+       specs: a pointer to an array of 9 pointers to items
+*/
+bool checkItemCombination(const InventoryItem * const * items,
+               const InventoryItem * const * specs);
+
 #endif
 
index b37c50bc072613b7da79ff900a9bb576e0d1090e..cd501060f9127a161f632b07b90d93e76f5cbad2 100644 (file)
@@ -37,6 +37,7 @@ extern "C" {
 #include "content_sao.h" // For LuaEntitySAO
 #include "tooldef.h"
 #include "nodedef.h"
+#include "craftdef.h"
 
 /*
 TODO:
@@ -205,26 +206,6 @@ static int l_register_globalstep(lua_State *L)
        return 0; /* number of results */
 }
 
-#if 0
-// Clear all registered tools
-// deregister_tools()
-static int l_deregister_tools(lua_State *L)
-{
-       infostream<<"deregister_tools"<<std::endl;
-
-       // Get server from registry
-       lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
-       Server *server = (Server*)lua_touserdata(L, -1);
-       // And get the writable tool definition manager from the server
-       IWritableToolDefManager *tooldef =
-                       server->getWritableToolDefManager();
-       
-       tooldef->clear();
-
-       return 0; /* number of results */
-}
-#endif
-
 // register_tool(name, {lots of stuff})
 static int l_register_tool(lua_State *L)
 {
@@ -336,16 +317,90 @@ static int l_register_node(lua_State *L)
                f.tname_inventory = lua_tostring(L, -1);
        lua_pop(L, 1);
 
+       // TODO: Replace with actual parameter reading
+       // Temporarily set some sane parameters to allow digging
+       f.material.diggability = DIGGABLE_NORMAL;
+       f.material.weight = 0;
+       f.material.crackiness = 0;
+       f.material.crumbliness = 0;
+       f.material.cuttability = 0;
+
        nodedef->set(name, f);
        return 0; /* number of results */
 }
 
+// register_craft({output=item, recipe={{item00,item10},{item01,item11}})
+static int l_register_craft(lua_State *L)
+{
+       infostream<<"register_craft"<<std::endl;
+       luaL_checktype(L, 1, LUA_TTABLE);
+       int table0 = 1;
+
+       // Get server from registry
+       lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
+       Server *server = (Server*)lua_touserdata(L, -1);
+       // And get the writable craft definition manager from the server
+       IWritableCraftDefManager *craftdef =
+                       server->getWritableCraftDefManager();
+       
+       std::string output;
+       int width = 0;
+       std::vector<std::string> input;
+
+       lua_getfield(L, table0, "output");
+       luaL_checktype(L, -1, LUA_TSTRING);
+       if(lua_isstring(L, -1))
+               output = lua_tostring(L, -1);
+       lua_pop(L, 1);
+
+       lua_getfield(L, table0, "recipe");
+       luaL_checktype(L, -1, LUA_TTABLE);
+       if(lua_istable(L, -1)){
+               int table1 = lua_gettop(L);
+               lua_pushnil(L);
+               int rowcount = 0;
+               while(lua_next(L, table1) != 0){
+                       int colcount = 0;
+                       // key at index -2 and value at index -1
+                       luaL_checktype(L, -1, LUA_TTABLE);
+                       if(lua_istable(L, -1)){
+                               int table2 = lua_gettop(L);
+                               lua_pushnil(L);
+                               while(lua_next(L, table2) != 0){
+                                       // key at index -2 and value at index -1
+                                       luaL_checktype(L, -1, LUA_TSTRING);
+                                       input.push_back(lua_tostring(L, -1));
+                                       // removes value, keeps key for next iteration
+                                       lua_pop(L, 1);
+                                       colcount++;
+                               }
+                       }
+                       if(rowcount == 0){
+                               width = colcount;
+                       } else {
+                               if(colcount != width){
+                                       script_error(L, "error: %s\n", "Invalid crafting recipe");
+                               }
+                       }
+                       // removes value, keeps key for next iteration
+                       lua_pop(L, 1);
+                       rowcount++;
+               }
+       }
+       lua_pop(L, 1);
+
+       CraftDefinition def(output, width, input);
+       craftdef->registerCraft(def);
+
+       return 0; /* number of results */
+}
+
 static const struct luaL_Reg minetest_f [] = {
        {"register_entity", l_register_entity},
        {"register_globalstep", l_register_globalstep},
-       //{"deregister_tools", l_deregister_tools},
        {"register_tool", l_register_tool},
        {"register_node", l_register_node},
+       {"register_craft", l_register_craft},
        {NULL, NULL}
 };
 
index c01b5050df9aaeab7881466637e7a3b6c421dd6c..894c3d362d1c5c5dc65782b1978a1109233e9c0c 100644 (file)
@@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "scriptapi.h"
 #include "nodedef.h"
 #include "tooldef.h"
+#include "craftdef.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
@@ -988,6 +989,7 @@ Server::Server(
        m_lua(NULL),
        m_toolmgr(createToolDefManager()),
        m_nodedef(createNodeDefManager()),
+       m_craftdef(createCraftDefManager()),
        m_thread(this),
        m_emergethread(this),
        m_time_counter(0),
@@ -4332,14 +4334,19 @@ void Server::UpdateCrafting(u16 peer_id)
                }
                if(clist && rlist && player->craftresult_is_preview)
                {
-                       InventoryItem *items[9];
-                       for(u16 i=0; i<9; i++)
-                       {
-                               items[i] = clist->getItem(i);
+                       // Get result of crafting grid
+                       
+                       std::vector<InventoryItem*> items;
+                       for(u16 i=0; i<9; i++){
+                               if(clist->getItem(i) == NULL)
+                                       items.push_back(NULL);
+                               else
+                                       items.push_back(clist->getItem(i)->clone());
                        }
+                       CraftPointerInput cpi(3, items);
                        
-                       // Get result of crafting grid
-                       InventoryItem *result = craft_get_result(items, this);
+                       InventoryItem *result = m_craftdef->getCraftResult(cpi, this);
+                       //InventoryItem *result = craft_get_result(items, this);
                        if(result)
                                rlist->addItem(result);
                }
@@ -4424,6 +4431,10 @@ INodeDefManager* Server::getNodeDefManager()
 {
        return m_nodedef;
 }
+ICraftDefManager* Server::getCraftDefManager()
+{
+       return m_craftdef;
+}
 ITextureSource* Server::getTextureSource()
 {
        return NULL;
@@ -4441,6 +4452,10 @@ IWritableNodeDefManager* Server::getWritableNodeDefManager()
 {
        return m_nodedef;
 }
+IWritableCraftDefManager* Server::getWritableCraftDefManager()
+{
+       return m_craftdef;
+}
 
 v3f findSpawnPos(ServerMap &map)
 {
index ff0abccc46b1c9b16823c29596cb060554e5454b..7620f5341bb291c4fa8fb1a9e24953d71d3765ac 100644 (file)
@@ -35,6 +35,7 @@ struct LuaState;
 typedef struct lua_State lua_State;
 class IWritableToolDefManager;
 class IWritableNodeDefManager;
+class IWritableCraftDefManager;
 
 /*
        Some random functions
@@ -490,11 +491,13 @@ public:
        // Under envlock
        virtual IToolDefManager* getToolDefManager();
        virtual INodeDefManager* getNodeDefManager();
+       virtual ICraftDefManager* getCraftDefManager();
        virtual ITextureSource* getTextureSource();
        virtual u16 allocateUnknownNodeId(const std::string &name);
        
        IWritableToolDefManager* getWritableToolDefManager();
        IWritableNodeDefManager* getWritableNodeDefManager();
+       IWritableCraftDefManager* getWritableCraftDefManager();
 
 private:
 
@@ -635,6 +638,9 @@ private:
        // Node definition manager
        IWritableNodeDefManager *m_nodedef;
        
+       // Craft definition manager
+       IWritableCraftDefManager *m_craftdef;
+       
        /*
                Threads
        */