Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow nodes to specify which sides to connect to.
NDT_CONNECTED attempts to connect to any side of nodes that it can
connect to, which is troublesome for FACEDIR type nodes that generally
may only have one usable face, and can be rotated.

We introduce a node parameter `connect_sides` that is valid for
any node type. If specified, it lists faces of the node (in "top",
"bottom", "front", "left", "back", "right", form, as array) that
connecting nodeboxes can connect to. "front" corresponds to the south
facing side of a node with facedir = 0.

If the node is rotatable using *simple* FACEDIR, then the attached
face is properly rotated before checking. This allows e.g. a chest
to be attached to only from the rear side.
  • Loading branch information
sofar authored and ShadowNinja committed Mar 12, 2016
1 parent e737b1c commit 37b4f0d
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 5 deletions.
2 changes: 2 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -3477,6 +3477,8 @@ Definition tables
* 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"` ]]
connect_sides = { "top", "bottom", "front", "left", "back", "right" }, --[[
^ Tells connected nodebox nodes to connect only to these sides of this node. ]]
mesh = "model",
selection_box = {type="regular"}, -- See "Node boxes" --[[
^ If drawtype "nodebox" is used and selection_box is nil, then node_box is used. ]]
Expand Down
2 changes: 1 addition & 1 deletion src/collision.cpp
Expand Up @@ -189,7 +189,7 @@ 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))
if (nodedef->nodeboxConnects(n, n2, v))
*neighbors |= v;
}

Expand Down
2 changes: 1 addition & 1 deletion src/content_mapblock.cpp
Expand Up @@ -167,7 +167,7 @@ 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))
if (nodedef->nodeboxConnects(n, n2, v))
*neighbors |= v;
}

Expand Down
25 changes: 23 additions & 2 deletions src/nodedef.cpp
Expand Up @@ -331,6 +331,7 @@ void ContentFeatures::reset()
sound_dug = SimpleSoundSpec();
connects_to.clear();
connects_to_ids.clear();
connect_sides = 0;
}

void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
Expand Down Expand Up @@ -402,6 +403,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
i != connects_to_ids.end(); ++i)
writeU16(os, *i);
writeU8(os, connect_sides);
}

void ContentFeatures::deSerialize(std::istream &is)
Expand Down Expand Up @@ -479,6 +481,7 @@ void ContentFeatures::deSerialize(std::istream &is)
u16 connects_to_size = readU16(is);
for (u16 i = 0; i < connects_to_size; i++)
connects_to_ids.insert(readU16(is));
connect_sides = readU8(is);
}catch(SerializationError &e) {};
}

Expand Down Expand Up @@ -517,7 +520,7 @@ class CNodeDefManager: public IWritableNodeDefManager {
virtual void runNodeResolveCallbacks();
virtual void resetNodeResolveState();
virtual void mapNodeboxConnections();
virtual bool nodeboxConnects(MapNode from, MapNode to);
virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);

private:
void addNameIdMapping(content_t i, std::string name);
Expand Down Expand Up @@ -1530,7 +1533,7 @@ void CNodeDefManager::mapNodeboxConnections()
}
}

bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to)
bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
{
const ContentFeatures &f1 = get(from);

Expand All @@ -1547,6 +1550,24 @@ bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to)
// ignores actually looking if back connection exists
return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());

// does to node declare usable faces?
if (f2.connect_sides > 0) {
if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) {
static const u8 rot[33 * 4] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back
8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32, 16, 8, 4 // 32 - left
};
return (f2.connect_sides & rot[(connect_face * 4) + to.param2]);
}
return (f2.connect_sides & connect_face);
}
// the target is just a regular node, so connect no matter back connection
return true;
}
Expand Down
4 changes: 3 additions & 1 deletion src/nodedef.h
Expand Up @@ -271,6 +271,8 @@ struct ContentFeatures
bool legacy_facedir_simple;
// Set to true if wall_mounted used to be set to true
bool legacy_wallmounted;
// for NDT_CONNECTED pairing
u8 connect_sides;

// Sound properties
SimpleSoundSpec sound_footstep;
Expand Down Expand Up @@ -325,7 +327,7 @@ class INodeDefManager {

virtual void pendNodeResolve(NodeResolver *nr)=0;
virtual bool cancelNodeResolveCallback(NodeResolver *nr)=0;
virtual bool nodeboxConnects(const MapNode from, const MapNode to)=0;
virtual bool nodeboxConnects(const MapNode from, const MapNode to, u8 connect_face)=0;
};

class IWritableNodeDefManager : public INodeDefManager {
Expand Down
28 changes: 28 additions & 0 deletions src/script/common/c_content.cpp
Expand Up @@ -547,6 +547,34 @@ ContentFeatures read_content_features(lua_State *L, int index)
}
lua_pop(L, 1);

lua_getfield(L, index, "connect_sides");
if (lua_istable(L, -1)) {
int table = lua_gettop(L);
lua_pushnil(L);
while (lua_next(L, table) != 0) {
// Value at -1
std::string side(lua_tostring(L, -1));
// Note faces are flipped to make checking easier
if (side == "top")
f.connect_sides |= 2;
else if (side == "bottom")
f.connect_sides |= 1;
else if (side == "front")
f.connect_sides |= 16;
else if (side == "left")
f.connect_sides |= 32;
else if (side == "back")
f.connect_sides |= 4;
else if (side == "right")
f.connect_sides |= 8;
else
warningstream << "Unknown value for \"connect_sides\": "
<< side << std::endl;
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);
Expand Down

5 comments on commit 37b4f0d

@HybridDog
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching stations are just connecting to the cable if it's below it.
How can you make "foo:hasconnecting" connect to "foo:allsideenter" from all sides but to "foo:justbottomopen" just from below it?

@ShadowNinja
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HybridDog: Set connect_sides = {"bottom"} on foo:justbottomoopen and leave foo:allsidesenter at the default of all sides.

@HybridDog
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, l thought connect_sides is part of the nodedef of the connected nodebox node and defines to which side it adds connections, which is actually done by omitting nodeboxes to those sides.

@HybridDog
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l just noticed that the selection box isn't set to the nodebox:
screenshot_20160320_101448

@ShadowNinja
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.