Start a new topic
Answered

Still Struggling With Implementing IObject

I'm revisiting an old topic I started ~8 months ago on implementing the IObject interface, found here.

I was never able to get the behavior that I wanted out of an IObject, and I've been working on it again recently. The core of the issue is that using the methodology explained in that post, I was able to make a child extension under the IObject, but the child extension was invisible in the editor's Explorer panel. That makes it very difficult to actually use the child extension, which in turn makes the entire IObject itself difficult to use.

At this point, all I am trying to accomplish is this:

1) Add an IObject to a scene

2) Have that IObject automatically include an empty VHL Interface child, that can be accessed from the editor's Explorer panel

 

I feel like there's something very small that I'm missing. I am able to add a VHL interface to my object, but that interface is invisible in the Explorer. The interface does still exist, and can be exposed using a python script, but any connections made to it would need to be instantiated in code. That is not ideal, since I want to be able to use the VHL interface the same way I use any other.

 

I've tried stripping my object down to the minimum that I believed was necessary to get this baseline functionality:

 

IObjectDemo.h

 

#include <VxSim/IObject.h>
#include <VxContent\ISceneAddOn.h>
#include <VxSim\VxVHLInterface.h>

namespace IObjectDemo
{
	// Stripped-down Object class
	// Implements IObject and ISceneAddOn only
	class IObjectDemoExtension : public VxSim::IObject, public VxContent::ISceneAddOn
	{
	public:
		IObjectDemoExtension(VxSim::VxObject* proxy);
		virtual ~IObjectDemoExtension();
		virtual void onActive() override;

	protected:
		// We are intending to nest a VHL interface within this object
		VxSim::VxSmartInterface<VxSim::VxVHLInterface> mInterface;
	};
}

 

 

IObjectDemo.cpp

 

#include "IObjectDemoExtension.h"

namespace IObjectDemo
{
	// Empty constructor
	IObjectDemoExtension::IObjectDemoExtension(VxSim::VxObject* proxy) :
		VxSim::IObject(proxy),
		VxContent::ISceneAddOn() 
	{
	}

	IObjectDemoExtension::~IObjectDemoExtension()
	{
	}
	
	// Only check for nested extensions when the object becomes active
	void IObjectDemoExtension::onActive()
	{
		// Debugging logs to make sure we hit onActive when expected
		Vx::LogInfo("IObjectDemoExtension onActive!\n");
		// mInterface is declared in the header as type VxSim::VxSmartInterface<VxSim::VxVHLInterface>
		mInterface = this->getProxy()->findExtensionByName("Interface");
		// If the interface is invalid
		if (!mInterface.valid())
		{
			Vx::LogInfo("IObjectDemoExtension Interface Invalid\n");
			// Instantiate a new VHL interface
			mInterface = VxSim::VxSmartInterface<VxSim::VxVHLInterface>::create();
			// Set the name to what we search for in the start of onActive
			mInterface->setName("Interface");
			// Add the interface to the object
			add(mInterface);
		}
		// Log that the interface is otherwise valid
		else
		{
			Vx::LogInfo("IObjectDemoExtension Interface Valid\n");
		}
	}

}


I have noticed that changing line 32 in IObjectDemo.cpp from

add(mInterface)

to:

add(mInterface.create())

 

Creates some very strange behavior. If added to a scene file, the editor will not show a VHL Interface nested underneath the object in the editor's Explorer panel. However, every time the scene file is saved, closed, and re-opened, a new VHL Interface will be instantiated and be visible in the Explorer panel. If this process is repeated, the object will continue adding more VHL interfaces, but only the most recently added interface is visible. Using a python script, I have verified that all previous interfaces are still children under the object, but only the most recent one created is visible. I assume the reason new interfaces are added is because the default name for a VHL Interface is "VHLInterface", instead of "Interface". However, when I change the name I search for to "VHLInterface", this behavior disappears, and the interface is again never visible in the Explorer panel, despite existing as a child extension.

 

I know that's a confusing description, so I've attached a demonstration of this very odd behavior. In case the python code is difficult to read, these are the two lines added to pre_step:

  

    print(len(self.parameters.parameter.value.toObject().getExtensions()))
    print(self.parameters.parameter.value.toObject().getExtensions()[0].getName())

 

 

Which demonstrate that child extensions are being added, but only the most recent is displayed, and that the first child extension added is never displayed.

 

One other thing I noticed in my earlier post on this issue, and that I still believe is relevant somehow, is that my object lacks a HierarchyView extension. I know that these can be instantiated on their own, but was told previously that they are instantiated by the Editor as necessary. It feels like there's another interface I need to implement to get the Editor to implement a HierarchyView, but I haven't found anything in the documentation to back that up.

 

Is there anything I've done in this basic implementation of IObject that is clearly wrong? Is there another way to get the behavior I want, where my extension comes with a VHL Interface (or any extension, for that matter) that is accessible through the Explorer panel? 

gif

Best Answer

Hi Seth,


Good news. My colleague just put together a small test IObject which makes this work.

