initial workings of the furnace
authorPerttu Ahola <celeron55@gmail.com>
Mon, 4 Apr 2011 23:56:29 +0000 (02:56 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Mon, 4 Apr 2011 23:56:29 +0000 (02:56 +0300)
src/inventory.cpp
src/inventory.h
src/map.cpp
src/map.h
src/mapnode.cpp
src/mapnode.h
src/nodemetadata.cpp
src/nodemetadata.h
src/server.cpp

index a610a4617556d4e816c8e5d8608579b59c06238e..86e00877c96054eb1e9001599d5da0bfb660192a 100644 (file)
@@ -403,6 +403,28 @@ InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
        }
 }
 
+bool InventoryList::itemFits(u32 i, InventoryItem *newitem)
+{
+       // If it is an empty position, it's an easy job.
+       InventoryItem *to_item = m_items[i];
+       if(to_item == NULL)
+       {
+               return true;
+       }
+       
+       // If not addable, return the item
+       if(newitem->addableTo(to_item) == false)
+               return false;
+       
+       // If the item fits fully in the slot, add counter and delete it
+       if(newitem->getCount() <= to_item->freeSpace())
+       {
+               return true;
+       }
+
+       return false;
+}
+
 InventoryItem * InventoryList::takeItem(u32 i, u32 count)
 {
        if(count == 0)
@@ -698,5 +720,132 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr)
                mgr->inventoryModified(c, to_inv);
 #endif
 }
+
+/*
+       Craft checking system
+*/
+
+bool ItemSpec::checkItem(InventoryItem *item)
+{
+       if(type == ITEM_NONE)
+       {
+               // Has to be no item
+               if(item != NULL)
+                       return false;
+               return true;
+       }
+       
+       // There should be an item
+       if(item == NULL)
+               return false;
+
+       std::string itemname = item->getName();
+
+       if(type == ITEM_MATERIAL)
+       {
+               if(itemname != "MaterialItem")
+                       return false;
+               MaterialItem *mitem = (MaterialItem*)item;
+               if(mitem->getMaterial() != num)
+                       return false;
+       }
+       else if(type == ITEM_CRAFT)
+       {
+               if(itemname != "CraftItem")
+                       return false;
+               CraftItem *mitem = (CraftItem*)item;
+               if(mitem->getSubName() != name)
+                       return false;
+       }
+       else if(type == ITEM_TOOL)
+       {
+               // Not supported yet
+               assert(0);
+       }
+       else if(type == ITEM_MBO)
+       {
+               // Not supported yet
+               assert(0);
+       }
+       else
+       {
+               // Not supported yet
+               assert(0);
+       }
+       return true;
+}
+
+bool checkItemCombination(InventoryItem **items, ItemSpec *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].type == ITEM_NONE)
+                       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;
+               InventoryItem *item = items[items_y * 3 + items_x];
+               ItemSpec &spec = specs[specs_y * 3 + specs_x];
+
+               if(spec.checkItem(item) == false)
+                       return false;
+       }
+
+       return true;
+}
        
 //END
index 45bc488c54d16aa2aea21c816efaa6d1fbde5bc4..0cbd97abc3dc70bdcc050523316bfd1cde9a2267 100644 (file)
@@ -435,6 +435,7 @@ public:
        InventoryItem * changeItem(u32 i, InventoryItem *newitem);
        // Delete item
        void deleteItem(u32 i);
+
        // Adds an item to a suitable place. Returns leftover item.
        // If all went into the list, returns NULL.
        InventoryItem * addItem(InventoryItem *newitem);
@@ -445,6 +446,9 @@ public:
        // If can be added fully, NULL is returned.
        InventoryItem * addItem(u32 i, InventoryItem *newitem);
 
+       // Checks whether the item could be added to the given slot
+       bool itemFits(u32 i, InventoryItem *newitem);
+
        // Takes some items from a slot.
        // If there are not enough, takes as many as it can.
        // Returns NULL if couldn't take any.
@@ -522,7 +526,7 @@ public:
        */
        virtual Inventory* getInventory(InventoryContext *c, std::string id)
                {return NULL;}
-       // Used on the server by InventoryAction::apply
+       // Used on the server by InventoryAction::apply and other stuff
        virtual void inventoryModified(InventoryContext *c, std::string id)
                {}
        // Used on the client
