WIP node metadata, node timers

This commit is contained in:
Kahrl 2012-03-19 01:08:04 +01:00 committed by Perttu Ahola
parent 67059e1932
commit 704782c95b
19 changed files with 788 additions and 1386 deletions

@ -177,6 +177,7 @@ set(common_SRCS
content_mapnode.cpp content_mapnode.cpp
collision.cpp collision.cpp
nodemetadata.cpp nodemetadata.cpp
nodetimer.cpp
serverobject.cpp serverobject.cpp
noise.cpp noise.cpp
porting.cpp porting.cpp

@ -1,6 +1,6 @@
/* /*
Minetest-c55 Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -18,15 +18,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "content_nodemeta.h" #include "content_nodemeta.h"
#include <map>
#include "inventory.h" #include "inventory.h"
#include "log.h" #include "log.h"
#include "utility.h" #include "utility.h"
#include "craftdef.h"
#include "gamedef.h"
class Inventory;
#define NODEMETA_GENERIC 1 #define NODEMETA_GENERIC 1
#define NODEMETA_SIGN 14 #define NODEMETA_SIGN 14
@ -34,809 +28,149 @@ class Inventory;
#define NODEMETA_FURNACE 16 #define NODEMETA_FURNACE 16
#define NODEMETA_LOCKABLE_CHEST 17 #define NODEMETA_LOCKABLE_CHEST 17
core::map<u16, NodeMetadata::Factory> NodeMetadata::m_types; // Returns true if node timer must be set
core::map<std::string, NodeMetadata::Factory2> NodeMetadata::m_names; static bool content_nodemeta_deserialize_legacy_body(
std::istream &is, s16 id, NodeMetadata *meta)
{
meta->clear();
class SignNodeMetadata : public NodeMetadata if(id == NODEMETA_GENERIC) // GenericNodeMetadata (0.4-dev)
{
public:
SignNodeMetadata(IGameDef *gamedef, std::string text);
//~SignNodeMetadata();
virtual u16 typeId() const;
virtual const char* typeName() const
{ return "sign"; }
static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
static NodeMetadata* create(IGameDef *gamedef);
virtual NodeMetadata* clone(IGameDef *gamedef);
virtual void serializeBody(std::ostream &os);
virtual std::string infoText();
virtual bool allowsTextInput(){ return true; }
virtual std::string getText(){ return m_text; }
virtual void setText(const std::string &t){ m_text = t; }
private:
std::string m_text;
};
class ChestNodeMetadata : public NodeMetadata
{
public:
ChestNodeMetadata(IGameDef *gamedef);
~ChestNodeMetadata();
virtual u16 typeId() const;
virtual const char* typeName() const
{ return "chest"; }
static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
static NodeMetadata* create(IGameDef *gamedef);
virtual NodeMetadata* clone(IGameDef *gamedef);
virtual void serializeBody(std::ostream &os);
virtual std::string infoText();
virtual Inventory* getInventory() {return m_inventory;}
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
private:
Inventory *m_inventory;
};
class LockingChestNodeMetadata : public NodeMetadata
{
public:
LockingChestNodeMetadata(IGameDef *gamedef);
~LockingChestNodeMetadata();
virtual u16 typeId() const;
virtual const char* typeName() const
{ return "locked_chest"; }
static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
static NodeMetadata* create(IGameDef *gamedef);
virtual NodeMetadata* clone(IGameDef *gamedef);
virtual void serializeBody(std::ostream &os);
virtual std::string infoText();
virtual Inventory* getInventory() {return m_inventory;}
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
virtual std::string getOwner(){ return m_text; }
virtual void setOwner(std::string t){ m_text = t; }
private:
Inventory *m_inventory;
std::string m_text;
};
class FurnaceNodeMetadata : public NodeMetadata
{
public:
FurnaceNodeMetadata(IGameDef *gamedef);
~FurnaceNodeMetadata();
virtual u16 typeId() const;
virtual const char* typeName() const
{ return "furnace"; }
virtual NodeMetadata* clone(IGameDef *gamedef);
static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
static NodeMetadata* create(IGameDef *gamedef);
virtual void serializeBody(std::ostream &os);
virtual std::string infoText();
virtual Inventory* getInventory() {return m_inventory;}
virtual void inventoryModified();
virtual bool step(float dtime);
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
protected:
bool getCookResult(bool remove, std::string &cookresult, float &cooktime);
bool getBurnResult(bool remove, float &burntime);
private:
Inventory *m_inventory;
std::string m_infotext;
float m_step_accumulator;
float m_fuel_totaltime;
float m_fuel_time;
float m_src_totaltime;
float m_src_time;
};
/*
SignNodeMetadata
*/
// Prototype
SignNodeMetadata proto_SignNodeMetadata(NULL, "");
SignNodeMetadata::SignNodeMetadata(IGameDef *gamedef, std::string text):
NodeMetadata(gamedef),
m_text(text)
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
}
u16 SignNodeMetadata::typeId() const
{
return NODEMETA_SIGN;
}
NodeMetadata* SignNodeMetadata::create(std::istream &is, IGameDef *gamedef)
{
std::string text = deSerializeString(is);
return new SignNodeMetadata(gamedef, text);
}
NodeMetadata* SignNodeMetadata::create(IGameDef *gamedef)
{
return new SignNodeMetadata(gamedef, "");
}
NodeMetadata* SignNodeMetadata::clone(IGameDef *gamedef)
{
return new SignNodeMetadata(gamedef, m_text);
}
void SignNodeMetadata::serializeBody(std::ostream &os)
{
os<<serializeString(m_text);
}
std::string SignNodeMetadata::infoText()
{
return std::string("\"")+m_text+"\"";
}
/*
ChestNodeMetadata
*/
// Prototype
ChestNodeMetadata proto_ChestNodeMetadata(NULL);
ChestNodeMetadata::ChestNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef)
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
m_inventory = NULL;
}
ChestNodeMetadata::~ChestNodeMetadata()
{
delete m_inventory;
}
u16 ChestNodeMetadata::typeId() const
{
return NODEMETA_CHEST;
}
NodeMetadata* ChestNodeMetadata::create(std::istream &is, IGameDef *gamedef)
{
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->deSerialize(is);
return d;
}
NodeMetadata* ChestNodeMetadata::create(IGameDef *gamedef)
{
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->addList("0", 8*4);
return d;
}
NodeMetadata* ChestNodeMetadata::clone(IGameDef *gamedef)
{
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
d->m_inventory = new Inventory(*m_inventory);
return d;
}
void ChestNodeMetadata::serializeBody(std::ostream &os)
{
m_inventory->serialize(os);
}
std::string ChestNodeMetadata::infoText()
{
return "Chest";
}
bool ChestNodeMetadata::nodeRemovalDisabled()
{
/*
Disable removal if chest contains something
*/
InventoryList *list = m_inventory->getList("0");
if(list == NULL)
return false;
if(list->getUsedSlots() == 0)
return false;
return true;
}
std::string ChestNodeMetadata::getInventoryDrawSpecString()
{
return
"invsize[8,9;]"
"list[current_name;0;0,0;8,4;]"
"list[current_player;main;0,5;8,4;]";
}
/*
LockingChestNodeMetadata
*/
// Prototype
LockingChestNodeMetadata proto_LockingChestNodeMetadata(NULL);
LockingChestNodeMetadata::LockingChestNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef)
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
m_inventory = NULL;
}
LockingChestNodeMetadata::~LockingChestNodeMetadata()
{
delete m_inventory;
}
u16 LockingChestNodeMetadata::typeId() const
{
return NODEMETA_LOCKABLE_CHEST;
}
NodeMetadata* LockingChestNodeMetadata::create(std::istream &is, IGameDef *gamedef)
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
d->setOwner(deSerializeString(is));
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->deSerialize(is);
return d;
}
NodeMetadata* LockingChestNodeMetadata::create(IGameDef *gamedef)
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->addList("0", 8*4);
return d;
}
NodeMetadata* LockingChestNodeMetadata::clone(IGameDef *gamedef)
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
d->m_inventory = new Inventory(*m_inventory);
return d;
}
void LockingChestNodeMetadata::serializeBody(std::ostream &os)
{
os<<serializeString(m_text);
m_inventory->serialize(os);
}
std::string LockingChestNodeMetadata::infoText()
{
return "Locking Chest";
}
bool LockingChestNodeMetadata::nodeRemovalDisabled()
{
/*
Disable removal if chest contains something
*/
InventoryList *list = m_inventory->getList("0");
if(list == NULL)
return false;
if(list->getUsedSlots() == 0)
return false;
return true;
}
std::string LockingChestNodeMetadata::getInventoryDrawSpecString()
{
return
"invsize[8,9;]"
"list[current_name;0;0,0;8,4;]"
"list[current_player;main;0,5;8,4;]";
}
/*
FurnaceNodeMetadata
*/
// Prototype
FurnaceNodeMetadata proto_FurnaceNodeMetadata(NULL);
FurnaceNodeMetadata::FurnaceNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef)
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
m_inventory = NULL;
m_infotext = "Furnace is inactive";
m_step_accumulator = 0;
m_fuel_totaltime = 0;
m_fuel_time = 0;
m_src_totaltime = 0;
m_src_time = 0;
}
FurnaceNodeMetadata::~FurnaceNodeMetadata()
{
delete m_inventory;
}
u16 FurnaceNodeMetadata::typeId() const
{
return NODEMETA_FURNACE;
}
NodeMetadata* FurnaceNodeMetadata::clone(IGameDef *gamedef)
{
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(m_gamedef);
d->m_inventory = new Inventory(*m_inventory);
return d;
}
NodeMetadata* FurnaceNodeMetadata::create(std::istream &is, IGameDef *gamedef)
{
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->deSerialize(is);
int temp = 0;
is>>temp;
d->m_fuel_totaltime = (float)temp/10;
temp = 0;
is>>temp;
d->m_fuel_time = (float)temp/10;
temp = 0;
is>>temp;
d->m_src_totaltime = (float)temp/10;
temp = 0;
is>>temp;
d->m_src_time = (float)temp/10;
if(is.eof())
{ {
// Old furnaces didn't serialize src_totaltime and src_time meta->getInventory()->deSerialize(is);
d->m_src_totaltime = 0; deSerializeLongString(is); // m_text
d->m_src_time = 0; deSerializeString(is); // m_owner
d->m_infotext = "";
}
else
{
// New furnaces also serialize the infotext (so that the
// client doesn't need to have the list of cooking recipes).
d->m_infotext = deSerializeJsonString(is);
}
return d; meta->setInfoText(deSerializeString(is));
} meta->setInventoryDrawSpec(deSerializeString(is));
NodeMetadata* FurnaceNodeMetadata::create(IGameDef *gamedef) readU8(is); // m_allow_text_input
{ meta->setAllowRemoval(readU8(is) == 0);
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef); readU8(is); // m_enforce_owner
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->addList("fuel", 1);
d->m_inventory->addList("src", 1);
d->m_inventory->addList("dst", 4);
return d;
}
void FurnaceNodeMetadata::serializeBody(std::ostream &os)
{
m_inventory->serialize(os);
os<<itos(m_fuel_totaltime*10)<<" ";
os<<itos(m_fuel_time*10)<<" ";
os<<itos(m_src_totaltime*10)<<" ";
os<<itos(m_src_time*10)<<" ";
os<<serializeJsonString(m_infotext);
}
std::string FurnaceNodeMetadata::infoText()
{
return m_infotext;
}
bool FurnaceNodeMetadata::nodeRemovalDisabled()
{
/*
Disable removal if furnace is not empty
*/
InventoryList *list[3] = {m_inventory->getList("src"),
m_inventory->getList("dst"), m_inventory->getList("fuel")};
for(int i = 0; i < 3; i++) {
if(list[i] == NULL)
continue;
if(list[i]->getUsedSlots() == 0)
continue;
return true;
}
return false;
}
void FurnaceNodeMetadata::inventoryModified()
{
infostream<<"Furnace inventory modification callback"<<std::endl;
}
bool FurnaceNodeMetadata::step(float dtime)
{
if(dtime > 60.0)
infostream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
InventoryList *dst_list = m_inventory->getList("dst");
assert(dst_list);
// Update at a fixed frequency
const float interval = 2.0;
m_step_accumulator += dtime;
bool changed = false;
while(m_step_accumulator > interval)
{
m_step_accumulator -= interval;
dtime = interval;
//infostream<<"Furnace step dtime="<<dtime<<std::endl;
bool changed_this_loop = false;
// Check
// 1. if the source item is cookable
// 2. if there is room for the cooked item
std::string cookresult;
float cooktime;
bool cookable = getCookResult(false, cookresult, cooktime);
ItemStack cookresult_item;
bool room_available = false;
if(cookable)
{
cookresult_item.deSerialize(cookresult, m_gamedef->idef());
room_available = dst_list->roomForItem(cookresult_item);
}
// Step fuel time
bool burning = (m_fuel_time < m_fuel_totaltime);
if(burning)
{
changed_this_loop = true;
m_fuel_time += dtime;
}
std::string infotext;
if(room_available)
{
float burntime;
if(burning)
{
changed_this_loop = true;
m_src_time += dtime;
m_src_totaltime = cooktime;
infotext = "Furnace is cooking";
}
else if(getBurnResult(true, burntime))
{
// Fuel inserted
changed_this_loop = true;
m_fuel_time = 0;
m_fuel_totaltime = burntime;
//m_src_time += dtime;
//m_src_totaltime = cooktime;
infotext = "Furnace is cooking";
}
else
{
m_src_time = 0;
m_src_totaltime = 0;
infotext = "Furnace is out of fuel";
}
if(m_src_totaltime > 0.001 && m_src_time >= m_src_totaltime)
{
// One item fully cooked
changed_this_loop = true;
dst_list->addItem(cookresult_item);
getCookResult(true, cookresult, cooktime); // decrement source
m_src_totaltime = 0;
m_src_time = 0;
}
}
else
{
// Not cookable or no room available
m_src_totaltime = 0;
m_src_time = 0;
if(cookable)
infotext = "Furnace is overloaded";
else if(burning)
infotext = "Furnace is active";
else
{
infotext = "Furnace is inactive";
m_fuel_totaltime = 0;
m_fuel_time = 0;
}
}
// Do this so it doesn't always show (0%) for weak fuel
if(m_fuel_totaltime > 3) {
infotext += " (";
infotext += itos(m_fuel_time/m_fuel_totaltime*100);
infotext += "%)";
}
if(infotext != m_infotext)
{
m_infotext = infotext;
changed_this_loop = true;
}
if(burning && m_fuel_time >= m_fuel_totaltime)
{
m_fuel_time = 0;
m_fuel_totaltime = 0;
}
if(changed_this_loop)
{
changed = true;
}
else
{
m_step_accumulator = 0;
break;
}
}
return changed;
}
std::string FurnaceNodeMetadata::getInventoryDrawSpecString()
{
return
"invsize[8,9;]"
"list[current_name;fuel;2,3;1,1;]"
"list[current_name;src;2,1;1,1;]"
"list[current_name;dst;5,1;2,2;]"
"list[current_player;main;0,5;8,4;]";
}
bool FurnaceNodeMetadata::getCookResult(bool remove,
std::string &cookresult, float &cooktime)
{
std::vector<ItemStack> items;
InventoryList *src_list = m_inventory->getList("src");
assert(src_list);
items.push_back(src_list->getItem(0));
CraftInput ci(CRAFT_METHOD_COOKING, 1, items);
CraftOutput co;
bool found = m_gamedef->getCraftDefManager()->getCraftResult(
ci, co, remove, m_gamedef);
if(remove)
src_list->changeItem(0, ci.items[0]);
cookresult = co.item;
cooktime = co.time;
return found;
}
bool FurnaceNodeMetadata::getBurnResult(bool remove, float &burntime)
{
std::vector<ItemStack> items;
InventoryList *fuel_list = m_inventory->getList("fuel");
assert(fuel_list);
items.push_back(fuel_list->getItem(0));
CraftInput ci(CRAFT_METHOD_FUEL, 1, items);
CraftOutput co;
bool found = m_gamedef->getCraftDefManager()->getCraftResult(
ci, co, remove, m_gamedef);
if(remove)
fuel_list->changeItem(0, ci.items[0]);
burntime = co.time;
return found;
}
/*
GenericNodeMetadata
*/
class GenericNodeMetadata : public NodeMetadata
{
private:
Inventory *m_inventory;
std::string m_text;
std::string m_owner;
std::string m_infotext;
std::string m_inventorydrawspec;
bool m_allow_text_input;
bool m_removal_disabled;
bool m_enforce_owner;
bool m_inventory_modified;
bool m_text_modified;
std::map<std::string, std::string> m_stringvars;
public:
u16 typeId() const
{
return NODEMETA_GENERIC;
}
const char* typeName() const
{
return "generic";
}
GenericNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef),
m_inventory(NULL),
m_text(""),
m_owner(""),
m_infotext("GenericNodeMetadata"),
m_inventorydrawspec(""),
m_allow_text_input(false),
m_removal_disabled(false),
m_enforce_owner(false),
m_inventory_modified(false),
m_text_modified(false)
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
}
virtual ~GenericNodeMetadata()
{
delete m_inventory;
}
NodeMetadata* clone(IGameDef *gamedef)
{
GenericNodeMetadata *d = new GenericNodeMetadata(m_gamedef);
d->m_inventory = new Inventory(*m_inventory);
d->m_text = m_text;
d->m_owner = m_owner;
d->m_infotext = m_infotext;
d->m_inventorydrawspec = m_inventorydrawspec;
d->m_allow_text_input = m_allow_text_input;
d->m_removal_disabled = m_removal_disabled;
d->m_enforce_owner = m_enforce_owner;
d->m_inventory_modified = m_inventory_modified;
d->m_text_modified = m_text_modified;
return d;
}
static NodeMetadata* create(IGameDef *gamedef)
{
GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
return d;
}
static NodeMetadata* create(std::istream &is, IGameDef *gamedef)
{
GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->deSerialize(is);
d->m_text = deSerializeLongString(is);
d->m_owner = deSerializeString(is);
d->m_infotext = deSerializeString(is);
d->m_inventorydrawspec = deSerializeString(is);
d->m_allow_text_input = readU8(is);
d->m_removal_disabled = readU8(is);
d->m_enforce_owner = readU8(is);
int num_vars = readU32(is); int num_vars = readU32(is);
for(int i=0; i<num_vars; i++){ for(int i=0; i<num_vars; i++){
std::string name = deSerializeString(is); std::string name = deSerializeString(is);
std::string var = deSerializeLongString(is); std::string var = deSerializeLongString(is);
d->m_stringvars[name] = var; meta->setString(name, var);
} }
return d;
}
void serializeBody(std::ostream &os)
{
m_inventory->serialize(os);
os<<serializeLongString(m_text);
os<<serializeString(m_owner);
os<<serializeString(m_infotext);
os<<serializeString(m_inventorydrawspec);
writeU8(os, m_allow_text_input);
writeU8(os, m_removal_disabled);
writeU8(os, m_enforce_owner);
int num_vars = m_stringvars.size();
writeU32(os, num_vars);
for(std::map<std::string, std::string>::iterator
i = m_stringvars.begin(); i != m_stringvars.end(); i++){
os<<serializeString(i->first);
os<<serializeLongString(i->second);
}
}
std::string infoText()
{
return m_infotext;
}
Inventory* getInventory()
{
return m_inventory;
}
void inventoryModified()
{
m_inventory_modified = true;
}
bool step(float dtime)
{
return false; return false;
} }
bool nodeRemovalDisabled() else if(id == NODEMETA_SIGN) // SignNodeMetadata
{ {
return m_removal_disabled; meta->setString("text", deSerializeLongString(is));
meta->setInfoText("\"${text}\"");
meta->setFormSpec("field[text;;${text}]");
return false;
} }
std::string getInventoryDrawSpecString() else if(id == NODEMETA_CHEST) // ChestNodeMetadata
{ {
return m_inventorydrawspec; meta->getInventory()->deSerialize(is);
meta->setInventoryDrawSpec("invsize[8,9;]"
"list[current_name;0;0,0;8,4;]"
"list[current_player;main;0,5;8,4;]");
return false;
} }
bool allowsTextInput() else if(id == NODEMETA_LOCKABLE_CHEST) // LockingChestNodeMetadata
{ {
return m_allow_text_input; meta->setString("owner", deSerializeString(is));
meta->getInventory()->deSerialize(is);
meta->setInventoryDrawSpec("invsize[8,9;]"
"list[current_name;0;0,0;8,4;]"
"list[current_player;main;0,5;8,4;]");
return false;
} }
std::string getText() else if(id == NODEMETA_FURNACE) // FurnaceNodeMetadata
{ {
return m_text; meta->getInventory()->deSerialize(is);
} int temp = 0;
void setText(const std::string &t) is>>temp;
{ meta->setString("fuel_totaltime", ftos((float)temp/10));
m_text = t; temp = 0;
m_text_modified = true; is>>temp;
} meta->setString("fuel_time", ftos((float)temp/10));
std::string getOwner() temp = 0;
{ is>>temp;
if(m_enforce_owner) //meta->setString("src_totaltime", ftos((float)temp/10));
return m_owner; temp = 0;
else is>>temp;
return ""; meta->setString("src_time", ftos((float)temp/10));
}
void setOwner(std::string t)
{
m_owner = t;
}
/* Interface for GenericNodeMetadata */
void setInfoText(const std::string &text) meta->setInventoryDrawSpec("invsize[8,9;]"
{ "list[current_name;fuel;2,3;1,1;]"
infostream<<"GenericNodeMetadata::setInfoText(\"" "list[current_name;src;2,1;1,1;]"
<<text<<"\")"<<std::endl; "list[current_name;dst;5,1;2,2;]"
m_infotext = text; "list[current_player;main;0,5;8,4;]");
return true;
} }
void setInventoryDrawSpec(const std::string &text) else
{ {
m_inventorydrawspec = text; throw SerializationError("Unknown legacy node metadata");
} }
void setAllowTextInput(bool b) }
{
m_allow_text_input = b;
}
void setRemovalDisabled(bool b)
{
m_removal_disabled = b;
}
void setEnforceOwner(bool b)
{
m_enforce_owner = b;
}
bool isInventoryModified()
{
return m_inventory_modified;
}
void resetInventoryModified()
{
m_inventory_modified = false;
}
bool isTextModified()
{
return m_text_modified;
}
void resetTextModified()
{
m_text_modified = false;
}
void setString(const std::string &name, const std::string &var)
{
m_stringvars[name] = var;
}
std::string getString(const std::string &name)
{
std::map<std::string, std::string>::iterator i;
i = m_stringvars.find(name);
if(i == m_stringvars.end())
return "";
return i->second;
}
};
// Prototype static bool content_nodemeta_deserialize_legacy_meta(
GenericNodeMetadata proto_GenericNodeMetadata(NULL); std::istream &is, NodeMetadata *meta)
{
// Read id
s16 id = readS16(is);
// Read data
std::string data = deSerializeString(is);
std::istringstream tmp_is(data, std::ios::binary);
return content_nodemeta_deserialize_legacy_body(tmp_is, id, meta);
}
void content_nodemeta_deserialize_legacy(std::istream &is,
NodeMetadataList *meta, NodeTimerList *timers,
IGameDef *gamedef)
{
meta->clear();
timers->clear();
u16 version = readU16(is);
if(version > 1)
{
infostream<<__FUNCTION_NAME<<": version "<<version<<" not supported"
<<std::endl;
throw SerializationError(__FUNCTION_NAME);
}
u16 count = readU16(is);
for(u16 i=0; i<count; i++)
{
u16 p16 = readU16(is);
v3s16 p(0,0,0);
p.Z += p16 / MAP_BLOCKSIZE / MAP_BLOCKSIZE;
p16 -= p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
p.Y += p16 / MAP_BLOCKSIZE;
p16 -= p.Y * MAP_BLOCKSIZE;
p.X += p16;
if(meta->get(p) != NULL)
{
infostream<<"WARNING: "<<__FUNCTION_NAME<<": "
<<"already set data at position"
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
<<std::endl;
continue;
}
NodeMetadata *data = new NodeMetadata(gamedef);
bool need_timer = content_nodemeta_deserialize_legacy_meta(is, data);
meta->set(p, data);
if(need_timer)
timers->set(p, NodeTimer(1., 0.));
}
}
void content_nodemeta_serialize_legacy(std::ostream &os, NodeMetadataList *meta)
{
// Sorry, I was too lazy to implement this. --kahrl
writeU16(os, 1); // version
writeU16(os, 0); // count
}
// END