The issue lies with the IObject::isCompatible function which needs to return true when the internal HierarchyView extension (which our editor uses) is added to the IObject. The editor will always try that and this is automatic, but if the HierarchyView extension is rejected (by IObject::isCompatible returning false when the editor tries to add it to your IObject), then the child extensions won't show up.


So the solution seems to be as simple as always returning true in your IObject::isCompatible implementation.


Here is the code:

class ObjectTest
    : public VxSim::IObject
    , public VxSim::IDynamics
    , public VxDynamics::IMechanismAddOn
{
public:
    ObjectTest(VxSim::VxObject * proxy)
        : VxSim::IObject(proxy)
        , VxSim::IDynamics(proxy)
    {

    }

    virtual void ObjectTest::onActive() override
    {
        auto * extension = getProxy()->findExtensionByName("Interface");
        if (!extension)
        {
            auto vhlInterface = VxSim::VxSmartInterface<VxSim::VxVHLInterface>::create();
            vhlInterface->setName("Interface");
            add(vhlInterface);
        }
    }

    virtual bool ObjectTest::isCompatible(VxSim::VxExtension*) const override
    {
        return true;
    }
};

 

And here is how it looks after first creation via the toolbox. Pardon the strange extension name in the screenshot. My colleague was being funny ;).


image


Cheers,

Daniel





Hi Seth,

 

Can you try one simple thing for me, please? 

 

Instead of trying to find the extension by name, just check if you have any child extensions, and if yes, take the first one and set it as mInterface.

 

I have the feeling something doesn't work with the search by name or the setting of a name, since in your code you search for "Interface" and also give the name "Interface", but in the editor (in your gif), the name of the child VHL extension is "VHLInterface". Does the gif not match your code, or is this actually a bug you discovered?

To confirm my suspicion, please try to use this code:

void IObjectDemoExtension::onActive()
{
    if (getProxy()->getExtensionCount() > 0)
    {
        mInterface = this->getProxy()->getExtension(0);
    }
    // If the interface is invalid
    if (!mInterface.valid())
    {
        mInterface = VxSim::VxSmartInterface<VxSim::VxVHLInterface>::create();
        mInterface->setName("Interface");
        add(mInterface);
    }
}

Regarding add: I wouldn't recommend using add(mInterface.create()). add(mInterface) is the right way to go.

 

Let me know if this works.

 

Daniel

Sorry about the confusion there - this is what I meant by my explanation being confusing and poorly-worded.

The reason the interface is showing up as "VxVHLInterface" in the demonstration is because I'm calling add(mInterface.create()), which instantiates a new VHL interface with the default name for a VHL, NOT the name "Interface".

 

Using your provided code gives the same result as before - no child extension appears at all in the Explorer, but the python script still exposes the VHL interface, which is correctly named Interface. This is the same behavior when I call findExtensionByName("Interface") instead of getExtension(0). Attached is a screenshot of the behavior, where you can see that no child is visible in the Explorer, but a child clearly still exists.

 

image


Ah! I understand.

So, the code that I gave you and your old code in onActive actually works as intended. When adding your IObject it adds a child extension only if not already present (meaning, the IObject was created from the toolbox and not from loading).

Your main blocker is that the child extension does not appear in the editor.

My colleagues are currently discussing this issue and somebody will get back to you soon on the details whether or not you can make these child extensions appear with the current Vortex version. It might be possible, but we are not sure, since we use some internal facilities usually to make this happen.


Regarding the use of add(mInterface.create()): Yes, this would not add your mInterface, but it would add a new instance of the VHL Interface extension. You should not do this. That's not what you want.


1 person likes this
Answer

Hi Seth,


Good news. My colleague just put together a small test IObject which makes this work.

The issue lies with the IObject::isCompatible function which needs to return true when the internal HierarchyView extension (which our editor uses) is added to the IObject. The editor will always try that and this is automatic, but if the HierarchyView extension is rejected (by IObject::isCompatible returning false when the editor tries to add it to your IObject), then the child extensions won't show up.


So the solution seems to be as simple as always returning true in your IObject::isCompatible implementation.


Here is the code:

class ObjectTest
    : public VxSim::IObject
    , public VxSim::IDynamics
    , public VxDynamics::IMechanismAddOn
{
public:
    ObjectTest(VxSim::VxObject * proxy)
        : VxSim::IObject(proxy)
        , VxSim::IDynamics(proxy)
    {

    }

    virtual void ObjectTest::onActive() override
    {
        auto * extension = getProxy()->findExtensionByName("Interface");
        if (!extension)
        {
            auto vhlInterface = VxSim::VxSmartInterface<VxSim::VxVHLInterface>::create();
            vhlInterface->setName("Interface");
            add(vhlInterface);
        }
    }

    virtual bool ObjectTest::isCompatible(VxSim::VxExtension*) const override
    {
        return true;
    }
};

 

And here is how it looks after first creation via the toolbox. Pardon the strange extension name in the screenshot. My colleague was being funny ;).


image


Cheers,

Daniel





1 person likes this
Login to post a comment