Index: trunk/nv/object.hh
===================================================================
--- trunk/nv/object.hh	(revision 57)
+++ trunk/nv/object.hh	(revision 57)
@@ -0,0 +1,166 @@
+// Copyright (C) 2012 Kornel Kisielewicz
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#ifndef NV_OBJECT_HH
+#define NV_OBJECT_HH
+
+#include <nv/common.hh>
+#include <nv/string.hh>
+#include <list>
+
+namespace nv
+{
+	class type_database;
+
+	/**
+	 * Implements a object tree-like structure.
+	 */
+	class object
+	{
+	public:
+		/**
+		 * Register the object type in the type database.
+		 */
+		static void register_type( type_database* db );
+
+		/// List type
+		typedef std::list<object*> list;
+
+		/**
+		 * Object default constructor, needed for RTTI
+		 */
+		object();
+
+		/**
+		 * Object constructor
+		 */
+		object( string aid, uid auid );
+
+		/**
+		 * Adds a child to this object. 
+		 *
+		 * The child is added to the end of the list. The child is
+		 * first detached from it's parent if present.
+		 *
+		 * @param child child to be added.
+		 */
+		virtual void add_child( object* child );
+
+
+		/**
+		 * Removes a child from this object.
+		 *
+		 * Does nothing if child not present, or is not child of
+		 * this object.
+		 *
+		 * @param child child to be removed.
+		 */
+		virtual void remove_child( object* child );
+
+		/**
+		 * Detaches object from parent.
+		 */
+		void detach(); 
+
+		/**
+		 * Moves the node to a new parent.
+		 *
+		 * Simply calls detach, and then add_child( new_parent ).
+		 *
+		 * @param new_parent the parent where we move
+		 */
+		virtual void change_parent( object* new_parent );
+
+		/**
+		 * Templated function to return parent.
+		 *
+		 * If parent doesn't exist, or is of other type nullptr will be returned.
+		 *
+		 * @tparam T requested parent type.
+		 * @returns parent as passed type, or nullptr if not present/invalid
+		 */
+		template< typename T >
+		typename T* get_parent_as() const
+		{
+			if ( !m_parent )
+			{
+				return nullptr;
+			}
+			return dynamic_cast<T>( m_parent )
+		}
+
+		/**
+		 * Destroys all children.
+		 */
+		void destroy_children();
+
+		/**
+		 * Searches for child by pointer.
+		 *
+		 * @param child child being searched
+		 * @param recursive whether to search recursively
+		 * @returns nullptr if not found, child otherwise
+		 */
+		object* find( object* child, bool recursive = false );
+
+		/**
+		 * Searches for child by uid.
+		 *
+		 * @param child uid being searched
+		 * @param recursive whether to search recursively
+		 * @returns nullptr if not found, child otherwise
+		 */
+		object* find( uid child, bool recursive = false );
+
+		/**
+		 * Searches for child by id.
+		 *
+		 * @param child id being searched
+		 * @param recursive whether to search recursively
+		 * @returns nullptr if not found, or *first* child otherwise (breadth first)
+		 */
+		object* find( string child, bool recursive = false );
+
+		/**
+		 * Returns the parent of this object.
+		 *
+		 * If no parent is present, nullptr will be returned.
+		 *
+		 * @returns parent object of current object
+		 */
+		object* get_parent() const { return m_parent; }
+
+		/**
+		 * Returns object UID
+		 */
+		uid get_uid() const { return m_uid; }
+
+		/**
+		 * Returns object UID
+		 */
+		int get_lua_index() const { return m_lua_index; }
+
+		list::iterator begin() { return m_children.begin(); }
+		list::iterator end()   { return m_children.end(); }
+
+		/**
+		 * Destructor.
+		 *
+		 * Destroys all children, unregisters the object from the uid_store.
+		 */
+		virtual ~object();
+
+	protected:
+		string  m_id;          ///< id type of the object
+		string  m_name;        ///< name of the object
+		uid     m_uid;         ///< uid of the object
+		int     m_lua_index;   ///< lua reference
+		object* m_parent;      ///< pointer to parent
+		list    m_children;    ///< children objects
+		size_t  m_child_count; ///< number of children
+	};
+
+} // namespace nv
+
+#endif // NV_OBJECT_HH
Index: trunk/nv/types.hh
===================================================================
--- trunk/nv/types.hh	(revision 56)
+++ trunk/nv/types.hh	(revision 57)
@@ -8,4 +8,5 @@
 #include <glm/glm.hpp>
 #include <nv/common.hh>