@ -21,6 +21,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define CONTENT_NODEMETA_HEADER #define CONTENT_NODEMETA_HEADER
#include "nodemetadata.h" #include "nodemetadata.h"
#include "nodetimer.h"
/*
Legacy nodemeta definitions
*/
void content_nodemeta_deserialize_legacy(std::istream &is,
NodeMetadataList *meta, NodeTimerList *timers,
IGameDef *gamedef);
void content_nodemeta_serialize_legacy(std::ostream &os, NodeMetadataList *meta);
#endif #endif

@ -773,18 +773,11 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
// Activate stored objects // Activate stored objects
activateObjects(block); activateObjects(block);
// Run node metadata // Run node timers
bool changed = block->m_node_metadata->step((float)dtime_s); std::map<v3s16, f32> elapsed_timers =
if(changed) block->m_node_timers.step((float)dtime_s);
{ if(!elapsed_timers.empty())
MapEditEvent event; errorstream<<"Node timers don't work yet!"<<std::endl;
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
event.p = block->getPos();
m_map->dispatchEvent(&event);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"node metadata modified in activateBlock");
}
/* Handle ActiveBlockModifiers */ /* Handle ActiveBlockModifiers */
ABMHandler abmhandler(m_abms, dtime_s, this, false); ABMHandler abmhandler(m_abms, dtime_s, this, false);
@ -1064,18 +1057,11 @@ void ServerEnvironment::step(float dtime)
block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD, block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
"Timestamp older than 60s (step)"); "Timestamp older than 60s (step)");
// Run node metadata // Run node timers
bool changed = block->m_node_metadata->step(dtime); std::map<v3s16, f32> elapsed_timers =
if(changed) block->m_node_timers.step(dtime);
{ if(!elapsed_timers.empty())
MapEditEvent event; errorstream<<"Node timers don't work yet!"<<std::endl;
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
event.p = p;
m_map->dispatchEvent(&event);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"node metadata modified in step");
}
} }
} }

