diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index e969dee72f..5729e22067 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -492,6 +492,7 @@ init_libpgraph() { ModelNode::register_with_read_factory(); ModelRoot::register_with_read_factory(); PandaNode::register_with_read_factory(); + ParamNodePath::register_with_read_factory(); PlaneNode::register_with_read_factory(); PolylightNode::register_with_read_factory(); PortalNode::register_with_read_factory(); diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 1832e18e5a..8732168212 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -5691,7 +5691,9 @@ encode_to_bam_stream(vector_uchar &data, BamWriter *writer) const { // Tell the BamWriter which node is the root node, for making NodePaths // relative to when writing them out to the file. - writer->set_root_node(node()); + if (!is_empty()) { + writer->set_root_node(node()); + } // Write an initial Datagram to represent the error type and number of // nodes. @@ -6698,6 +6700,11 @@ r_replace_material(PandaNode *node, Material *mat, */ void NodePath:: write_datagram(BamWriter *manager, Datagram &dg) const { + if (is_empty()) { + manager->write_pointer(dg, nullptr); + return; + } + PandaNode *root = DCAST(PandaNode, manager->get_root_node()); // We have no root node to measure from. diff --git a/tests/pgraph/test_nodepath.py b/tests/pgraph/test_nodepath.py index 1b98da32d7..19a40021ca 100644 --- a/tests/pgraph/test_nodepath.py +++ b/tests/pgraph/test_nodepath.py @@ -2,13 +2,39 @@ import pytest, sys def test_nodepath_empty(): """Tests NodePath behavior for empty NodePaths.""" + from panda3d.core import NodePath, ParamNodePath + import pickle + + empty = NodePath() + assert empty.is_empty() + assert not empty + + # Try pickling, which uses __reduce__ + dumped = pickle.dumps(empty) + empty2 = pickle.loads(dumped) + assert empty2.is_empty() + assert not empty2 + assert empty == empty2 + + # Test write_datagram/fillin, which are invoked when the NodePath is being + # serialized indirectly, such as via ParamNodePath + dumped = pickle.dumps(ParamNodePath(empty)) + empty2 = pickle.loads(dumped).get_value() + assert empty2.is_empty() + assert not empty2 + assert empty == empty2 + +def test_nodepath_single(): + """Tests NodePath behavior for single-node NodePaths.""" from panda3d.core import NodePath - empty = NodePath('np') + np = NodePath('np') + assert not np.is_empty() + assert np - assert empty.get_pos() == (0, 0, 0) - assert empty.get_hpr() == (0, 0, 0) - assert empty.get_scale() == (1, 1, 1) + assert np.get_pos() == (0, 0, 0) + assert np.get_hpr() == (0, 0, 0) + assert np.get_scale() == (1, 1, 1) def test_nodepath_parent(): """Tests NodePath.reparentTo()."""