@@ -600,5 +604,51 @@ struct IMoveAction : public InventoryAction
        void apply(InventoryContext *c, InventoryManager *mgr);
 };
 
+/*
+       Craft checking system
+*/
+
+enum ItemSpecType
+{
+       ITEM_NONE,
+       ITEM_MATERIAL,
+       ITEM_CRAFT,
+       ITEM_TOOL,
+       ITEM_MBO
+};
+
+struct ItemSpec
+{
+       enum ItemSpecType type;
+       // Only other one of these is used
+       std::string name;
+       u16 num;
+
+       ItemSpec():
+               type(ITEM_NONE)
+       {
+       }
+       ItemSpec(enum ItemSpecType a_type, std::string a_name):
+               type(a_type),
+               name(a_name),
+               num(65535)
+       {
+       }
+       ItemSpec(enum ItemSpecType a_type, u16 a_num):
+               type(a_type),
+               name(""),
+               num(a_num)
+       {
+       }
+
+       bool checkItem(InventoryItem *item);
+};
+
+/*
+       items: a pointer to an array of 9 pointers to items
+       specs: a pointer to an array of 9 ItemSpecs
+*/
+bool checkItemCombination(InventoryItem **items, ItemSpec *specs);
+
 #endif
 
index f6115a62a9fd84ea9be827576bb641843c12f9de..40274ae295cd298a200c637b39603b2807d03bf4 100644 (file)
@@ -1756,6 +1756,35 @@ void Map::removeNodeMetadata(v3s16 p)
        block->m_node_metadata.remove(p_rel);
 }
 
+void Map::nodeMetadataStep(float dtime,
+               core::map<v3s16, MapBlock*> &changed_blocks)
+{
+       /*
+               NOTE:
+               Currently there is no way to ensure that all the necessary
+               blocks are loaded when this is run. (They might get unloaded)
+               NOTE: ^- Actually, that might not be so. In a quick test it
+               reloaded a block with a furnace when I walked back to it from
+               a distance.
+       */
+       core::map<v2s16, MapSector*>::Iterator si;
+       si = m_sectors.getIterator();
+       for(; si.atEnd() == false; si++)
+       {
+               MapSector *sector = si.getNode()->getValue();
+               core::list< MapBlock * > sectorblocks;
+               sector->getBlocks(sectorblocks);
+               core::list< MapBlock * >::Iterator i;
+               for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
+               {
+                       MapBlock *block = *i;
+                       bool changed = block->m_node_metadata.step(dtime);
+                       if(changed)
+                               changed_blocks[block->getPos()] = block;
+               }
+       }
+}
+
 /*
        ServerMap
 */
index b1b3b9aff42aaf94a229951c07cacca028c42abf..081705a5f83f4e26c7852dd681d66ac6028a314d 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -285,6 +285,8 @@ public:
        NodeMetadata* getNodeMetadata(v3s16 p);
        void setNodeMetadata(v3s16 p, NodeMetadata *meta);
        void removeNodeMetadata(v3s16 p);
