+ return neighbors;
+}
+
+void MapNode::getNodeBoxes(const NodeDefManager *nodemgr,
+ std::vector<aabb3f> *boxes, u8 neighbors) const
+{
+ const ContentFeatures &f = nodemgr->get(*this);
+ transformNodeBox(*this, f.node_box, nodemgr, boxes, neighbors);
+}
+
+void MapNode::getCollisionBoxes(const NodeDefManager *nodemgr,
+ std::vector<aabb3f> *boxes, u8 neighbors) const
+{
+ const ContentFeatures &f = nodemgr->get(*this);
+ if (f.collision_box.fixed.empty())
+ transformNodeBox(*this, f.node_box, nodemgr, boxes, neighbors);
+ else
+ transformNodeBox(*this, f.collision_box, nodemgr, boxes, neighbors);
+}
+
+void MapNode::getSelectionBoxes(const NodeDefManager *nodemgr,
+ std::vector<aabb3f> *boxes, u8 neighbors) const
+{
+ const ContentFeatures &f = nodemgr->get(*this);
+ transformNodeBox(*this, f.selection_box, nodemgr, boxes, neighbors);
+}
+
+u8 MapNode::getMaxLevel(const NodeDefManager *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 f.leveled_max;
+ return 0;
+}
+
+u8 MapNode::getLevel(const NodeDefManager *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.param_type_2 == CPT2_LEVELED) {
+ u8 level = getParam2() & LEVELED_MASK;
+ if (level)
+ return level;
+ }
+ // Return static value from nodedef if param2 isn't used for level
+ if (f.leveled > f.leveled_max)
+ return f.leveled_max;
+ return f.leveled;
+}
+
+s8 MapNode::setLevel(const NodeDefManager *nodemgr, s16 level)
+{
+ s8 rest = 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 <= 0) { // liquid can’t exist with zero level
+ setContent(CONTENT_AIR);
+ return 0;
+ }
+ if (level >= LIQUID_LEVEL_SOURCE) {
+ rest = level - LIQUID_LEVEL_SOURCE;
+ setContent(f.liquid_alternative_source_id);
+ setParam2(0);
+ } else {
+ setContent(f.liquid_alternative_flowing_id);
+ setParam2((level & LIQUID_LEVEL_MASK) | (getParam2() & ~LIQUID_LEVEL_MASK));
+ }
+ } else if (f.param_type_2 == CPT2_LEVELED) {
+ if (level < 0) { // zero means default for a leveled nodebox
+ rest = level;
+ level = 0;
+ } else if (level > f.leveled_max) {
+ rest = level - f.leveled_max;
+ level = f.leveled_max;
+ }
+ setParam2((level & LEVELED_MASK) | (getParam2() & ~LEVELED_MASK));
+ }
+ return rest;
+}
+
+s8 MapNode::addLevel(const NodeDefManager *nodemgr, s16 add)
+{
+ s16 level = getLevel(nodemgr);
+ level += add;
+ return setLevel(nodemgr, level);