initial workings of the furnace

This commit is contained in:
Perttu Ahola 2011-04-05 02:56:29 +03:00
parent 281f76b6a0
commit d1d57cf5c3
9 changed files with 423 additions and 165 deletions

View 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)
@ -699,4 +721,131 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr)
#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

View 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

View 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
*/

View File

@ -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

View 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()
{

View 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
{

View 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;
}

View 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;
};

View 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);