Browse Source

pgraph: fix issues with serializing empty NodePaths

rdb 7 years ago
parent
commit
b5b77e5956
3 changed files with 39 additions and 5 deletions
  1. 1 0
      panda/src/pgraph/config_pgraph.cxx
  2. 8 1
      panda/src/pgraph/nodePath.cxx
  3. 30 4
      tests/pgraph/test_nodepath.py

+ 1 - 0
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();

+ 8 - 1
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.

+ 30 - 4
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()."""