@ -2195,7 +2195,7 @@ void the_game(
ClientMap &map = client.getEnv().getClientMap(); ClientMap &map = client.getEnv().getClientMap();
NodeMetadata *meta = map.getNodeMetadata(nodepos); NodeMetadata *meta = map.getNodeMetadata(nodepos);
if(meta){ if(meta){
infotext = narrow_to_wide(meta->infoText()); infotext = narrow_to_wide(meta->getInfoText());
} else { } else {
MapNode n = map.getNode(nodepos); MapNode n = map.getNode(nodepos);
if(nodedef->get(n).tname_tiles[0] == "unknown_block.png"){ if(nodedef->get(n).tname_tiles[0] == "unknown_block.png"){
@ -2321,6 +2321,8 @@ void the_game(
infostream<<"Ground right-clicked"<<std::endl; infostream<<"Ground right-clicked"<<std::endl;
// If metadata provides an inventory view, activate it // If metadata provides an inventory view, activate it
errorstream<<"Need to implement metadata formspecs"<<std::endl;
#if 0
if(meta && meta->getInventoryDrawSpecString() != "" && !random_input) if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
{ {
infostream<<"Launching custom inventory view"<<std::endl; infostream<<"Launching custom inventory view"<<std::endl;
@ -2362,6 +2364,9 @@ void the_game(
&g_menumgr, dest, &g_menumgr, dest,
wtext))->drop(); wtext))->drop();
} }
#else
if(0) /* do nothing */;
#endif
// Otherwise report right click to server // Otherwise report right click to server
else else
{ {

@ -1015,21 +1015,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
setNode(p, n); setNode(p, n);
/*
Add intial metadata
*/
std::string metadata_name = nodemgr->get(n).metadata_name;
if(metadata_name != ""){
NodeMetadata *meta = NodeMetadata::create(metadata_name, m_gamedef);
if(!meta){
errorstream<<"Failed to create node metadata \""
<<metadata_name<<"\""<<std::endl;
} else {
setNodeMetadata(p, meta);
}
}
/* /*
If node is under sunlight and doesn't let sunlight through, If node is under sunlight and doesn't let sunlight through,
take all sunlighted nodes under it and clear light from them take all sunlighted nodes under it and clear light from them
@ -1853,7 +1838,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p)
<<std::endl; <<std::endl;
return NULL; return NULL;
} }
NodeMetadata *meta = block->m_node_metadata->get(p_rel); NodeMetadata *meta = block->m_node_metadata.get(p_rel);
return meta; return meta;
} }
@ -1873,7 +1858,7 @@ void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
<<std::endl; <<std::endl;
return; return;
} }
block->m_node_metadata->set(p_rel, meta); block->m_node_metadata.set(p_rel, meta);
} }
void Map::removeNodeMetadata(v3s16 p) void Map::removeNodeMetadata(v3s16 p)
@ -1887,36 +1872,7 @@ void Map::removeNodeMetadata(v3s16 p)
<<std::endl; <<std::endl;
return; return;
} }
block->m_node_metadata->remove(p_rel); 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;
}
}
} }
/* /*

@ -309,9 +309,7 @@ public:
NodeMetadata* getNodeMetadata(v3s16 p); NodeMetadata* getNodeMetadata(v3s16 p);
void setNodeMetadata(v3s16 p, NodeMetadata *meta); void setNodeMetadata(v3s16 p, NodeMetadata *meta);
void removeNodeMetadata(v3s16 p); void removeNodeMetadata(v3s16 p);
void nodeMetadataStep(float dtime,
core::map<v3s16, MapBlock*> &changed_blocks);
/* /*
Misc. Misc.
*/ */

@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h" #include "log.h"
#include "nameidmapping.h" #include "nameidmapping.h"
#include "content_mapnode.h" // For legacy name-id mapping #include "content_mapnode.h" // For legacy name-id mapping
#include "content_nodemeta.h" // For legacy deserialization
#ifndef SERVER #ifndef SERVER
#include "mapblock_mesh.h" #include "mapblock_mesh.h"
#endif #endif
@ -39,7 +40,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy): MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy):
m_node_metadata(new NodeMetadataList),
m_parent(parent), m_parent(parent),
m_pos(pos), m_pos(pos),
m_gamedef(gamedef), m_gamedef(gamedef),
@ -79,8 +79,6 @@ MapBlock::~MapBlock()
} }
#endif #endif
delete m_node_metadata;
if(data) if(data)
delete[] data; delete[] data;
} }
@ -605,7 +603,10 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
Node metadata Node metadata
*/ */
std::ostringstream oss(std::ios_base::binary); std::ostringstream oss(std::ios_base::binary);
m_node_metadata->serialize(oss); if(version >= 23)
m_node_metadata.serialize(oss);
else
content_nodemeta_serialize_legacy(oss, &m_node_metadata);
compressZlib(oss.str(), os); compressZlib(oss.str(), os);
/* /*
@ -613,6 +614,10 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
*/ */
if(disk) if(disk)
{ {
// Node timers
if(version >= 23)
m_node_timers.serialize(os);
// Static objects // Static objects
m_static_objects.serialize(os); m_static_objects.serialize(os);
@ -665,12 +670,17 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
std::ostringstream oss(std::ios_base::binary); std::ostringstream oss(std::ios_base::binary);
decompressZlib(is, oss); decompressZlib(is, oss);
std::istringstream iss(oss.str(), std::ios_base::binary); std::istringstream iss(oss.str(), std::ios_base::binary);
m_node_metadata->deSerialize(iss, m_gamedef); if(version >= 23)
m_node_metadata.deSerialize(iss, m_gamedef);
else
content_nodemeta_deserialize_legacy(iss,
&m_node_metadata, &m_node_timers,
m_gamedef);
} }
catch(SerializationError &e) catch(SerializationError &e)
{ {
errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error" errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
<<" while deserializing node metadata"<<std::endl; <<" while deserializing node metadata: "<<e.what()<<std::endl;
} }
/* /*
@ -678,6 +688,10 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
*/ */
if(disk) if(disk)
{ {
// Node timers
if(version >= 23)
m_node_timers.deSerialize(is);
// Static objects // Static objects
m_static_objects.deSerialize(is); m_static_objects.deSerialize(is);
@ -857,7 +871,7 @@ void MapBlock::serialize_pre22(std::ostream &os, u8 version, bool disk)
{ {
try{ try{
std::ostringstream oss(std::ios_base::binary); std::ostringstream oss(std::ios_base::binary);
m_node_metadata->serialize(oss); content_nodemeta_serialize_legacy(oss, &m_node_metadata);
os<<serializeString(oss.str()); os<<serializeString(oss.str());
} }
// This will happen if the string is longer than 65535 // This will happen if the string is longer than 65535
@ -870,7 +884,7 @@ void MapBlock::serialize_pre22(std::ostream &os, u8 version, bool disk)
else else
{ {
std::ostringstream oss(std::ios_base::binary); std::ostringstream oss(std::ios_base::binary);
m_node_metadata->serialize(oss); content_nodemeta_serialize_legacy(oss, &m_node_metadata);
compressZlib(oss.str(), os); compressZlib(oss.str(), os);
//os<<serializeLongString(oss.str()); //os<<serializeLongString(oss.str());
} }
@ -1024,7 +1038,9 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
{ {
std::string data = deSerializeString(is); std::string data = deSerializeString(is);
std::istringstream iss(data, std::ios_base::binary); std::istringstream iss(data, std::ios_base::binary);
m_node_metadata->deSerialize(iss, m_gamedef); content_nodemeta_deserialize_legacy(iss,
&m_node_metadata, &m_node_timers,
m_gamedef);
} }
else else
{ {
@ -1032,7 +1048,9 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
std::ostringstream oss(std::ios_base::binary); std::ostringstream oss(std::ios_base::binary);
decompressZlib(is, oss); decompressZlib(is, oss);
std::istringstream iss(oss.str(), std::ios_base::binary); std::istringstream iss(oss.str(), std::ios_base::binary);
m_node_metadata->deSerialize(iss, m_gamedef); content_nodemeta_deserialize_legacy(iss,
&m_node_metadata, &m_node_timers,
m_gamedef);
} }
} }
catch(SerializationError &e) catch(SerializationError &e)

@ -31,6 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "constants.h" #include "constants.h"
#include "voxel.h" #include "voxel.h"
#include "staticobject.h" #include "staticobject.h"
#include "nodemetadata.h"
#include "nodetimer.h"
#include "modifiedstate.h" #include "modifiedstate.h"
class Map; class Map;
@ -473,7 +475,8 @@ public:
//JMutex mesh_mutex; //JMutex mesh_mutex;
#endif #endif
NodeMetadataList *m_node_metadata; NodeMetadataList m_node_metadata;
NodeTimerList m_node_timers;
StaticObjectList m_static_objects; StaticObjectList m_static_objects;
private: private:

@ -145,7 +145,6 @@ void ContentFeatures::reset()
diggable = true; diggable = true;
climbable = false; climbable = false;
buildable_to = false; buildable_to = false;
metadata_name = "";
liquid_type = LIQUID_NONE; liquid_type = LIQUID_NONE;
liquid_alternative_flowing = ""; liquid_alternative_flowing = "";
liquid_alternative_source = ""; liquid_alternative_source = "";
@ -194,7 +193,7 @@ void ContentFeatures::serialize(std::ostream &os)
writeU8(os, diggable); writeU8(os, diggable);
writeU8(os, climbable); writeU8(os, climbable);
writeU8(os, buildable_to); writeU8(os, buildable_to);
os<<serializeString(metadata_name); os<<serializeString(""); // legacy: used to be metadata_name
writeU8(os, liquid_type); writeU8(os, liquid_type);
os<<serializeString(liquid_alternative_flowing); os<<serializeString(liquid_alternative_flowing);
os<<serializeString(liquid_alternative_source); os<<serializeString(liquid_alternative_source);
@ -248,7 +247,7 @@ void ContentFeatures::deSerialize(std::istream &is)
diggable = readU8(is); diggable = readU8(is);
climbable = readU8(is); climbable = readU8(is);
buildable_to = readU8(is); buildable_to = readU8(is);
metadata_name = deSerializeString(is); deSerializeString(is); // legacy: used to be metadata_name
liquid_type = (enum LiquidType)readU8(is); liquid_type = (enum LiquidType)readU8(is);
liquid_alternative_flowing = deSerializeString(is); liquid_alternative_flowing = deSerializeString(is);
liquid_alternative_source = deSerializeString(is); liquid_alternative_source = deSerializeString(is);

@ -179,8 +179,6 @@ struct ContentFeatures
bool climbable; bool climbable;
// Player can build on these // Player can build on these
bool buildable_to; bool buildable_to;
// Metadata name of node (eg. "furnace")
std::string metadata_name;
// Whether the node is non-liquid, source liquid or flowing liquid // Whether the node is non-liquid, source liquid or flowing liquid
enum LiquidType liquid_type; enum LiquidType liquid_type;
// If the content is liquid, this is the flowing version of the liquid. // If the content is liquid, this is the flowing version of the liquid.

@ -19,11 +19,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodemetadata.h" #include "nodemetadata.h"
#include "utility.h" #include "utility.h"
#include "mapnode.h"
#include "exceptions.h" #include "exceptions.h"
#include "gamedef.h"
#include "inventory.h" #include "inventory.h"
#include <sstream> #include <sstream>
#include "content_mapnode.h"
#include "log.h" #include "log.h"
/* /*
@ -31,161 +30,120 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
NodeMetadata::NodeMetadata(IGameDef *gamedef): NodeMetadata::NodeMetadata(IGameDef *gamedef):
m_gamedef(gamedef) m_stringvars(),
m_inventory(new Inventory(gamedef->idef())),
m_inventorydrawspec(""),
m_formspec(""),
m_infotext(""),
m_allow_removal(true)
{ {
} }
NodeMetadata::~NodeMetadata() NodeMetadata::~NodeMetadata()
{ {
delete m_inventory;
} }
NodeMetadata* NodeMetadata::create(const std::string &name, IGameDef *gamedef) void NodeMetadata::serialize(std::ostream &os) const
{ {
// Find factory function int num_vars = m_stringvars.size();
core::map<std::string, Factory2>::Node *n; writeU32(os, num_vars);
n = m_names.find(name); for(std::map<std::string, std::string>::const_iterator
if(n == NULL) i = m_stringvars.begin(); i != m_stringvars.end(); i++){
{ os<<serializeString(i->first);
// If factory is not found, just return. os<<serializeLongString(i->second);
errorstream<<"WARNING: NodeMetadata: No factory for name=\""
<<name<<"\""<<std::endl;
return NULL;
}
// Try to load the metadata. If it fails, just return.
try
{
Factory2 f2 = n->getValue();
NodeMetadata *meta = (*f2)(gamedef);
return meta;
}
catch(SerializationError &e)
{
errorstream<<"NodeMetadata: SerializationError "
<<"while creating name=\""<<name<<"\""<<std::endl;
return NULL;
} }
m_inventory->serialize(os);
os<<serializeString(m_inventorydrawspec);
os<<serializeString(m_formspec);
os<<serializeString(m_infotext);
writeU8(os, m_allow_removal);
} }
NodeMetadata* NodeMetadata::deSerialize(std::istream &is, IGameDef *gamedef) void NodeMetadata::deSerialize(std::istream &is)
{ {
// Read id m_stringvars.clear();
u8 buf[2]; int num_vars = readU32(is);
is.read((char*)buf, 2); for(int i=0; i<num_vars; i++){
s16 id = readS16(buf); std::string name = deSerializeString(is);
std::string var = deSerializeLongString(is);
// Read data m_stringvars[name] = var;
std::string data = deSerializeString(is);
// Find factory function
core::map<u16, Factory>::Node *n;
n = m_types.find(id);
if(n == NULL)
{
// If factory is not found, just return.
infostream<<"WARNING: NodeMetadata: No factory for typeId="
<<id<<std::endl;
return NULL;
}
// Try to load the metadata. If it fails, just return.
try
{
std::istringstream iss(data, std::ios_base::binary);
Factory f = n->getValue();
NodeMetadata *meta = (*f)(iss, gamedef);
return meta;
}
catch(SerializationError &e)
{
infostream<<"WARNING: NodeMetadata: ignoring SerializationError"<<std::endl;
return NULL;
} }
m_inventory->deSerialize(is);
m_inventorydrawspec = deSerializeString(is);
m_formspec = deSerializeString(is);
m_infotext = deSerializeString(is);
m_allow_removal = readU8(is);
} }
void NodeMetadata::serialize(std::ostream &os) void NodeMetadata::clear()
{ {
u8 buf[2]; m_stringvars.clear();
writeU16(buf, typeId()); m_inventory->clear();
os.write((char*)buf, 2); m_inventorydrawspec = "";
m_formspec = "";
std::ostringstream oss(std::ios_base::binary); m_infotext = "";
serializeBody(oss); m_allow_removal = true;
os<<serializeString(oss.str());
}
void NodeMetadata::registerType(u16 id, const std::string &name, Factory f,
Factory2 f2)
{
{ // typeId
core::map<u16, Factory>::Node *n;
n = m_types.find(id);
if(!n)
m_types.insert(id, f);
}
{ // typeName
core::map<std::string, Factory2>::Node *n;
n = m_names.find(name);
if(!n)
m_names.insert(name, f2);
}
} }
/* /*
NodeMetadataList NodeMetadataList
*/ */
void NodeMetadataList::serialize(std::ostream &os) void NodeMetadataList::serialize(std::ostream &os) const
{ {
u8 buf[6]; /*
Version 0 is a placeholder for "nothing to see here; go away."
u16 version = 1; */
writeU16(buf, version);
os.write((char*)buf, 2); if(m_data.size() == 0){
writeU8(os, 0); // version
return;
}
writeU8(os, 1); // version
u16 count = m_data.size(); u16 count = m_data.size();
writeU16(buf, count); writeU16(os, count);
os.write((char*)buf, 2);
for(core::map<v3s16, NodeMetadata*>::Iterator for(std::map<v3s16, NodeMetadata*>::const_iterator
i = m_data.getIterator(); i = m_data.begin();
i.atEnd()==false; i++) i != m_data.end(); i++)
{ {
v3s16 p = i.getNode()->getKey(); v3s16 p = i->first;
NodeMetadata *data = i.getNode()->getValue(); NodeMetadata *data = i->second;
u16 p16 = p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X; u16 p16 = p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X;
writeU16(buf, p16); writeU16(os, p16);
os.write((char*)buf, 2);
data->serialize(os); data->serialize(os);
} }
} }
void NodeMetadataList::deSerialize(std::istream &is, IGameDef *gamedef) void NodeMetadataList::deSerialize(std::istream &is, IGameDef *gamedef)
{ {
m_data.clear(); m_data.clear();
u8 buf[6]; u8 version = readU8(is);
is.read((char*)buf, 2); if(version == 0){
u16 version = readU16(buf); // Nothing
return;
}
if(version > 1) if(version != 1){
{
infostream<<__FUNCTION_NAME<<": version "<<version<<" not supported" infostream<<__FUNCTION_NAME<<": version "<<version<<" not supported"
<<std::endl; <<std::endl;
throw SerializationError("NodeMetadataList::deSerialize"); throw SerializationError("NodeMetadataList::deSerialize");
} }
is.read((char*)buf, 2); u16 count = readU16(is);
u16 count = readU16(buf);
for(u16 i=0; i<count; i++) for(u16 i=0; i<count; i++)
{ {
is.read((char*)buf, 2); u16 p16 = readU16(is);
u16 p16 = readU16(buf);
v3s16 p(0,0,0); v3s16 p(0,0,0);
p.Z += p16 / MAP_BLOCKSIZE / MAP_BLOCKSIZE; p.Z += p16 / MAP_BLOCKSIZE / MAP_BLOCKSIZE;
@ -193,43 +151,33 @@ void NodeMetadataList::deSerialize(std::istream &is, IGameDef *gamedef)
p.Y += p16 / MAP_BLOCKSIZE; p.Y += p16 / MAP_BLOCKSIZE;
p16 -= p.Y * MAP_BLOCKSIZE; p16 -= p.Y * MAP_BLOCKSIZE;
p.X += p16; p.X += p16;
NodeMetadata *data = NodeMetadata::deSerialize(is, gamedef);
if(data == NULL) if(m_data.find(p) != m_data.end())
continue;
if(m_data.find(p))
{ {
infostream<<"WARNING: NodeMetadataList::deSerialize(): " infostream<<"WARNING: NodeMetadataList::deSerialize(): "
<<"already set data at position" <<"already set data at position"
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring." <<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
<<std::endl; <<std::endl;
delete data;
continue; continue;
} }
m_data.insert(p, data); NodeMetadata *data = new NodeMetadata(gamedef);
data->deSerialize(is);
m_data[p] = data;
} }
} }
NodeMetadataList::~NodeMetadataList() NodeMetadataList::~NodeMetadataList()
{ {
for(core::map<v3s16, NodeMetadata*>::Iterator clear();
i = m_data.getIterator();
i.atEnd()==false; i++)
{
delete i.getNode()->getValue();
}
} }
NodeMetadata* NodeMetadataList::get(v3s16 p) NodeMetadata* NodeMetadataList::get(v3s16 p)
{ {
core::map<v3s16, NodeMetadata*>::Node *n; std::map<v3s16, NodeMetadata*>::const_iterator n = m_data.find(p);
n = m_data.find(p); if(n == m_data.end())
if(n == NULL)
return NULL; return NULL;
return n->getValue(); return n->second;
} }
void NodeMetadataList::remove(v3s16 p) void NodeMetadataList::remove(v3s16 p)
@ -238,29 +186,23 @@ void NodeMetadataList::remove(v3s16 p)
if(olddata) if(olddata)
{ {
delete olddata; delete olddata;
m_data.remove(p); m_data.erase(p);
} }
} }
void NodeMetadataList::set(v3s16 p, NodeMetadata *d) void NodeMetadataList::set(v3s16 p, NodeMetadata *d)
{ {
remove(p); remove(p);
m_data.insert(p, d); m_data.insert(std::make_pair(p, d));
} }
bool NodeMetadataList::step(float dtime) void NodeMetadataList::clear()
{ {
bool something_changed = false; for(std::map<v3s16, NodeMetadata*>::iterator
for(core::map<v3s16, NodeMetadata*>::Iterator i = m_data.begin();
i = m_data.getIterator(); i != m_data.end(); i++)
i.atEnd()==false; i++)
{ {
v3s16 p = i.getNode()->getKey(); delete i->second;
NodeMetadata *meta = i.getNode()->getValue();
bool changed = meta->step(dtime);
if(changed)
something_changed = true;
} }
return something_changed; m_data.clear();
} }

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <map>
/* /*
NodeMetadata stores arbitary amounts of data for special blocks. NodeMetadata stores arbitary amounts of data for special blocks.
@ -39,77 +40,89 @@ class IGameDef;
class NodeMetadata class NodeMetadata
{ {
public: public:
typedef NodeMetadata* (*Factory)(std::istream&, IGameDef *gamedef);
typedef NodeMetadata* (*Factory2)(IGameDef *gamedef);
NodeMetadata(IGameDef *gamedef); NodeMetadata(IGameDef *gamedef);
virtual ~NodeMetadata(); ~NodeMetadata();
static NodeMetadata* create(const std::string &name, IGameDef *gamedef); void serialize(std::ostream &os) const;
static NodeMetadata* deSerialize(std::istream &is, IGameDef *gamedef); void deSerialize(std::istream &is);
void serialize(std::ostream &os);
virtual u16 typeId() const = 0; void clear();
virtual const char* typeName() const = 0;
virtual NodeMetadata* clone(IGameDef *gamedef) = 0;
virtual void serializeBody(std::ostream &os) = 0;
// Called on client-side; shown on screen when pointed at // Generic key/value store
virtual std::string infoText() {return "";} std::string getString(const std::string &name) const
{
std::map<std::string, std::string>::const_iterator i;
i = m_stringvars.find(name);
if(i == m_stringvars.end())
return "";
return i->second;
}
void setString(const std::string &name, const std::string &var)
{
if(var.empty())
m_stringvars.erase(name);
else
m_stringvars[name] = var;
}
// The inventory
Inventory* getInventory()
{
return m_inventory;
}
//
virtual Inventory* getInventory() {return NULL;}
// Called always after the inventory is modified, before the changes
// are copied elsewhere
virtual void inventoryModified(){}
// A step in time. Shall return true if metadata changed.
virtual bool step(float dtime) {return false;}
// Whether the related node and this metadata cannot be removed
virtual bool nodeRemovalDisabled(){return false;}
// If non-empty, player can interact by using an inventory view // If non-empty, player can interact by using an inventory view
// See format in guiInventoryMenu.cpp. // See format in guiInventoryMenu.cpp.
virtual std::string getInventoryDrawSpecString(){return "";} std::string getInventoryDrawSpec() const
{
return m_inventorydrawspec;
}
void setInventoryDrawSpec(const std::string &text)
{
m_inventorydrawspec = text;
}
// If non-empty, player can interact by using an form view
// See format in guiFormMenu.cpp.
std::string getFormSpec() const
{
return m_formspec;
}
void setFormSpec(const std::string &text)
{
m_formspec = text;
}
// Called on client-side; shown on screen when pointed at
std::string getInfoText() const
{
return m_infotext;
}
void setInfoText(const std::string &text)
{
m_infotext = text;
}
// Whether the related node and this metadata can be removed
bool getAllowRemoval() const
{
return m_allow_removal;
}
void setAllowRemoval(bool b)
{
m_allow_removal = b;
}
// If true, player can interact by writing text
virtual bool allowsTextInput(){ return false; }
// Get old text for player interaction
virtual std::string getText(){ return ""; }
// Set player-written text
virtual void setText(const std::string &t){}
// If returns non-empty, only given player can modify text/inventory
virtual std::string getOwner(){ return std::string(""); }
// The name of the player who placed the node
virtual void setOwner(std::string t){}
/* Interface for GenericNodeMetadata */
virtual void setInfoText(const std::string &text){};
virtual void setInventoryDrawSpec(const std::string &text){};
virtual void setAllowTextInput(bool b){};
virtual void setRemovalDisabled(bool b){};
virtual void setEnforceOwner(bool b){};
virtual bool isInventoryModified(){return false;};
virtual void resetInventoryModified(){};
virtual bool isTextModified(){return false;};
virtual void resetTextModified(){};
virtual void setString(const std::string &name, const std::string &var){}
virtual std::string getString(const std::string &name){return "";}
protected:
static void registerType(u16 id, const std::string &name, Factory f,
Factory2 f2);
IGameDef *m_gamedef;
private: private:
static core::map<u16, Factory> m_types; std::map<std::string, std::string> m_stringvars;
static core::map<std::string, Factory2> m_names; Inventory *m_inventory;
std::string m_inventorydrawspec;
std::string m_formspec;
std::string m_infotext;
bool m_allow_removal;
}; };
/* /*
List of metadata of all the nodes of a block List of metadata of all the nodes of a block
*/ */
@ -119,7 +132,7 @@ class NodeMetadataList
public: public:
~NodeMetadataList(); ~NodeMetadataList();
void serialize(std::ostream &os); void serialize(std::ostream &os) const;
void deSerialize(std::istream &is, IGameDef *gamedef); void deSerialize(std::istream &is, IGameDef *gamedef);
// Get pointer to data // Get pointer to data
@ -128,12 +141,11 @@ public:
void remove(v3s16 p); void remove(v3s16 p);
// Deletes old data and sets a new one // Deletes old data and sets a new one
void set(v3s16 p, NodeMetadata *d); void set(v3s16 p, NodeMetadata *d);
// Deletes all
void clear();
// A step in time. Returns true if something changed.
bool step(float dtime);
private: private:
core::map<v3s16, NodeMetadata*> m_data; std::map<v3s16, NodeMetadata*> m_data;
}; };
#endif #endif

