summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lua_api.txt16
-rw-r--r--src/collision.cpp40
-rw-r--r--src/content_mapblock.cpp41
-rw-r--r--src/game.cpp7
-rw-r--r--src/localplayer.cpp3
-rw-r--r--src/mapnode.cpp65
-rw-r--r--src/mapnode.h6
-rw-r--r--src/network/networkprotocol.h1
-rw-r--r--src/nodedef.cpp136
-rw-r--r--src/nodedef.h13
-rw-r--r--src/script/common/c_content.cpp56
-rw-r--r--src/script/cpp_api/s_node.cpp1
-rw-r--r--src/server.cpp3
13 files changed, 335 insertions, 53 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index e2ab65ddc..f51c950c3 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -617,6 +617,18 @@ A nodebox is defined as any of:
wall_bottom = box,
wall_side = box
}
+ {
+ -- A node that has optional boxes depending on neighbouring nodes'
+ -- presence and type. See also `connects_to`.
+ type = "connected",
+ fixed = box OR {box1, box2, ...}
+ connect_top = box OR {box1, box2, ...}
+ connect_bottom = box OR {box1, box2, ...}
+ connect_front = box OR {box1, box2, ...}
+ connect_left = box OR {box1, box2, ...}
+ connect_back = box OR {box1, box2, ...}
+ connect_right = box OR {box1, box2, ...}
+ }
A `box` is defined as:
@@ -3461,6 +3473,10 @@ Definition tables
light_source = 0, -- Amount of light emitted by node
damage_per_second = 0, -- If player is inside node, this damage is caused
node_box = {type="regular"}, -- See "Node boxes"
+ connects_to = nodenames, --[[
+ * Used for nodebox nodes with the type == "connected"
+ * Specifies to what neighboring nodes connections will be drawn
+ * e.g. `{"group:fence", "default:wood"}` or `"default:stone"` ]]
mesh = "model",
selection_box = {type="regular"}, -- See "Node boxes" --[[
^ If drawtype "nodebox" is used and selection_box is nil, then node_box is used. ]]
diff --git a/src/collision.cpp b/src/collision.cpp
index d847f6297..a3979f1dc 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -185,6 +185,13 @@ bool wouldCollideWithCeiling(
return false;
}
+static inline void getNeighborConnectingFace(v3s16 p, INodeDefManager *nodedef,
+ Map *map, MapNode n, int v, int *neighbors)
+{
+ MapNode n2 = map->getNodeNoEx(p);
+ if (nodedef->nodeboxConnects(n, n2))
+ *neighbors |= v;
+}
collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
f32 pos_max_d, const aabb3f &box_0,
@@ -261,12 +268,41 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
// Object collides into walkable nodes
any_position_valid = true;
- const ContentFeatures &f = gamedef->getNodeDefManager()->get(n);
+ INodeDefManager *nodedef = gamedef->getNodeDefManager();
+ const ContentFeatures &f = nodedef->get(n);
if(f.walkable == false)
continue;
int n_bouncy_value = itemgroup_get(f.groups, "bouncy");
- std::vector<aabb3f> nodeboxes = n.getCollisionBoxes(gamedef->ndef());
+ int neighbors = 0;
+ if (f.drawtype == NDT_NODEBOX && f.node_box.type == NODEBOX_CONNECTED) {
+ v3s16 p2 = p;
+
+ p2.Y++;
+ getNeighborConnectingFace(p2, nodedef, map, n, 1, &neighbors);
+
+ p2 = p;
+ p2.Y--;
+ getNeighborConnectingFace(p2, nodedef, map, n, 2, &neighbors);
+
+ p2 = p;
+ p2.Z--;
+ getNeighborConnectingFace(p2, nodedef, map, n, 4, &neighbors);
+
+ p2 = p;
+ p2.X--;
+ getNeighborConnectingFace(p2, nodedef, map, n, 8, &neighbors);
+
+ p2 = p;
+ p2.Z++;
+ getNeighborConnectingFace(p2, nodedef, map, n, 16, &neighbors);
+
+ p2 = p;
+ p2.X++;
+ getNeighborConnectingFace(p2, nodedef, map, n, 32, &neighbors);
+ }
+ std::vector<aabb3f> nodeboxes;
+ n.getCollisionBoxes(gamedef->ndef(), &nodeboxes, neighbors);
for(std::vector<aabb3f>::iterator
i = nodeboxes.begin();
i != nodeboxes.end(); ++i)
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index c15b9c424..c2934f26a 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -163,6 +163,14 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
}
}
+static inline void getNeighborConnectingFace(v3s16 p, INodeDefManager *nodedef,
+ MeshMakeData *data, MapNode n, int v, int *neighbors)
+{
+ MapNode n2 = data->m_vmanip.getNodeNoEx(p);
+ if (nodedef->nodeboxConnects(n, n2))
+ *neighbors |= v;
+}
+
/*
TODO: Fix alpha blending for special nodes
Currently only the last element rendered is blended correct
@@ -1501,7 +1509,38 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
v3f pos = intToFloat(p, BS);
- std::vector<aabb3f> boxes = n.getNodeBoxes(nodedef);
+ int neighbors = 0;
+
+ // locate possible neighboring nodes to connect to
+ if (f.node_box.type == NODEBOX_CONNECTED) {
+ v3s16 p2 = p;
+
+ p2.Y++;
+ getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 1, &neighbors);
+
+ p2 = p;
+ p2.Y--;
+ getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 2, &neighbors);
+
+ p2 = p;
+ p2.Z--;
+ getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 4, &neighbors);
+
+ p2 = p;
+ p2.X--;
+ getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 8, &neighbors);
+
+ p2 = p;
+ p2.Z++;
+ getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 16, &neighbors);
+
+ p2 = p;
+ p2.X++;
+ getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 32, &neighbors);
+ }
+
+ std::vector<aabb3f> boxes;
+ n.getNodeBoxes(nodedef, &boxes, neighbors);
for(std::vector<aabb3f>::iterator
i = boxes.begin();
i != boxes.end(); ++i)
diff --git a/src/game.cpp b/src/game.cpp
index c6125dd43..be4c46bc3 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -358,7 +358,9 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
if (!isPointableNode(n, client, liquids_pointable)) {
continue;
}
- std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
+
+ std::vector<aabb3f> boxes;
+ n.getSelectionBoxes(nodedef, &boxes);
v3s16 np(x, y, z);
v3f npf = intToFloat(np, BS);
@@ -389,7 +391,8 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
f32 d = 0.001 * BS;
MapNode n = map.getNodeNoEx(pointed_pos);
v3f npf = intToFloat(pointed_pos, BS);
- std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
+ std::vector<aabb3f> boxes;
+ n.getSelectionBoxes(nodedef, &boxes);
f32 face_min_distance = 1000 * BS;
for (std::vector<aabb3f>::const_iterator
i = boxes.begin();
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 524c6272e..0c94582aa 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -310,7 +310,8 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
if (sneak_node_found) {
f32 cb_max = 0;
MapNode n = map->getNodeNoEx(m_sneak_node);
- std::vector<aabb3f> nodeboxes = n.getCollisionBoxes(nodemgr);
+ std::vector<aabb3f> nodeboxes;
+ n.getCollisionBoxes(nodemgr, &nodeboxes);
for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
it != nodeboxes.end(); ++it) {
aabb3f box = *it;
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 671e949f1..a54658873 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -214,12 +214,12 @@ void MapNode::rotateAlongYAxis(INodeDefManager *nodemgr, Rotation rot)
}
}
-static std::vector<aabb3f> transformNodeBox(const MapNode &n,
- const NodeBox &nodebox, INodeDefManager *nodemgr)
+void transformNodeBox(const MapNode &n, const NodeBox &nodebox,
+ INodeDefManager *nodemgr, std::vector<aabb3f> *p_boxes, u8 neighbors = 0)
{
- std::vector<aabb3f> boxes;
- if(nodebox.type == NODEBOX_FIXED || nodebox.type == NODEBOX_LEVELED)
- {
+ std::vector<aabb3f> &boxes = *p_boxes;
+
+ if (nodebox.type == NODEBOX_FIXED || nodebox.type == NODEBOX_LEVELED) {
const std::vector<aabb3f> &fixed = nodebox.fixed;
int facedir = n.getFaceDir(nodemgr);
u8 axisdir = facedir>>2;
@@ -395,32 +395,71 @@ static std::vector<aabb3f> transformNodeBox(const MapNode &n,
boxes.push_back(box);
}
}
+ else if (nodebox.type == NODEBOX_CONNECTED)
+ {
+ size_t boxes_size = boxes.size();
+ boxes_size += nodebox.fixed.size();
+ if (neighbors & 1)
+ boxes_size += nodebox.connect_top.size();
+ if (neighbors & 2)
+ boxes_size += nodebox.connect_bottom.size();
+ if (neighbors & 4)
+ boxes_size += nodebox.connect_front.size();
+ if (neighbors & 8)
+ boxes_size += nodebox.connect_left.size();
+ if (neighbors & 16)
+ boxes_size += nodebox.connect_back.size();
+ if (neighbors & 32)
+ boxes_size += nodebox.connect_right.size();
+ boxes.reserve(boxes_size);
+
+#define BOXESPUSHBACK(c) do { \
+ for (std::vector<aabb3f>::const_iterator \
+ it = (c).begin(); \
+ it != (c).end(); ++it) \
+ (boxes).push_back(*it); \
+ } while (0)
+
+ BOXESPUSHBACK(nodebox.fixed);
+
+ if (neighbors & 1)
+ BOXESPUSHBACK(nodebox.connect_top);
+ if (neighbors & 2)
+ BOXESPUSHBACK(nodebox.connect_bottom);
+ if (neighbors & 4)
+ BOXESPUSHBACK(nodebox.connect_front);
+ if (neighbors & 8)
+ BOXESPUSHBACK(nodebox.connect_left);
+ if (neighbors & 16)
+ BOXESPUSHBACK(nodebox.connect_back);
+ if (neighbors & 32)
+ BOXESPUSHBACK(nodebox.connect_right);
+ }
else // NODEBOX_REGULAR
{
boxes.push_back(aabb3f(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2));
}
- return boxes;
}
-std::vector<aabb3f> MapNode::getNodeBoxes(INodeDefManager *nodemgr) const
+void MapNode::getNodeBoxes(INodeDefManager *nodemgr, std::vector<aabb3f> *boxes, u8 neighbors)
{
const ContentFeatures &f = nodemgr->get(*this);
- return transformNodeBox(*this, f.node_box, nodemgr);
+ transformNodeBox(*this, f.node_box, nodemgr, boxes, neighbors);
}
-std::vector<aabb3f> MapNode::getCollisionBoxes(INodeDefManager *nodemgr) const
+void MapNode::getCollisionBoxes(INodeDefManager *nodemgr, std::vector<aabb3f> *boxes, u8 neighbors)
{
const ContentFeatures &f = nodemgr->get(*this);
if (f.collision_box.fixed.empty())
- return transformNodeBox(*this, f.node_box, nodemgr);
+ transformNodeBox(*this, f.node_box, nodemgr, boxes, neighbors);
else
- return transformNodeBox(*this, f.collision_box, nodemgr);
+ transformNodeBox(*this, f.collision_box, nodemgr, boxes, neighbors);
}
-std::vector<aabb3f> MapNode::getSelectionBoxes(INodeDefManager *nodemgr) const
+void MapNode::getSelectionBoxes(INodeDefManager *nodemgr, std::vector<aabb3f> *boxes)
{
const ContentFeatures &f = nodemgr->get(*this);
- return transformNodeBox(*this, f.selection_box, nodemgr);
+ transformNodeBox(*this, f.selection_box, nodemgr, boxes);
}
u8 MapNode::getMaxLevel(INodeDefManager *nodemgr) const
diff --git a/src/mapnode.h b/src/mapnode.h
index 7cc25c60c..4db888616 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -240,17 +240,17 @@ struct MapNode
/*
Gets list of node boxes (used for rendering (NDT_NODEBOX))
*/
- std::vector<aabb3f> getNodeBoxes(INodeDefManager *nodemgr) const;
+ void getNodeBoxes(INodeDefManager *nodemgr, std::vector<aabb3f> *boxes, u8 neighbors = 0);
/*
Gets list of selection boxes
*/
- std::vector<aabb3f> getSelectionBoxes(INodeDefManager *nodemgr) const;
+ void getSelectionBoxes(INodeDefManager *nodemg, std::vector<aabb3f> *boxes);
/*
Gets list of collision boxes
*/
- std::vector<aabb3f> getCollisionBoxes(INodeDefManager *nodemgr) const;
+ void getCollisionBoxes(INodeDefManager *nodemgr, std::vector<aabb3f> *boxes, u8 neighbors = 0);
/*
Liquid helpers
diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h
index dc15326d9..7cde6d764 100644
--- a/src/network/networkprotocol.h
+++ b/src/network/networkprotocol.h
@@ -135,6 +135,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
PROTOCOL_VERSION 27:
backface_culling: backwards compatibility for playing with
newer client on pre-27 servers.
+ Add nodedef v3 - connected nodeboxes
*/
#define LATEST_PROTOCOL_VERSION 27
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index ba9b4abf2..85cd848ae 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "exceptions.h"
#include "debug.h"
#include "gamedef.h"
+#include "mapnode.h"
#include <fstream> // Used in applyTextureOverrides()
/*
@@ -48,44 +49,91 @@ void NodeBox::reset()
wall_top = aabb3f(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2);
wall_bottom = aabb3f(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2);
wall_side = aabb3f(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2);
+ // no default for other parts
+ connect_top.clear();
+ connect_bottom.clear();
+ connect_front.clear();
+ connect_left.clear();
+ connect_back.clear();
+ connect_right.clear();
}
void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
{
- int version = protocol_version >= 21 ? 2 : 1;
+ int version = 1;
+ if (protocol_version >= 27)
+ version = 3;
+ else if (protocol_version >= 21)
+ version = 2;
writeU8(os, version);
- if (version == 1 && type == NODEBOX_LEVELED)
- writeU8(os, NODEBOX_FIXED);
- else
- writeU8(os, type);
+ switch (type) {
+ case NODEBOX_LEVELED:
+ case NODEBOX_FIXED:
+ if (version == 1)
+ writeU8(os, NODEBOX_FIXED);
+ else
+ writeU8(os, type);
- if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED)
- {
writeU16(os, fixed.size());
- for(std::vector<aabb3f>::const_iterator
+ for (std::vector<aabb3f>::const_iterator
i = fixed.begin();
i != fixed.end(); ++i)
{
writeV3F1000(os, i->MinEdge);
writeV3F1000(os, i->MaxEdge);
}
- }
- else if(type == NODEBOX_WALLMOUNTED)
- {
+ break;
+ case NODEBOX_WALLMOUNTED:
+ writeU8(os, type);
+
writeV3F1000(os, wall_top.MinEdge);
writeV3F1000(os, wall_top.MaxEdge);
writeV3F1000(os, wall_bottom.MinEdge);
writeV3F1000(os, wall_bottom.MaxEdge);
writeV3F1000(os, wall_side.MinEdge);
writeV3F1000(os, wall_side.MaxEdge);
+ break;
+ case NODEBOX_CONNECTED:
+ if (version <= 2) {
+ // send old clients nodes that can't be walked through
+ // to prevent abuse
+ writeU8(os, NODEBOX_FIXED);
+
+ writeU16(os, 1);
+ writeV3F1000(os, v3f(-BS/2, -BS/2, -BS/2));
+ writeV3F1000(os, v3f(BS/2, BS/2, BS/2));
+ } else {
+ writeU8(os, type);
+
+#define WRITEBOX(box) do { \
+ writeU16(os, (box).size()); \
+ for (std::vector<aabb3f>::const_iterator \
+ i = (box).begin(); \
+ i != (box).end(); ++i) { \
+ writeV3F1000(os, i->MinEdge); \
+ writeV3F1000(os, i->MaxEdge); \
+ }; } while (0)
+
+ WRITEBOX(fixed);
+ WRITEBOX(connect_top);
+ WRITEBOX(connect_bottom);
+ WRITEBOX(connect_front);
+ WRITEBOX(connect_left);
+ WRITEBOX(connect_back);
+ WRITEBOX(connect_right);
+ }
+ break;
+ default:
+ writeU8(os, type);
+ break;
}
}
void NodeBox::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version < 1 || version > 2)
+ if (version < 1 || version > 3)
throw SerializationError("unsupported NodeBox version");
reset();
@@ -112,6 +160,26 @@ void NodeBox::deSerialize(std::istream &is)
wall_side.MinEdge = readV3F1000(is);
wall_side.MaxEdge = readV3F1000(is);
}
+ else if (type == NODEBOX_CONNECTED)
+ {
+#define READBOXES(box) do { \
+ count = readU16(is); \
+ (box).reserve(count); \
+ while (count--) { \
+ v3f min = readV3F1000(is); \
+ v3f max = readV3F1000(is); \
+ (box).push_back(aabb3f(min, max)); }; } while (0)
+
+ u16 count;
+
+ READBOXES(fixed);
+ READBOXES(connect_top);
+ READBOXES(connect_bottom);
+ READBOXES(connect_front);
+ READBOXES(connect_left);
+ READBOXES(connect_back);
+ READBOXES(connect_right);
+ }
}
/*
@@ -261,6 +329,8 @@ void ContentFeatures::reset()
sound_footstep = SimpleSoundSpec();
sound_dig = SimpleSoundSpec("__group");
sound_dug = SimpleSoundSpec();
+ connects_to.clear();
+ connects_to_ids.clear();
}
void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
@@ -328,6 +398,10 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
os<<serializeString(mesh);
collision_box.serialize(os, protocol_version);
writeU8(os, floodable);
+ writeU16(os, connects_to_ids.size());
+ for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
+ i != connects_to_ids.end(); ++i)
+ writeU16(os, *i);
}
void ContentFeatures::deSerialize(std::istream &is)
@@ -402,6 +476,9 @@ void ContentFeatures::deSerialize(std::istream &is)
mesh = deSerializeString(is);
collision_box.deSerialize(is);
floodable = readU8(is);
+ u16 connects_to_size = readU16(is);
+ for (u16 i = 0; i < connects_to_size; i++)
+ connects_to_ids.insert(readU16(is));
}catch(SerializationError &e) {};
}
@@ -439,6 +516,8 @@ public:
virtual bool cancelNodeResolveCallback(NodeResolver *nr);
virtual void runNodeResolveCallbacks();
virtual void resetNodeResolveState();
+ virtual void mapNodeboxConnections();
+ virtual bool nodeboxConnects(MapNode from, MapNode to);
private:
void addNameIdMapping(content_t i, std::string name);
@@ -1438,6 +1517,39 @@ void CNodeDefManager::resetNodeResolveState()
m_pending_resolve_callbacks.clear();
}
+void CNodeDefManager::mapNodeboxConnections()
+{
+ for (u32 i = 0; i < m_content_features.size(); i++) {
+ ContentFeatures *f = &m_content_features[i];
+ if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
+ continue;
+ for (std::vector<std::string>::iterator it = f->connects_to.begin();
+ it != f->connects_to.end(); ++it) {
+ getIds(*it, f->connects_to_ids);
+ }
+ }
+}
+
+bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to)
+{
+ const ContentFeatures &f1 = get(from);
+
+ if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
+ return false;
+
+ // lookup target in connected set
+ if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
+ return false;
+
+ const ContentFeatures &f2 = get(to);
+
+ if ((f2.drawtype == NDT_NODEBOX) && (f1.node_box.type == NODEBOX_CONNECTED))
+ // ignores actually looking if back connection exists
+ return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
+
+ // the target is just a regular node, so connect no matter back connection
+ return true;
+}
////
//// NodeResolver
diff --git a/src/nodedef.h b/src/nodedef.h
index bf2c7bc72..f92a3a941 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -80,6 +80,7 @@ enum NodeBoxType
NODEBOX_FIXED, // Static separately defined box(es)
NODEBOX_WALLMOUNTED, // Box for wall mounted nodes; (top, bottom, side)
NODEBOX_LEVELED, // Same as fixed, but with dynamic height from param2. for snow, ...
+ NODEBOX_CONNECTED, // optionally draws nodeboxes if a neighbor node attaches
};
struct NodeBox
@@ -92,6 +93,13 @@ struct NodeBox
aabb3f wall_top;
aabb3f wall_bottom;
aabb3f wall_side; // being at the -X side
+ // NODEBOX_CONNECTED
+ std::vector<aabb3f> connect_top;
+ std::vector<aabb3f> connect_bottom;
+ std::vector<aabb3f> connect_front;
+ std::vector<aabb3f> connect_left;
+ std::vector<aabb3f> connect_back;
+ std::vector<aabb3f> connect_right;
NodeBox()
{ reset(); }
@@ -269,6 +277,9 @@ struct ContentFeatures
SimpleSoundSpec sound_dig;
SimpleSoundSpec sound_dug;
+ std::vector<std::string> connects_to;
+ std::set<content_t> connects_to_ids;
+
/*
Methods
*/
@@ -314,6 +325,7 @@ public:
virtual void pendNodeResolve(NodeResolver *nr)=0;
virtual bool cancelNodeResolveCallback(NodeResolver *nr)=0;
+ virtual bool nodeboxConnects(const MapNode from, const MapNode to)=0;
};
class IWritableNodeDefManager : public INodeDefManager {
@@ -368,6 +380,7 @@ public:
virtual bool cancelNodeResolveCallback(NodeResolver *nr)=0;
virtual void runNodeResolveCallbacks()=0;
virtual void resetNodeResolveState()=0;
+ virtual void mapNodeboxConnections()=0;
};
IWritableNodeDefManager *createNodeDefManager();
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 96fb78d99..ababf0718 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -535,6 +535,18 @@ ContentFeatures read_content_features(lua_State *L, int index)
f.node_box = read_nodebox(L, -1);
lua_pop(L, 1);
+ lua_getfield(L, index, "connects_to");
+ if (lua_istable(L, -1)) {
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, table) != 0) {
+ // Value at -1
+ f.connects_to.push_back(lua_tostring(L, -1));
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+
lua_getfield(L, index, "selection_box");
if(lua_istable(L, -1))
f.selection_box = read_nodebox(L, -1);
@@ -627,25 +639,31 @@ NodeBox read_nodebox(lua_State *L, int index)
nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
- lua_getfield(L, index, "fixed");
- if(lua_istable(L, -1))
- nodebox.fixed = read_aabb3f_vector(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "wall_top");
- if(lua_istable(L, -1))
- nodebox.wall_top = read_aabb3f(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "wall_bottom");
- if(lua_istable(L, -1))
- nodebox.wall_bottom = read_aabb3f(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "wall_side");
- if(lua_istable(L, -1))
- nodebox.wall_side = read_aabb3f(L, -1, BS);
- lua_pop(L, 1);
+#define NODEBOXREAD(n, s) \
+ do { \
+ lua_getfield(L, index, (s)); \
+ if (lua_istable(L, -1)) \
+ (n) = read_aabb3f(L, -1, BS); \
+ lua_pop(L, 1); \
+ } while (0)
+
+#define NODEBOXREADVEC(n, s) \
+ do { \
+ lua_getfield(L, index, (s)); \
+ if (lua_istable(L, -1)) \
+ (n) = read_aabb3f_vector(L, -1, BS); \
+ lua_pop(L, 1); \
+ } while (0)
+ NODEBOXREADVEC(nodebox.fixed, "fixed");
+ NODEBOXREAD(nodebox.wall_top, "wall_top");
+ NODEBOXREAD(nodebox.wall_bottom, "wall_bottom");
+ NODEBOXREAD(nodebox.wall_side, "wall_side");
+ NODEBOXREADVEC(nodebox.connect_top, "connect_top");
+ NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom");
+ NODEBOXREADVEC(nodebox.connect_front, "connect_front");
+ NODEBOXREADVEC(nodebox.connect_left, "connect_left");
+ NODEBOXREADVEC(nodebox.connect_back, "connect_back");
+ NODEBOXREADVEC(nodebox.connect_right, "connect_right");
}
return nodebox;
}
diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp
index a905f843d..17f0f0dac 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -82,6 +82,7 @@ struct EnumString ScriptApiNode::es_NodeBoxType[] =
{NODEBOX_FIXED, "fixed"},
{NODEBOX_WALLMOUNTED, "wallmounted"},
{NODEBOX_LEVELED, "leveled"},
+ {NODEBOX_CONNECTED, "connected"},
{0, NULL},
};
diff --git a/src/server.cpp b/src/server.cpp
index 2fa8c4cf8..6c008a2a1 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -320,6 +320,9 @@ Server::Server(
// Perform pending node name resolutions
m_nodedef->runNodeResolveCallbacks();
+ // unmap node names for connected nodeboxes
+ m_nodedef->mapNodeboxConnections();
+
// init the recipe hashes to speed up crafting
m_craftdef->initHashes(this);