}
}
+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)
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
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);
// 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.
*/
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
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
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
*/
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
#include "mineral.h"
// For g_settings
#include "main.h"
+#include "nodemetadata.h"
ContentFeatures::~ContentFeatures()
{
#include "serialization.h"
#include "tile.h"
#include "iirrlichtwrapper.h"
-#include "nodemetadata.h"
/*
Initializes all kind of stuff in here.
};
class MapNode;
+class NodeMetadata;
struct ContentFeatures
{
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()
{
{
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
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;
+}
+
// 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);
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:
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;
};
}
}
+ /*
+ 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)
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);
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);