141
src/nodetimer.cpp Normal file

@ -0,0 +1,141 @@
/*
Minetest-c55
Copyright (C) 2010-2012 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 "nodetimer.h"
#include "utility.h"
#include "log.h"
/*
NodeTimer
*/
void NodeTimer::serialize(std::ostream &os) const
{
writeF1000(os, duration);
writeF1000(os, elapsed);
}
void NodeTimer::deSerialize(std::istream &is)
{
duration = readF1000(is);
elapsed = readF1000(is);
}
/*
NodeTimerList
*/
void NodeTimerList::serialize(std::ostream &os) const
{
/*
Version 0 is a placeholder for "nothing to see here; go away."
*/
if(m_data.size() == 0){
writeU8(os, 0); // version
return;
}
writeU8(os, 1); // version
writeU16(os, m_data.size());
for(std::map<v3s16, NodeTimer>::const_iterator
i = m_data.begin();
i != m_data.end(); i++){
v3s16 p = i->first;
NodeTimer t = i->second;
u16 p16 = p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X;
writeU16(os, p16);
t.serialize(os);
}
}
void NodeTimerList::deSerialize(std::istream &is)
{
m_data.clear();
u8 version = readU8(is);
if(version == 0)
return;
if(version != 1)
throw SerializationError("unsupported NodeTimerList version");
u16 count = readU16(is);
for(u16 i=0; i<count; i++)
{
u16 p16 = readU16(is);
v3s16 p(0,0,0);
p.Z += p16 / MAP_BLOCKSIZE / MAP_BLOCKSIZE;
p16 -= p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
p.Y += p16 / MAP_BLOCKSIZE;
p16 -= p.Y * MAP_BLOCKSIZE;
p.X += p16;
NodeTimer t;
t.deSerialize(is);
if(t.duration <= 0)
{
infostream<<"WARNING: NodeTimerList::deSerialize(): "
<<"invalid data at position"
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
<<std::endl;
continue;
}
if(m_data.find(p) != m_data.end())
{
infostream<<"WARNING: NodeTimerList::deSerialize(): "
<<"already set data at position"
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
<<std::endl;
continue;
}
m_data.insert(std::make_pair(p, t));
}
}
std::map<v3s16, f32> NodeTimerList::step(float dtime)
{
std::map<v3s16, f32> elapsed_timers;
// Increment timers
for(std::map<v3s16, NodeTimer>::iterator
i = m_data.begin();
i != m_data.end(); i++){
v3s16 p = i->first;
NodeTimer t = i->second;
t.elapsed += dtime;
if(t.elapsed >= t.duration)
elapsed_timers.insert(std::make_pair(p, t.elapsed));
else
i->second = t;
}
// Delete elapsed timers
for(std::map<v3s16, f32>::const_iterator
i = elapsed_timers.begin();
i != elapsed_timers.end(); i++){
v3s16 p = i->first;
m_data.erase(p);
}
return elapsed_timers;
}

