Bug in MovableObject.UserData

Robert Isele

22-03-2006 02:49:38

Hi,
there's a bug in the property MovableObject.UserData:

public object UserData
{
get{return _userData;}
set{_userData = value;}
}
private object _userData;


If you retrieve a moveableObject with SceneNode.GetAttachedObject(i), its UserData property is 'null', even if you've assigned some value to it before. For this reason the following code won't work as expected:

entity.UserData = someObject;
sceneNode.AttachObject(entity);
Object o = sceneNode.GetAttachedObject(0).UserData;
//o == null


The root of this problem is the way GetAttachedObject works: It always returns a new instance of MovableObject, hence its userData-member is initialized with null.


public virtual MovableObject GetAttachedObject(UInt16 index)
{
IntPtr cPtr = OgreBindingsPINVOKE.SceneNode_GetAttachedObject__SWIG_0(swigCPtr, (UInt16)index);
MovableObject ret = (cPtr == IntPtr.Zero) ? null : new MovableObject(cPtr, false);
return ret;
}

Robert Isele

22-03-2006 03:07:26

i can think of the following solution:
We need to use the ogre function Ogre::MovableObject::setUserObject (UserDefinedObject * obj) to store our userdata.
Because this function only accepts objects derived from the class 'UserDefinedObject' and we want to assign an generic object, we ll need to encapsulate a reference to the actual userdata by some class derived from 'UserDefinedObject'.

I'm thinking of something like this:


class UserDataContainer : UserDefinedObject //unmanaged class
{
public:
gcroot<Object^> data; //managed handle
}

property MovableObject::UserData::set(Object^ object)
{
UserDataContainer* userData = new UserDataContainer ();
userData->data= object;
pointerToNativeMovableObject->setUserObject(userData);
}

//get property analog


Note: Unfortunately i've no idea how to implement this with Swig

rastaman

22-03-2006 23:03:32

umm what is gcroot and the "Object^" thing ?

The problem is there's no way for OgreBindings to hold a reference to managed data. If you no longer hold any references to your user data then the GC will distroy it. Plus the framework's memory manager could move the data and OgreBindings would be holding an invalid pointer.

I think the best way to do this would be to keep you own database of user objects in a System.Collections.Hashtable or your own Dictionary implementation where the key is the Ogre object's name.

If you find a good way to do it I will be happy to add it to ODN.

Robert Isele

23-03-2006 02:46:26

umm what is gcroot and the "Object^" thing ?
Sorry i didn't know that swig is using plain C++ for OgreBindings. I wrote the example in C++/CLR which is the successor of managed C++ in .Net 2.0.
All managed classes are implicitly derived from the System::Object baseclass (in C# it's mapped to the 'object' type, same as the System:Int32 type is mapped to 'int')
Basically, gcroot<BaseType> behaves like a native pointer, but encapsulates a managed handle. This is the standard way of assigning a managed object to a unmanaged pointer. See http://www.codeproject.com/managedcpp/ijw_unmanaged.asp
The problem is there's no way for OgreBindings to hold a reference to managed data
Actually, it is possible by using a gcroot<> pointer, but it would require to enable the common language runtime for OgreBindings.
If you no longer hold any references to your user data then the GC will distroy it.
Ogre::MovableObject would hold a reference to gcroot<Object^>, which itself holds a reference to the managed userdata, hence the gc won't remove it
Plus the framework's memory manager could move the data and OgreBindings would be holding an invalid pointer
Again, gcroot solves this. think of it as a "tracking" pointer

I'm pretty sure that it would work this way. I wrote many wrappers in C++/CLR, which needed interoperability between unmanaged and managed classes.
BUT:
To be honest, I'm unable to implement this with swig.
plus, after realising that Ogrebindings is using plain C++ without the Common Language Runtime i doubt my solution is the best way to do this.

Your idea about using a hashtable sounds better. :idea:
But, do we really need a UserData property?
I mean, if the user needs to associate some data to an entity he could easily create a hashtable by himself.

PS: I just began to read into swig and i'm already beginning to hate it for its inflexibility and its inability to implement polymorphism :evil: :evil: :evil: