diff --git a/src/inventory.cpp b/src/inventory.cpp index a610a46..86e0087 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -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; ym_node_metadata.remove(p_rel); } +void Map::nodeMetadataStep(float dtime, + core::map &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::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 */ diff --git a/src/map.h b/src/map.h index b1b3b9a..081705a 100644 --- 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 &changed_blocks); /* Variables diff --git a/src/mapnode.cpp b/src/mapnode.cpp index 8e968c8..187689c 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -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() { diff --git a/src/mapnode.h b/src/mapnode.h index ce233e8..0423483 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -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 { diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp index 2405e76..21f55a0 100644 --- a/src/nodemetadata.cpp +++ b/src/nodemetadata.cpp @@ -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<= 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"<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"<= 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"<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"<::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; +} + diff --git a/src/nodemetadata.h b/src/nodemetadata.h index e8aa576..c38ab13 100644 --- a/src/nodemetadata.h +++ b/src/nodemetadata.h @@ -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 m_data; }; diff --git a/src/server.cpp b/src/server.cpp index df712e0..c405af3 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1503,6 +1503,32 @@ void Server::AsyncRunStep() } } + /* + Step node metadata + */ + { + JMutexAutoLock envlock(m_env_mutex); + JMutexAutoLock conlock(m_con_mutex); + + core::map changed_blocks; + m_env.getMap().nodeMetadataStep(dtime, changed_blocks); + + for(core::map::Iterator + i = changed_blocks.getIterator(); + i.atEnd() == false; i++) + { + MapBlock *block = i.getNode()->getValue(); + + for(core::map::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; ygetName(); - - 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);