+ size_t boxes_size = boxes.size();
+ boxes_size += nodebox.fixed.size();
+ if (neighbors & 1)
+ boxes_size += nodebox.connect_top.size();
+ else
+ boxes_size += nodebox.disconnected_top.size();
+
+ if (neighbors & 2)
+ boxes_size += nodebox.connect_bottom.size();
+ else
+ boxes_size += nodebox.disconnected_bottom.size();
+
+ if (neighbors & 4)
+ boxes_size += nodebox.connect_front.size();
+ else
+ boxes_size += nodebox.disconnected_front.size();
+
+ if (neighbors & 8)
+ boxes_size += nodebox.connect_left.size();
+ else
+ boxes_size += nodebox.disconnected_left.size();
+
+ if (neighbors & 16)
+ boxes_size += nodebox.connect_back.size();
+ else
+ boxes_size += nodebox.disconnected_back.size();
+
+ if (neighbors & 32)
+ boxes_size += nodebox.connect_right.size();
+ else
+ boxes_size += nodebox.disconnected_right.size();
+
+ if (neighbors == 0)
+ boxes_size += nodebox.disconnected.size();
+
+ if (neighbors < 4)
+ boxes_size += nodebox.disconnected_sides.size();
+
+ boxes.reserve(boxes_size);
+
+#define BOXESPUSHBACK(c) \
+ for (std::vector<aabb3f>::const_iterator \
+ it = (c).begin(); \
+ it != (c).end(); ++it) \
+ (boxes).push_back(*it);
+
+ BOXESPUSHBACK(nodebox.fixed);
+
+ if (neighbors & 1) {
+ BOXESPUSHBACK(nodebox.connect_top);
+ } else {
+ BOXESPUSHBACK(nodebox.disconnected_top);
+ }
+
+ if (neighbors & 2) {
+ BOXESPUSHBACK(nodebox.connect_bottom);
+ } else {
+ BOXESPUSHBACK(nodebox.disconnected_bottom);
+ }
+
+ if (neighbors & 4) {
+ BOXESPUSHBACK(nodebox.connect_front);
+ } else {
+ BOXESPUSHBACK(nodebox.disconnected_front);
+ }
+
+ if (neighbors & 8) {
+ BOXESPUSHBACK(nodebox.connect_left);
+ } else {
+ BOXESPUSHBACK(nodebox.disconnected_left);
+ }
+
+ if (neighbors & 16) {
+ BOXESPUSHBACK(nodebox.connect_back);
+ } else {
+ BOXESPUSHBACK(nodebox.disconnected_back);
+ }
+
+ if (neighbors & 32) {
+ BOXESPUSHBACK(nodebox.connect_right);
+ } else {
+ BOXESPUSHBACK(nodebox.disconnected_right);
+ }
+
+ if (neighbors == 0) {
+ BOXESPUSHBACK(nodebox.disconnected);
+ }
+
+ if (neighbors < 4) {
+ BOXESPUSHBACK(nodebox.disconnected_sides);
+ }
+
+ }
+ else // NODEBOX_REGULAR
+ {
+ boxes.emplace_back(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
+ }
+}
+
+static inline void getNeighborConnectingFace(
+ const v3s16 &p, const NodeDefManager *nodedef,
+ Map *map, MapNode n, u8 bitmask, u8 *neighbors)
+{
+ MapNode n2 = map->getNodeNoEx(p);
+ if (nodedef->nodeboxConnects(n, n2, bitmask))
+ *neighbors |= bitmask;
+}
+
+u8 MapNode::getNeighbors(v3s16 p, Map *map)
+{
+ const NodeDefManager *nodedef = map->getNodeDefManager();
+ u8 neighbors = 0;
+ const ContentFeatures &f = nodedef->get(*this);
+ // locate possible neighboring nodes to connect to
+ if (f.drawtype == NDT_NODEBOX && f.node_box.type == NODEBOX_CONNECTED) {
+ v3s16 p2 = p;
+
+ p2.Y++;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 1, &neighbors);
+
+ p2 = p;
+ p2.Y--;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 2, &neighbors);
+
+ p2 = p;
+ p2.Z--;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 4, &neighbors);
+
+ p2 = p;
+ p2.X--;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 8, &neighbors);
+
+ p2 = p;
+ p2.Z++;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 16, &neighbors);
+
+ p2 = p;
+ p2.X++;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 32, &neighbors);
+ }
+
+ return neighbors;
+}
+
+void MapNode::getNodeBoxes(const NodeDefManager *nodemgr,
+ std::vector<aabb3f> *boxes, u8 neighbors)
+{
+ 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 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 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 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.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