91
src/nodetimer.h Normal file

@ -0,0 +1,91 @@
/*
Minetest-c55
Copyright (C) 2010-2012 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 NODETIMER_HEADER
#define NODETIMER_HEADER
#include "irrlichttypes.h"
#include <iostream>
#include <map>
/*
NodeTimer provides per-node timed callback functionality.
Can be used for:
- Furnaces, to keep the fire burnin'
- "activated" nodes that snap back to their original state
after a fixed amount of time (mesecons buttons, for example)
*/
class NodeTimer
{
public:
NodeTimer(): duration(0.), elapsed(0.) {}
NodeTimer(f32 duration_, f32 elapsed_):
duration(duration_), elapsed(elapsed_) {}
~NodeTimer() {}
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
f32 duration;
f32 elapsed;
};
/*
List of timers of all the nodes of a block
*/
class NodeTimerList
{
public:
NodeTimerList() {}
~NodeTimerList() {}
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
// Get timer
NodeTimer get(v3s16 p){
std::map<v3s16, NodeTimer>::iterator n = m_data.find(p);
if(n == m_data.end())
return NodeTimer();
return n->second;
}
// Deletes timer
void remove(v3s16 p){
m_data.erase(p);
}
// Deletes old timer and sets a new one
void set(v3s16 p, NodeTimer t){
m_data[p] = t;
}
// Deletes all timers
void clear(){
m_data.clear();
}
// A step in time. Returns map of elapsed timers.
std::map<v3s16, f32> step(float dtime);
private:
std::map<v3s16, NodeTimer> m_data;
};
#endif