+       void nodeMetadataStep(float dtime,
+                       core::map<v3s16, MapBlock*> &changed_blocks);
 
        /*
                Variables
index 8e968c81120b5b29559c838c2a7708f47a0c6922..187689c6fc3c038bba9256b88ad5cd0fe42949b7 100644 (file)
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mineral.h"
 // For g_settings
 #include "main.h"
+#include "nodemetadata.h"
 
 ContentFeatures::~ContentFeatures()
 {
index ce233e8e39e4c87a5321a1e95d6b8a6312d46661..04234830d951843354b6ae7bb570c704657f4fea 100644 (file)
@@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serialization.h"
 #include "tile.h"
 #include "iirrlichtwrapper.h"
-#include "nodemetadata.h"
 
 /*
        Initializes all kind of stuff in here.
@@ -121,6 +120,7 @@ enum LiquidType
 };
 
 class MapNode;
+class NodeMetadata;
 
 struct ContentFeatures
 {
index 2405e7601ea7d42c5b0c67840164323ec8ba5d40..21f55a0ca463706477bbd60a8032f137ba71c857 100644 (file)
@@ -178,6 +178,12 @@ FurnaceNodeMetadata::FurnaceNodeMetadata()
        m_inventory->addList("fuel", 1);
        m_inventory->addList("src", 1);
        m_inventory->addList("dst", 1);
+
+       m_step_accumulator = 0;
+       m_fuel_totaltime = 0;
+       m_fuel_time = 0;
+       m_src_totaltime = 0;
+       m_src_time = 0;
 }
 FurnaceNodeMetadata::~FurnaceNodeMetadata()
 {
@@ -197,24 +203,134 @@ NodeMetadata* FurnaceNodeMetadata::create(std::istream &is)
 {
        FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
        d->m_inventory->deSerialize(is);
-       /*std::string params;
-       std::getline(is, params, '\n');*/
+       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);
-       // This line will contain the other parameters
-       //os<<"\n";
+       os<<itos(m_fuel_totaltime*10)<<" ";
+       os<<itos(m_fuel_time*10)<<" ";
 }
 std::string FurnaceNodeMetadata::infoText()
 {
-       return "Furnace";
+       //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)
+{
+       // Update at a fixed frequency
+       const float interval = 0.5;
+       m_step_accumulator += dtime;
+       if(m_step_accumulator < interval)
+               return false;
+       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);
+
+       if(ItemSpec(ITEM_MATERIAL, CONTENT_TREE).checkItem(src_item)
+                       && dst_list->itemFits(0, new CraftItem("lump_of_coal", 1)))
+       {
+               m_src_totaltime = 3;
+       }
+       else
+       {
+               m_src_time = 0;
+               m_src_totaltime = 0;
+       }
+
+       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)
+               {
+                       if(ItemSpec(ITEM_MATERIAL, CONTENT_TREE).checkItem(src_item))
+                       {
+                               src_list->decrementMaterials(1);
+                               dst_list->addItem(0, new CraftItem("lump_of_coal", 1));
+                               m_src_time = 0;
+                               m_src_totaltime = 0;
+                       }
+               }
+               return true;
+       }
+       
+       if(src_item == NULL || m_src_totaltime < 0.001)
+       {
+               return false;
+       }
+       
+       bool changed = false;
+
+       //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 = 10;
+               m_fuel_time = 0;
+               fuel_list->decrementMaterials(1);
+               changed = true;
+       }
+       else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
+       {
+               m_fuel_totaltime = 5;
+               m_fuel_time = 0;
+               fuel_list->decrementMaterials(1);
+               changed = true;
+       }
+       else if(ItemSpec(ITEM_CRAFT, "lump_of_coal").checkItem(fuel_item))
+       {
+               m_fuel_totaltime = 10;
+               m_fuel_time = 0;
+               fuel_list->decrementMaterials(1);
+               changed = true;
+       }
+       else
+       {
+               //dstream<<"No fuel found"<<std::endl;
+       }
+
+       return changed;
+}
 
 /*
        NodeMetadatalist
@@ -318,3 +434,32 @@ void NodeMetadataList::set(v3s16 p, NodeMetadata *d)
        m_data.insert(p, d);
 }
 
+bool NodeMetadataList::step(float dtime)
+{
+       bool something_changed = false;
+       for(core::map<v3s16, NodeMetadata*>::Iterator
+                       i = m_data.getIterator();
+                       i.atEnd()==false; i++)
+       {
+               v3s16 p = i.getNode()->getKey();
+               NodeMetadata *meta = i.getNode()->getValue();
+               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;
+}
+
index e8aa57622d51a1706e9e278331134796e8abcafc..c38ab13102fb45857eb334f3024a07135bb49068 100644 (file)
@@ -59,6 +59,8 @@ public:
        // This is called always after the inventory is modified, before
        // the changes are copied elsewhere
        virtual void inventoryModified(){}
+       // A step in time. Returns true if metadata changed.
+       virtual bool step(float dtime) {return false;}
 
 protected:
        static void registerType(u16 id, Factory f);
@@ -115,15 +117,23 @@ public:
        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:
@@ -138,6 +148,10 @@ public:
        void remove(v3s16 p);
        // Deletes old data and sets a new one
        void set(v3s16 p, NodeMetadata *d);
+       
+       // A step in time. Returns true if something changed.
+       bool step(float dtime);
+
 private:
        core::map<v3s16, NodeMetadata*> m_data;
 };
index df712e07f9164d6dc3a5f893253bd74987585830..c405af3f50e0e79e4f39784d49b21ab1e91c7d6a 100644 (file)
@@ -1503,6 +1503,32 @@ void Server::AsyncRunStep()
                }
        }
        
+       /*
+               Step node metadata
+       */
+       {
+               JMutexAutoLock envlock(m_env_mutex);
+               JMutexAutoLock conlock(m_con_mutex);
+               
+               core::map<v3s16, MapBlock*> changed_blocks;
+               m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
+
+               for(core::map<v3s16, MapBlock*>::Iterator
+                               i = changed_blocks.getIterator();
+                               i.atEnd() == false; i++)
+               {
+                       MapBlock *block = i.getNode()->getValue();
+
+                       for(core::map<u16, RemoteClient*>::Iterator
+                               i = m_clients.getIterator();
+                               i.atEnd()==false; i++)
+                       {
+                               RemoteClient *client = i.getNode()->getValue();
+                               client->SetBlockNotSent(block->getPos());
+                       }
+               }
+       }
+               
        /*
                Trigger emergethread (it somehow gets to a non-triggered but
                bysy state sometimes)
@@ -2740,7 +2766,6 @@ void Server::inventoryModified(InventoryContext *c, std::string id)
                p.X = stoi(fn.next(","));
                p.Y = stoi(fn.next(","));
                p.Z = stoi(fn.next(","));
-               assert(c->current_player);
                v3s16 blockpos = getNodeBlockPos(p);
 
                NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
@@ -2888,163 +2913,6 @@ void Server::SendPlayerInfos()
        m_con.SendToAll(0, data, true);
 }
 
-/*
-       Craft checking system
-*/
-
-enum ItemSpecType
-{
-       ITEM_NONE,
-       ITEM_MATERIAL,
-       ITEM_CRAFT,
-       ITEM_TOOL,
-       ITEM_MBO
-};
-
-struct ItemSpec
-{
-       ItemSpec():
-               type(ITEM_NONE)
-       {
-       }
-       ItemSpec(enum ItemSpecType a_type, std::string a_name):
-               type(a_type),
-               name(a_name),
-               num(65535)
-       {
-       }
-       ItemSpec(enum ItemSpecType a_type, u16 a_num):
-               type(a_type),
-               name(""),
-               num(a_num)
-       {
-       }
-       enum ItemSpecType type;
-       // Only other one of these is used
-       std::string name;
-       u16 num;
-};
-
-/*
-       items: a pointer to an array of 9 pointers to items
-       specs: a pointer to an array of 9 ItemSpecs
-*/
-bool checkItemCombination(InventoryItem **items, ItemSpec *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].type == ITEM_NONE)
-                       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;
-               InventoryItem *item = items[items_y * 3 + items_x];
-               ItemSpec &spec = specs[specs_y * 3 + specs_x];
-               
-               if(spec.type == ITEM_NONE)
-               {
-                       // Has to be no item
-                       if(item != NULL)
-                               return false;
-                       continue;
-               }
-               
-               // There should be an item
-               if(item == NULL)
-                       return false;
-
-               std::string itemname = item->getName();
-
-               if(spec.type == ITEM_MATERIAL)
-               {
-                       if(itemname != "MaterialItem")
-                               return false;
-                       MaterialItem *mitem = (MaterialItem*)item;
-                       if(mitem->getMaterial() != spec.num)
-                               return false;
-               }
-               else if(spec.type == ITEM_CRAFT)
-               {
-                       if(itemname != "CraftItem")
-                               return false;
-                       CraftItem *mitem = (CraftItem*)item;
-                       if(mitem->getSubName() != spec.name)
-                               return false;
-               }
-               else if(spec.type == ITEM_TOOL)
-               {
-                       // Not supported yet
-                       assert(0);
-               }
-               else if(spec.type == ITEM_MBO)
-               {
-                       // Not supported yet
-                       assert(0);
-               }
-               else
-               {
-                       // Not supported yet
-                       assert(0);
-               }
-       }
-
-       return true;
-}
-
 void Server::SendInventory(u16 peer_id)
 {
        DSTACK(__FUNCTION_NAME);