+#include <nv/object.hh>
 #include <type_traits>
 #include <utility>
@@ -14,6 +15,9 @@
 #include <string>
 
+#define NV_REGISTER_NAME( s ) template <> inline const char* nv::get_type_name<s>   () { return #s; }
+
 namespace nv
 {
+
 	enum type
 	{
@@ -95,8 +99,6 @@
     inline const char* get_type_name()
     {
-        static_assert< FALSE >( "Type not implemented!" );
+        static_assert( false, "Type not implemented!" );
     }
-
-#define NV_REGISTER_NAME( s ) template <> inline const char* nv::get_type_name<s>   () { return #s; }
 
 	template <> inline const char* get_type_name<int>   () { return "sint"; }
@@ -130,4 +132,23 @@
 
 	template <> inline const char* get_type_name<std::string> () { return "string"; }
+	template <> inline const char* get_type_name<object>      () { return "object"; }
+
+	template<typename T>
+	struct is_container
+	{
+	private:
+		typedef char                      yes;
+		typedef struct { char array[2]; } no;
+		template<typename C> static yes test(typename C::iterator*);
+		template<typename C> static no  test(...);
+	public:
+		static const bool value = sizeof(test<T>(0)) == sizeof(yes);
+	};
+
+	template<>
+	struct is_container< std::string > {
+		static const bool value = false;
+	};
+
 
 	template <typename TYPE>
@@ -170,15 +191,17 @@
 	struct type_entry;
 
+	enum type_flag
+	{
+		TF_POINTER      = 0x01, //< field is a pointer
+		TF_NOSERIALIZE  = 0x02, //< ignore during serialization
+		TF_INVISIBLE    = 0x04, //< field invisible to API
+		TF_READONLY     = 0x08, //< read only field
+		TF_SIMPLETYPE   = 0x10, //< raw binary I/O possible
+		TF_OWNED        = 0x20,
+		TF_CONTAINER    = 0x40, //< is a container
+	};
+
 	struct type_field
 	{
-		enum flags
-		{
-			FPOINTER      = 0x01, //< field is a pointer
-			FNOSERIALIZE  = 0x02, //< ignore during serialization
-			FINVISIBLE    = 0x04, //< field invisible to API
-			FREADONLY     = 0x08, //< read only field
-			FSIMPLETYPE   = 0x10, //< raw binary I/O possible
-			FOWNED        = 0x20,
-		};
 		hash_string  name;      //< name of the field
 		hash_string  type_name; //< name of the type of the field
@@ -187,6 +210,20 @@
 		size_t       offset;
 
-		template< typename TOBJECT, typename TFIELD>
-		type_field( hash_string name, TFIELD TOBJECT::*field )
+		template< typename TOBJECT, typename TFIELD >
+		type_field( hash_string name, TFIELD TOBJECT::*field, typename std::enable_if< is_container<TFIELD>::value, void* >::type = nullptr )
+			: name(name)
+			, type_name( get_type_name< std::remove_pointer<TFIELD::value_type>::type >() )
+			, type( nullptr )
+			, flags( 0 )
+			, offset( offsetof( TOBJECT, *field ) )
+			// NOTE: if offsetof behaves badly, check offset_of in common.hh
+		{
+			flags = FCONTAINER |
+				( std::is_pointer<TFIELD::value_type>::value ? FPOINTER : 0 ) |
+				( std::is_pod<TFIELD::value_type>::value ? FSIMPLETYPE : 0 );
+		}
+
+		template< typename TOBJECT, typename TFIELD >
+		type_field( hash_string name, TFIELD TOBJECT::*field, typename std::enable_if< !is_container<TFIELD>::value, void* >::type = nullptr )
 			: name(name)
 			, type_name( get_type_name< std::remove_pointer<TFIELD>::type >() )
@@ -199,4 +236,10 @@
 				( std::is_pointer<TFIELD>::value ? FPOINTER : 0 ) |
 				( std::is_pod<TFIELD>::value ? FSIMPLETYPE : 0 );
+		}
+
+		type_field& flag( unsigned int f )
+		{
+			flags |= f;
+			return *this;
 		}
 	};
Index: trunk/src/object.cc
===================================================================
--- trunk/src/object.cc	(revision 57)
+++ trunk/src/object.cc	(revision 57)
@@ -0,0 +1,150 @@
+// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/object.hh"
+
+#include "nv/types.hh"
+
+using namespace nv;
+
+object::object()
+	: m_id(), m_name(), m_uid(0), m_lua_index(-2), m_parent( nullptr ), m_children(), m_child_count(0)
+{
+//	m_uid = uid_store::get_free_uid();
+//	uid_store::register_object( this, m_uid );
+}
+
+object::object( string aid, uid auid )
+	: m_id(aid), m_name(), m_uid( auid ), m_lua_index(-2), m_parent( nullptr ), m_children(), m_child_count(0)
+{
+	//	uid_store::register_object( this, auid );
+}
+
+void object::add_child( object* child )
+{
+	if (child)
+	{
+		if (child->m_parent)
+		{
+			child->detach();
+		}
+		child->m_parent = this;
+		m_children.push_back( child );
+		m_child_count++;
+	}
+}
+
+void object::remove_child( object* child )
+{
+	if ( child->m_parent != this )
+	{
+		return; // signal error?
+	}
+	list::iterator it = std::find( m_children.begin(), m_children.end(), child );
+	if ( it != m_children.end() )
+	{
+		(*it)->m_parent = nullptr;
+		m_children.erase(it);
+	}	
+}
+
+void object::detach()
+{
+	if (m_parent)
+	{
+		m_parent->remove_child( this );
+	}
+}
+
+void object::change_parent( object* new_parent )
+{
+	if (m_parent) detach();
+	if (new_parent) new_parent->add_child( this );
+}
+
+void object::destroy_children()
+{
+	while ( !m_children.empty() )
+	{
+		delete m_children.front();
+	}
+}
+
+object::~object()
+{
+// 	if ( m_lua_index != lua::ref_none )
+// 	{
+// 		lua::state::get()->unregister_object( this );
+// 	}
+// 	uid_store::unregister_object( m_uid );
+	detach();
+	destroy_children();
+}
+
+object* object::find( object* child, bool recursive /*= false */ )
+{
+	list::iterator it = std::find( m_children.begin(), m_children.end(), child );
+	if ( it != m_children.end() )
+	{
+		return *it;
+	}
+	if ( recursive )
+	{
+		for ( object* i : m_children )
+		{
+			object* r = i->find( child, recursive );
+			if (r) return r;
+		}
+	}
+	return nullptr;
+}
+
+object* object::find( uid child, bool recursive /*= false */ )
+{
+	for ( object* i : m_children )
+	{
+		if (i->m_uid == child) return i;
+	}
+	if ( recursive )
+	{
+		for ( object* i : m_children )
+		{
+			object* r = i->find( child, recursive );
+			if (r) return r;
+		}
+	}
+	return nullptr;
+}
+
+object* object::find( string child, bool recursive /*= false */ )
+{
+	for ( object* i : m_children )
+	{
+		if (i->m_id == child) return i;
+	}
+	if ( recursive )
+	{
+		for ( object* i : m_children )
+		{
+			object* r = i->find( child, recursive );
+			if (r) return r;
+		}
+	}
+	return nullptr;
+}
+
+void object::register_type( type_database* db )
+{
+	type_field fields[] = {
+		type_field("id",          &object::m_id),
+		type_field("uid",         &object::m_uid).flag( TF_READONLY ), 
+		type_field("lua_index",   &object::m_lua_index).flag( TF_READONLY | TF_NOSERIALIZE ),
+		type_field("parent",      &object::m_parent).flag( TF_READONLY | TF_NOSERIALIZE ),
+		type_field("child_count", &object::m_child_count).flag( TF_READONLY ),
+		type_field("children"   , &object::m_children).flag( TF_READONLY ),
+	};
+	db->create_type<object>().fields(fields);
+}