@ -1080,6 +1080,8 @@ static ContentFeatures read_content_features(lua_State *L, int index)
"deprecated: use 'drop' field"); "deprecated: use 'drop' field");
warn_if_field_exists(L, index, "extra_dug_item_rarity", warn_if_field_exists(L, index, "extra_dug_item_rarity",
"deprecated: use 'drop' field"); "deprecated: use 'drop' field");
warn_if_field_exists(L, index, "metadata_name",
"deprecated: use on_add and metadata callbacks");
// True for all ground-like things like stone and mud, false for eg. trees // True for all ground-like things like stone and mud, false for eg. trees
getboolfield(L, index, "is_ground_content", f.is_ground_content); getboolfield(L, index, "is_ground_content", f.is_ground_content);
@ -1096,8 +1098,6 @@ static ContentFeatures read_content_features(lua_State *L, int index)
getboolfield(L, index, "climbable", f.climbable); getboolfield(L, index, "climbable", f.climbable);
// Player can build on these // Player can build on these
getboolfield(L, index, "buildable_to", f.buildable_to); getboolfield(L, index, "buildable_to", f.buildable_to);
// Metadata name of node (eg. "furnace")
getstringfield(L, index, "metadata_name", f.metadata_name);
// Whether the node is non-liquid, source liquid or flowing liquid // Whether the node is non-liquid, source liquid or flowing liquid
f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype", f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
es_LiquidType, LIQUID_NONE); es_LiquidType, LIQUID_NONE);
@ -1947,22 +1947,17 @@ private:
return *(NodeMetaRef**)ud; // unbox pointer return *(NodeMetaRef**)ud; // unbox pointer
} }
static NodeMetadata* getmeta(NodeMetaRef *ref) static NodeMetadata* getmeta(NodeMetaRef *ref, bool auto_create)
{ {
NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p); NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
if(meta == NULL && auto_create)
{
meta = new NodeMetadata(ref->m_env->getGameDef());
ref->m_env->getMap().setNodeMetadata(ref->m_p, meta);
}
return meta; return meta;
} }
/*static IGenericNodeMetadata* getgenericmeta(NodeMetaRef *ref)
{
NodeMetadata *meta = getmeta(ref);
if(meta == NULL)
return NULL;
if(meta->typeId() != NODEMETA_GENERIC)
return NULL;
return (IGenericNodeMetadata*)meta;
}*/
static void reportMetadataChange(NodeMetaRef *ref) static void reportMetadataChange(NodeMetaRef *ref)
{ {
// Inform other things that the metadata has changed // Inform other things that the metadata has changed
@ -1987,106 +1982,99 @@ private:
return 0; return 0;
} }
// get_type(self) // get_string(self, name)
static int l_get_type(lua_State *L) static int l_get_string(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref); std::string name = luaL_checkstring(L, 2);
NodeMetadata *meta = getmeta(ref, false);
if(meta == NULL){ if(meta == NULL){
lua_pushnil(L); lua_pushlstring(L, "", 0);
return 1; return 1;
} }
// Do it std::string str = meta->getString(name);
lua_pushstring(L, meta->typeName()); lua_pushlstring(L, str.c_str(), str.size());
return 1; return 1;
} }
// allows_text_input(self) // set_string(self, name, var)
static int l_allows_text_input(lua_State *L) static int l_set_string(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref); std::string name = luaL_checkstring(L, 2);
if(meta == NULL) return 0; size_t len = 0;
// Do it const char *s = lua_tolstring(L, 3, &len);
lua_pushboolean(L, meta->allowsTextInput()); std::string str(s, len);
return 1;
}
// set_text(self, text) NodeMetadata *meta = getmeta(ref, !str.empty());
static int l_set_text(lua_State *L) if(meta == NULL || str == meta->getString(name))
{ return 0;
NodeMetaRef *ref = checkobject(L, 1); meta->setString(name, str);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
std::string text = luaL_checkstring(L, 2);
meta->setText(text);
reportMetadataChange(ref); reportMetadataChange(ref);
return 0; return 0;
} }
// get_text(self) // get_int(self, name)
static int l_get_text(lua_State *L) static int l_get_int(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref); std::string name = lua_tostring(L, 2);
if(meta == NULL) return 0;
// Do it
std::string text = meta->getText();
lua_pushstring(L, text.c_str());
return 1;
}
// get_owner(self) NodeMetadata *meta = getmeta(ref, false);
static int l_get_owner(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
std::string owner = meta->getOwner();
lua_pushstring(L, owner.c_str());
return 1;
}
// set_owner(self, string)
static int l_set_owner(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
std::string owner = luaL_checkstring(L, 2);
meta->setOwner(owner);
reportMetadataChange(ref);
return 1;
}
// get_allow_removal(self)
static int l_get_allow_removal(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL){ if(meta == NULL){
lua_pushboolean(L, true); lua_pushnumber(L, 0);
return 1; return 1;
} }
// Do it std::string str = meta->getString(name);
lua_pushboolean(L, !meta->nodeRemovalDisabled()); lua_pushnumber(L, stoi(str));
return 1; return 1;
} }
/* IGenericNodeMetadata interface */ // set_int(self, name, var)
static int l_set_int(lua_State *L)
// set_infotext(self, text)
static int l_set_infotext(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref); std::string name = lua_tostring(L, 2);
if(meta == NULL) return 0; int a = lua_tointeger(L, 3);
// Do it std::string str = itos(a);
std::string text = luaL_checkstring(L, 2);
meta->setInfoText(text); NodeMetadata *meta = getmeta(ref, true);
if(meta == NULL || str == meta->getString(name))
return 0;
meta->setString(name, str);
reportMetadataChange(ref);
return 0;
}
// get_float(self, name)
static int l_get_float(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
std::string name = lua_tostring(L, 2);
NodeMetadata *meta = getmeta(ref, false);
if(meta == NULL){
lua_pushnumber(L, 0);
return 1;
}
std::string str = meta->getString(name);
lua_pushnumber(L, stof(str));
return 1;
}
// set_float(self, name, var)
static int l_set_float(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
std::string name = lua_tostring(L, 2);
float a = lua_tonumber(L, 3);
std::string str = ftos(a);
NodeMetadata *meta = getmeta(ref, true);
if(meta == NULL || str == meta->getString(name))
return 0;
meta->setString(name, str);
reportMetadataChange(ref); reportMetadataChange(ref);
return 0; return 0;
} }
@ -2095,140 +2083,132 @@ private:
static int l_get_inventory(lua_State *L) static int l_get_inventory(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref); getmeta(ref, true); // try to ensure the metadata exists
if(meta == NULL) return 0;
// Do it
InvRef::createNodeMeta(L, ref->m_p); InvRef::createNodeMeta(L, ref->m_p);
return 1; return 1;
} }
// get_inventory_draw_spec(self)
static int l_get_inventory_draw_spec(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref, false);
if(meta == NULL){
lua_pushlstring(L, "", 0);
return 1;
}
std::string str = meta->getInventoryDrawSpec();
lua_pushlstring(L, str.c_str(), str.size());
return 1;
}
// set_inventory_draw_spec(self, text) // set_inventory_draw_spec(self, text)
static int l_set_inventory_draw_spec(lua_State *L) static int l_set_inventory_draw_spec(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref); size_t len = 0;
if(meta == NULL) return 0; const char *s = lua_tolstring(L, 2, &len);
// Do it std::string str(s, len);
std::string text = luaL_checkstring(L, 2);
meta->setInventoryDrawSpec(text); NodeMetadata *meta = getmeta(ref, !str.empty());
if(meta == NULL || str == meta->getInventoryDrawSpec())
return 0;
meta->setInventoryDrawSpec(str);
reportMetadataChange(ref); reportMetadataChange(ref);
return 0; return 0;
} }
// set_allow_text_input(self, text) // get_form_spec(self)
static int l_set_allow_text_input(lua_State *L) static int l_get_form_spec(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0; NodeMetadata *meta = getmeta(ref, false);
// Do it if(meta == NULL){
bool b = lua_toboolean(L, 2); lua_pushlstring(L, "", 0);
meta->setAllowTextInput(b); return 1;
}
std::string str = meta->getFormSpec();
lua_pushlstring(L, str.c_str(), str.size());
return 1;
}
// set_form_spec(self, text)
static int l_set_form_spec(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
size_t len = 0;
const char *s = lua_tolstring(L, 2, &len);
std::string str(s, len);
NodeMetadata *meta = getmeta(ref, !str.empty());
if(meta == NULL || str == meta->getFormSpec())
return 0;
meta->setFormSpec(str);
reportMetadataChange(ref); reportMetadataChange(ref);
return 0; return 0;
} }
// set_allow_removal(self, text) // get_infotext(self)
static int l_get_infotext(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref, false);
if(meta == NULL){
lua_pushlstring(L, "", 0);
return 1;
}
std::string str = meta->getInfoText();
lua_pushlstring(L, str.c_str(), str.size());
return 1;
}
// set_infotext(self, text)
static int l_set_infotext(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
size_t len = 0;
const char *s = lua_tolstring(L, 2, &len);
std::string str(s, len);
NodeMetadata *meta = getmeta(ref, !str.empty());
if(meta == NULL || str == meta->getInfoText())
return 0;
meta->setInfoText(str);
reportMetadataChange(ref);
return 0;
}
// get_allow_removal(self)
static int l_get_allow_removal(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref, false);
if(meta == NULL){
lua_pushboolean(L, true);
return 1;
}
lua_pushboolean(L, meta->getAllowRemoval());
return 1;
}
// set_allow_removal(self, flag)
static int l_set_allow_removal(lua_State *L) static int l_set_allow_removal(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref); bool flag = lua_toboolean(L, 2);
if(meta == NULL) return 0;
// Do it NodeMetadata *meta = getmeta(ref, flag != true);
bool b = lua_toboolean(L, 2); if(meta == NULL || flag == meta->getAllowRemoval())
meta->setRemovalDisabled(!b); return 0;
meta->setAllowRemoval(flag);
reportMetadataChange(ref); reportMetadataChange(ref);
return 0; return 0;
} }
// set_enforce_owner(self, text)
static int l_set_enforce_owner(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
bool b = lua_toboolean(L, 2);
meta->setEnforceOwner(b);
reportMetadataChange(ref);
return 0;
}
// is_inventory_modified(self)
static int l_is_inventory_modified(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
lua_pushboolean(L, meta->isInventoryModified());
return 1;
}
// reset_inventory_modified(self)
static int l_reset_inventory_modified(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
meta->resetInventoryModified();
reportMetadataChange(ref);
return 0;
}
// is_text_modified(self)
static int l_is_text_modified(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
lua_pushboolean(L, meta->isTextModified());
return 1;
}
// reset_text_modified(self)
static int l_reset_text_modified(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
meta->resetTextModified();
reportMetadataChange(ref);
return 0;
}
// set_string(self, name, var)
static int l_set_string(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
std::string name = luaL_checkstring(L, 2);
size_t len = 0;
const char *s = lua_tolstring(L, 3, &len);
std::string str(s, len);
meta->setString(name, str);
reportMetadataChange(ref);
return 0;
}
// get_string(self, name)
static int l_get_string(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
std::string name = luaL_checkstring(L, 2);
std::string str = meta->getString(name);
lua_pushlstring(L, str.c_str(), str.size());
return 1;
}
public: public:
NodeMetaRef(v3s16 p, ServerEnvironment *env): NodeMetaRef(v3s16 p, ServerEnvironment *env):
m_p(p), m_p(p),
@ -2281,25 +2261,21 @@ public:
}; };
const char NodeMetaRef::className[] = "NodeMetaRef"; const char NodeMetaRef::className[] = "NodeMetaRef";
const luaL_reg NodeMetaRef::methods[] = { const luaL_reg NodeMetaRef::methods[] = {
method(NodeMetaRef, get_type),
method(NodeMetaRef, allows_text_input),
method(NodeMetaRef, set_text),
method(NodeMetaRef, get_text),
method(NodeMetaRef, get_owner),
method(NodeMetaRef, set_owner),
method(NodeMetaRef, get_allow_removal),
method(NodeMetaRef, set_infotext),
method(NodeMetaRef, get_inventory),
method(NodeMetaRef, set_inventory_draw_spec),
method(NodeMetaRef, set_allow_text_input),
method(NodeMetaRef, set_allow_removal),
method(NodeMetaRef, set_enforce_owner),
method(NodeMetaRef, is_inventory_modified),
method(NodeMetaRef, reset_inventory_modified),
method(NodeMetaRef, is_text_modified),
method(NodeMetaRef, reset_text_modified),
method(NodeMetaRef, set_string),
method(NodeMetaRef, get_string), method(NodeMetaRef, get_string),
method(NodeMetaRef, set_string),
method(NodeMetaRef, get_int),
method(NodeMetaRef, set_int),
method(NodeMetaRef, get_float),
method(NodeMetaRef, set_float),
method(NodeMetaRef, get_inventory),
method(NodeMetaRef, get_inventory_draw_spec),
method(NodeMetaRef, set_inventory_draw_spec),
method(NodeMetaRef, get_form_spec),
method(NodeMetaRef, set_form_spec),
method(NodeMetaRef, get_infotext),
method(NodeMetaRef, set_infotext),
method(NodeMetaRef, get_allow_removal),
method(NodeMetaRef, set_allow_removal),
{0,0} {0,0}
}; };

