+std::vector<aabb3f> MapNode::getSelectionBoxes(INodeDefManager *nodemgr) const
+{
+ const ContentFeatures &f = nodemgr->get(*this);
+ return transformNodeBox(*this, f.selection_box, nodemgr);
+}
+
+u8 MapNode::getMaxLevel(INodeDefManager *nodemgr) const
+{
+ const ContentFeatures &f = nodemgr->get(*this);
+ // todo: after update in all games leave only if (f.param_type_2 ==
+ if( f.liquid_type == LIQUID_FLOWING || f.param_type_2 == CPT2_FLOWINGLIQUID)
+ return LIQUID_LEVEL_MAX;
+ if(f.leveled || f.param_type_2 == CPT2_LEVELED)
+ return LEVELED_MAX;
+ return 0;
+}
+
+u8 MapNode::getLevel(INodeDefManager *nodemgr) const
+{
+ const ContentFeatures &f = nodemgr->get(*this);
+ // todo: after update in all games leave only if (f.param_type_2 ==
+ if(f.liquid_type == LIQUID_SOURCE)
+ return LIQUID_LEVEL_SOURCE;
+ if (f.param_type_2 == CPT2_FLOWINGLIQUID)
+ return getParam2() & LIQUID_LEVEL_MASK;
+ if(f.liquid_type == LIQUID_FLOWING) // can remove if all param_type_2 setted
+ return getParam2() & LIQUID_LEVEL_MASK;
+ if(f.leveled || f.param_type_2 == CPT2_LEVELED) {
+ u8 level = getParam2() & LEVELED_MASK;
+ if(level)
+ return level;
+ if(f.leveled > LEVELED_MAX)
+ return LEVELED_MAX;
+ return f.leveled; //default
+ }
+ return 0;
+}
+
+u8 MapNode::setLevel(INodeDefManager *nodemgr, s8 level)
+{
+ u8 rest = 0;
+ if (level < 1) {
+ setContent(CONTENT_AIR);
+ return 0;
+ }
+ const ContentFeatures &f = nodemgr->get(*this);
+ if (f.param_type_2 == CPT2_FLOWINGLIQUID
+ || f.liquid_type == LIQUID_FLOWING
+ || f.liquid_type == LIQUID_SOURCE) {
+ if (level >= LIQUID_LEVEL_SOURCE) {
+ rest = level - LIQUID_LEVEL_SOURCE;
+ setContent(nodemgr->getId(f.liquid_alternative_source));
+ } else {
+ setContent(nodemgr->getId(f.liquid_alternative_flowing));
+ setParam2(level & LIQUID_LEVEL_MASK);
+ }
+ } else if (f.leveled || f.param_type_2 == CPT2_LEVELED) {
+ if (level > LEVELED_MAX) {
+ rest = level - LEVELED_MAX;
+ level = LEVELED_MAX;
+ }
+ setParam2(level & LEVELED_MASK);
+ }
+ return rest;
+}
+
+u8 MapNode::addLevel(INodeDefManager *nodemgr, s8 add)
+{
+ s8 level = getLevel(nodemgr);
+ if (add == 0) level = 1;
+ level += add;
+ return setLevel(nodemgr, level);
+}
+
+void MapNode::freezeMelt(INodeDefManager *ndef) {
+ u8 level_was_max = this->getMaxLevel(ndef);
+ u8 level_was = this->getLevel(ndef);
+ this->setContent(ndef->getId(ndef->get(*this).freezemelt));
+ u8 level_now_max = this->getMaxLevel(ndef);
+ if (level_was_max && level_was_max != level_now_max) {
+ u8 want = (float)level_now_max / level_was_max * level_was;
+ if (!want)
+ want = 1;
+ if (want != level_was)
+ this->setLevel(ndef, want);
+ //errorstream<<"was="<<(int)level_was<<"/"<<(int)level_was_max<<" nowm="<<(int)want<<"/"<<(int)level_now_max<< " => "<<(int)this->getLevel(ndef)<< std::endl;
+ }
+ if (this->getMaxLevel(ndef) && !this->getLevel(ndef))
+ this->addLevel(ndef);
+}
+
+u32 MapNode::serializedLength(u8 version)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapNode format not supported");
+
+ if(version == 0)
+ return 1;
+ else if(version <= 9)
+ return 2;
+ else if(version <= 23)
+ return 3;
+ else
+ return 4;
+}
+void MapNode::serialize(u8 *dest, u8 version)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapNode format not supported");