From e67bbcf22f2290fd8e2afd009c23568f59534dcb Mon Sep 17 00:00:00 2001
From: LogicDragon <nathanvnbg@gmail.com>
Date: Sat, 2 Jul 2011 13:39:43 -0700
Subject: [PATCH] Fixed EnumerateObjects to write the correct block order

---
 src/niflib.cpp | 86 ++++++++++++++++++++++++++++----------------------
 1 file changed, 49 insertions(+), 37 deletions(-)

diff --git a/src/niflib.cpp b/src/niflib.cpp
index ed6393ad..680ce248 100644
--- a/src/niflib.cpp
+++ b/src/niflib.cpp
@@ -31,8 +31,7 @@ All rights reserved.  Please see niflib.h for license. */
 #include "../include/obj/NiMultiTargetTransformController.h"
 #include "../include/obj/NiStringExtraData.h"
 #include "../include/obj/NiExtraData.h"
-#include "../include/obj/bhkRigidBody.h"
-#include "../include/obj/bhkCollisionObject.h"
+#include "../include/obj/bhkConstraint.h"
 #include "../include/gen/Header.h"
 #include "../include/gen/Footer.h"
 
@@ -43,7 +42,8 @@ bool g_objects_registered = false;
 void RegisterObjects();
 
 //Utility Functions
-void EnumerateObjects( NiObject * root, map<Type*,unsigned int> & type_map, map<NiObjectRef, unsigned int> & link_map, bool reverse = false );
+bool BlockChildBeforeParent( NiObject * root );
+void EnumerateObjects( NiObject * root, map<Type*,unsigned int> & type_map, map<NiObjectRef, unsigned int> & link_map );
 NiObjectRef FindRoot( vector<NiObjectRef> const & objects );
 NiObjectRef GetObjectByType( NiObject * root, const Type & type );
 
@@ -577,50 +577,62 @@ void WriteNifTree( ostream & out, NiObject * root, const NifInfo & info ) {
    WriteNifTree( out, roots, info );
 }
 
-void EnumerateObjects( NiObject * root, map<Type*,unsigned int> & type_map, map<NiObjectRef, unsigned int> & link_map, bool reverse ) {
-	//Ensure that this object has not already been visited
+// Determine whether block comes before its parent or not, depending on the block type.
+// return: 'True' if child should come first, 'False' otherwise.
+bool BlockChildBeforeParent( NiObject * root ) {
+	Type *t = (Type*)&(root->GetType());
+	return (t->IsDerivedType(bhkRefObject::TYPE) && !t->IsDerivedType(bhkConstraint::TYPE));
+}
+
+// This is a helper function for write to set up the list of all blocks,
+// the block index map, and the block type map.
+void EnumerateObjects( NiObject * root, map<Type*,unsigned int> & type_map, map<NiObjectRef, unsigned int> & link_map ) {
+	// Ensure that this object has not already been visited
 	if ( link_map.find( root ) != link_map.end() ) {
 		//This object has already been visited.  Return.
 		return;
 	}
 
-	//Add this object type to the map if it isn't there already
-	if ( type_map.find( (Type*)&(root->GetType()) ) == type_map.end() ) {
-		//The type has not yet been registered, so register it
-		unsigned int n = type_map.size();
-		type_map[ (Type*)&(root->GetType()) ] = n;
+	list<NiObjectRef> links = root->GetRefs();
+	Type *t = (Type*)&(root->GetType());
+
+	// special case: add bhkConstraint entities before bhkConstraint
+	// (these are actually links, not refs)
+	if ( t->IsDerivedType(bhkConstraint::TYPE) ) {
+		vector< bhkEntity * > entities = ((bhkConstraint *)root)->GetEntities();
+		for ( vector< bhkEntity * >::iterator it = entities.begin(); it != entities.end(); ++it ) {
+			if ( *it != NULL ) {
+				EnumerateObjects( (NiObject*)(*it), type_map, link_map );
+			}
+		}
 	}
 
-   // Oblivion has very rigid requirements about object ordering and the bhkRigidBody 
-   //   must be after its children. Hopefully this can be removed and replaced with 
-   //   a more generic mechanism in the future.
-	Type *t = (Type*)&(root->GetType());
-   if (  reverse
-      || t->IsDerivedType(bhkRigidBody::TYPE) 
-      || t->IsDerivedType(bhkCollisionObject::TYPE)
-      )
-   {
-      reverse = true;
-   }
+	// Call this function on all links of this object
+	// add children that come before the block
+	for ( list<NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it ) {
+		if ( *it != NULL && BlockChildBeforeParent(*it) ) {
+			EnumerateObjects( *it, type_map, link_map );
+		}
+	}
 
-   // If reverse is set then add the link after children otherwise add it before
-   if (!reverse) {
-      unsigned int n = link_map.size();
-      link_map[root] = n;
-   }
+	// Add this object type to the map if it isn't there already
+	// TODO: add support for NiDataStreams
+	if ( type_map.find(t) == type_map.end() ) {
+		//The type has not yet been registered, so register it
+		unsigned int n = type_map.size();
+		type_map[t] = n;
+	}
 
-   //Call this function on all links of this object	
-   list<NiObjectRef> links = root->GetRefs();
-   for ( list<NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it ) {
-      if ( *it != NULL ) {
-         EnumerateObjects( *it, type_map, link_map, reverse );
-      }
-   }
+	// add the block
+	unsigned int n = link_map.size();
+	link_map[root] = n;
 
-   if (reverse) {
-      unsigned int n = link_map.size();
-      link_map[root] = n;
-   }
+	// add children that come after the block
+	for ( list<NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it ) {
+		if ( *it != NULL && !BlockChildBeforeParent(*it) ) {
+			EnumerateObjects( *it, type_map, link_map );
+		}
+	}
 }
 
 //TODO: Should this be returning an object of a derived type too?
-- 
GitLab