@ -57,12 +57,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
19: new content type handling 19: new content type handling
20: many existing content types translated to extended ones 20: many existing content types translated to extended ones
21: dynamic content type allocation 21: dynamic content type allocation
22: full 16-bit content types, minerals removed, facedir & wallmounted changed 22: minerals removed, facedir & wallmounted changed
23: NodeTimers, new node metadata format
*/ */
// This represents an uninitialized or invalid format // This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255 #define SER_FMT_VER_INVALID 255
// Highest supported serialization version // Highest supported serialization version
#define SER_FMT_VER_HIGHEST 22 #define SER_FMT_VER_HIGHEST 23
// Lowest supported serialization version // Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0 #define SER_FMT_VER_LOWEST 0

@ -2417,47 +2417,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
} }
else if(command == TOSERVER_SIGNNODETEXT) else if(command == TOSERVER_SIGNNODETEXT)
{ {
if(!checkPriv(player->getName(), "interact")) infostream<<"Server: SIGNNODETEXT not supported anymore"
return; <<std::endl;
/* return;
u16 command
v3s16 p
u16 textlen
textdata
*/
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
u8 buf[6];
// Read stuff
is.read((char*)buf, 6);
v3s16 p = readV3S16(buf);
is.read((char*)buf, 2);
u16 textlen = readU16(buf);
std::string text;
for(u16 i=0; i<textlen; i++)
{
is.read((char*)buf, 1);
text += (char)buf[0];
}
NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
if(!meta)
return;
meta->setText(text);
actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
<<" at "<<PP(p)<<std::endl;
v3s16 blockpos = getNodeBlockPos(p);
MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
if(block)
{
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"sign node text");
}
setBlockNotSent(blockpos);
} }
else if(command == TOSERVER_INVENTORY_ACTION) else if(command == TOSERVER_INVENTORY_ACTION)
{ {
@ -2540,7 +2502,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
} }
// If player is not an admin, check for ownership of src and dst // If player is not an admin, check for ownership of src and dst
if(!checkPriv(player->getName(), "server")) /*if(!checkPriv(player->getName(), "server"))
{ {
std::string owner_from = getInventoryOwner(ma->from_inv); std::string owner_from = getInventoryOwner(ma->from_inv);
if(owner_from != "" && owner_from != player->getName()) if(owner_from != "" && owner_from != player->getName())
@ -2561,7 +2523,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
delete a; delete a;
return; return;
} }
} }*/
} }
/* /*
Handle restrictions and special cases of the drop action Handle restrictions and special cases of the drop action
@ -2581,7 +2543,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return; return;
} }
// If player is not an admin, check for ownership // If player is not an admin, check for ownership
else if(!checkPriv(player->getName(), "server")) /*else if(!checkPriv(player->getName(), "server"))
{ {
std::string owner_from = getInventoryOwner(da->from_inv); std::string owner_from = getInventoryOwner(da->from_inv);
if(owner_from != "" && owner_from != player->getName()) if(owner_from != "" && owner_from != player->getName())
@ -2592,7 +2554,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
delete a; delete a;
return; return;
} }
} }*/
} }
/* /*
Handle restrictions and special cases of the craft action Handle restrictions and special cases of the craft action
@ -2619,7 +2581,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
} }
// If player is not an admin, check for ownership of inventory // If player is not an admin, check for ownership of inventory
if(!checkPriv(player->getName(), "server")) /*if(!checkPriv(player->getName(), "server"))
{ {
std::string owner_craft = getInventoryOwner(ca->craft_inv); std::string owner_craft = getInventoryOwner(ca->craft_inv);
if(owner_craft != "" && owner_craft != player->getName()) if(owner_craft != "" && owner_craft != player->getName())
@ -2630,7 +2592,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
delete a; delete a;
return; return;
} }
} }*/
} }
// Do the action // Do the action
@ -3223,33 +3185,6 @@ Inventory* Server::getInventory(const InventoryLocation &loc)
} }
return NULL; return NULL;
} }
std::string Server::getInventoryOwner(const InventoryLocation &loc)
{
switch(loc.type){
case InventoryLocation::UNDEFINED:
{}
break;
case InventoryLocation::CURRENT_PLAYER:
{}
break;
case InventoryLocation::PLAYER:
{
return loc.name;
}
break;
case InventoryLocation::NODEMETA:
{
NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
if(!meta)
return "";
return meta->getOwner();
}
break;
default:
assert(0);
}
return "";
}
void Server::setInventoryModified(const InventoryLocation &loc) void Server::setInventoryModified(const InventoryLocation &loc)
{ {
switch(loc.type){ switch(loc.type){
@ -3272,10 +3207,6 @@ void Server::setInventoryModified(const InventoryLocation &loc)
{ {
v3s16 blockpos = getNodeBlockPos(loc.p); v3s16 blockpos = getNodeBlockPos(loc.p);
NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
if(meta)
meta->inventoryModified();
MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos); MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
if(block) if(block)
block->raiseModified(MOD_STATE_WRITE_NEEDED); block->raiseModified(MOD_STATE_WRITE_NEEDED);

@ -483,7 +483,6 @@ public:
Shall be called with the environment and the connection locked. Shall be called with the environment and the connection locked.
*/ */
Inventory* getInventory(const InventoryLocation &loc); Inventory* getInventory(const InventoryLocation &loc);
std::string getInventoryOwner(const InventoryLocation &loc);
void setInventoryModified(const InventoryLocation &loc); void setInventoryModified(const InventoryLocation &loc);
// Connection must be locked when called // Connection must be locked when called