Jump to content

[SOLVED] CIGIClient to CIGIConnector migration, create component callback


photo

Recommended Posts

Hi,

Let's consider an entity loaded with CIGI.
entity_types.xml specifies node to load.
In the entity node, a group of 0..n cameras could be declared.
The idea is once the entity is loaded, the user can switch from one camera to another one.

Previously, using CIGIClient, here was the code.

int AppWorldLogic::init()
{
	[...]
	int be200_type = cigi->findEntityType("be200_aircraft");
	int be200_component_id = cigi->findComponentID(be200_type, "rotor");
	cigi->setCreateComponentCallback(Cigi::CIGI_COMPONENT_ENTITY, be200_type, be200_component_id, MakeCallback(this, &AppWorldLogic::be200_created));
	[...]
}

void AppWorldLogic::be200_created(Cigi::IComponent* component)
{
	auto cigi = (Cigi::CigiClientInterface*)Engine::get()->getPluginData(Engine::get()->findPlugin("CigiClient"));
	auto entity = cigi->getEntity(component->getInstanceID());
	//catch potentiel predefined cameras, recursive scan
	find_nodes_in_children(entity->getNode(), Node::PLAYER_DUMMY, "refPos", &m_cameras); //Vector<NodePtr> m_cameras;
}
      
int AppWorldLogic::update()
{
	[...]
	// keyboard
	if (!Console::get()->getActivity())
	{
		//scan over all potential predefined cameras
		for (int i = 0; i < m_cameras.size(); i++)
			if (App::get()->clearKeyState(48 + i) == 1)
				//smthg as getPlayer()->setWorldTransform(m_cameras[i]->getWorldTransform());
	}
	[...]
}

But trying to upgrade using  CIGIConnector, it seems harder to setup equiv create component callback.

Here is first attempt / callback available.. but seems not be right approach.

void CIGIWorldLogic::init_cigi()
{
	[...]
	int cigi_connector_index = Engine::get()->findPlugin("CIGIConnector");
	_cigi = (IG::CIGI::ConnectorInterface*)Engine::get()->getPluginData(cigi_connector_index);
	_cigi->setReceivePacketCallback(IG::CIGI::CIGI_OPCODE_ENTITY_CONTROL, MakeCallback(this, &CIGIWorldLogic::entity_control));
	_cigi->setReceivePacketCallback(IG::CIGI::CIGI_OPCODE_COMPONENT_CONTROL, MakeCallback(this, &CIGIWorldLogic::component_control));
	_cigi->setReceivePacketCallback(IG::CIGI::CIGI_OPCODE_COMPONENT_SHORT_CONTROL, MakeCallback(this, &CIGIWorldLogic::component_short_control));
	[...]
}

void CIGIWorldLogic::entity_control(IG::CIGI::ICigiEntityControl* ec)
{
	auto eId = ec->getEntityID();
	auto state = ec->getEntityState();
	auto aState = ec->getAttachState();
	auto type = ec->getEntityType();
	auto pId = ec->getParentID();
	auto typeN = ec->getTypeName();

	//catch potentiel predefined cameras
	auto entity = _ig_manager->getEntity(eId);
	//find_nodes_in_children(entity->getNode(), Node::PLAYER_DUMMY, "refPos", &_cameras); //entity->getNode() fails

	Unigine::Log::message("entity control id %i state %i attached state %i type %i parentID %i typeName %s\n", eId, state, aState, type, pId, typeN);
}

void CIGIWorldLogic::component_control(IG::CIGI::ICigiComponentControl* cc)
{
	auto cID = cc->getComponentID();
	auto iID = cc->getInstanceID();

	Unigine::Log::message("component control cID %i instanceID %i\n", cID, iID);
}

void CIGIWorldLogic::component_short_control(IG::CIGI::ICigiComponentShortControl* csc)
{
	auto cID = csc->getComponentID();
	auto iID = csc->getInstanceID();

	Unigine::Log::message("component short control cID %i instanceID %i\n", cID, iID);
}

Then I'm more looking at ComponentSystem, with node recursive scan to find potential cameras during component init.. is it correct?
Otherwise, what would be possible?

Thanks in advance.
Kind regards,
Charles

Link to comment

Hello! 
How will switching cameras work? with hotkeys on IG or with the component_control_packet  from the host? How to work the camera switching between entities?

Yes, using a component system is a good solution. You can create a c++ component with override init() and shutdown(), then add properties in nodereference.

Link to comment

Hi,

Right, it is a project that can run with keyboard or with CIGI.
In case of CIGI, we load up to now only one entity, but I'd like to consider multiple entities loaded with CIGI.
Right now the swhich between camera is made on hotkeys on IG, but will be CIGI extended.
Component system let me scan the node loaded and find the set of cameras.
Here is the entity declaration in ig_config.xml

[...]
<entity id="160" name="h160">
  <path>entities/h160/h160.node</path>
  <component id="161" name="hc">
    <property>hc</property>
    <parameter name="data1">rpm</parameter>
  </component>
</entity>
[...]

So, to detect entity creation, we have to add a component and override init().. hum, is it really the right / only way?

After that, how can I get access to parameter rpm in this case?
For example in a module dedicated to CIGI on view ctrl event cmd received?

void CIGIWorldLogic::view_control(IG::CIGI::ICigiViewControl* vc)
{
 auto e = _ig_manager->getEntity(vc->getEntityID());
 auto cs = e->getComponents(); //array seems always emtpy
 auto c = e->getComponent(161); //what is get (create)?
 if (c)
 {
  auto prop = c->getProperty();
  auto param = prop->findParameter("rpm");
  prop->setParameterInt(param, 10);
 }
}

Kind regards,
Charles
 

Link to comment
On 10/25/2019 at 6:01 PM, Lales.Charles said:

Component system let me scan the node loaded and find the set of cameras.

not exactly. you have to search yourself

On 10/25/2019 at 6:01 PM, Lales.Charles said:

After that, how can I get access to parameter rpm in this case?

lock at small example. when you send data1 or data 2 - you see it in you component update and in parameter_changed callback 

// ===================== in EntityCameraController.h =======================
#pragma once

#include <UnigineObjects.h>
#include "ComponentSystem.h"

class EntityCameraController : public ComponentBase
{
	
public:
	COMPONENT(EntityCameraController, ComponentBase);
	COMPONENT_INIT(init);
  	COMPONENT_UPDATE(update);

	PROP_NAME("EntityCameraController");
	PROP_AUTOSAVE(0);
	PROP_PARAM(Int, current_camera, 0)
	PROP_PARAM(Float, rpm, 0)

protected:
	
	void init();
  	void update();
	void parameter_changed(Unigine::PropertyPtr property, int num);
	Vector<PlayerPtr> cameras;
};


// ===================== in EntityCameraController.cpp =======================

REGISTER_COMPONENT(EntityCameraController);

void findCameras(const NodePtr & node, Vector<PlayerPtr> & players)
{
	if (!node) return;

	if (node->getType() >= Node::PLAYER_BEGIN && node->getType() <= Node::PLAYER_END)
		cameras.append(Player::cast(node));

	if (node->getType() == Node::NODE_REFERENCE)
		findCameras(NodeReference::cast(node)->getReference(), players);

	for (int i = 0 ; i < node->getNumChildren(); i++)
	{
		findCameras(node->getChild(i), players)
	}

}

void EntityCameraController::init()
{
	Log::message("init \n");
	getProperty()->addCallback(
				Property::CALLBACK_PARAMETER_CHANGED,
				MakeCallback(this,&EffectAircraftController::parameter_changed));
	
	findCameras(node, cameras);
}
void EntityCameraController::update()
{
	Log::message("udpate: rpm = %f, current camera = %d \n", rpm, current_camera);
  ///
}
void EntityCameraController::parameter_changed(PropertyPtr property, int num)
{
	AircraftEffectType type = AircraftEffectType::FIRE_ENGINE_1;
	if		(current_camera.getID() == num)	
	{
		int value = property->getParameterPtr(num)->getValueInt();
		// makesmth
		Log::message("getValue %d\n", value);
	}
	else if (rpm.getID() == num)
	{
		float value =  property->getParameterPtr(num)->getValueFloat();
		// makesmth

		Log::message("getValue %f\n", value);
	}
}


// ================== in ig_config.xml ====================

<entity id="160" name="h160">
  <path>entities/h160/h160.node</path>
  <component id="161" name="hc">
    <property>EntityCameraController</property>
    <node>path/to/node/in/noderef</node>
    <parameter name="data1">current_camera</parameter>
    <parameter name="data2">rpm</parameter>
  </component>
</entity>

there may be minor errors in this code, but I hope this example helps you understand how the c ++ components and the cigi component work.


 

On 10/25/2019 at 6:01 PM, Lales.Charles said:

For example in a module dedicated to CIGI on view ctrl event cmd received?

it is not known exactly, because view_control_packet and component_control_packet can come in any order.

Link to comment

Hi,

In fact the entity that can be loaded with CIGI has a node dummy containing a collection of playerdummy or cameras.
These are in fact simply ref positions to set the current camera (free, CIGI or VR) on demand (keys, CIGI cmd, VR controller button).

So, I'm not sure it is entity responsibility to proceed, and I would more implement camera management at WordLogic for example.
It can be on update with keys analyze, or as event handler on CIGI cmd received.

In this piece of code (out of any component), I would try to get currently active / selected / attached entity, get its cameras (or ref positions, that I can get on init from component), and reset position of current camera.

Is it consistent and a bit more clear?
If it's not right approach, feel free to suggest proper one ;)

Kind regards;
Charles

Link to comment

perhaps you can help create a singleton "camera controller", which will list all the cameras in the scene.

in the camera component, you can follow several parameters of the "node" type
- free camera position
- Cigi camera position
- position of the VR camera
in which you specify nodes with cameras.

when the component is initialized, it registers its cameras with the controller. By calling the IG :: IManager :: findEntity (node) method, you can find out which entity this camera is from.
when a component is removed, it informs the controller that its cameras are no longer active.

Thus, you will always know which cameras on which entity exist.

 

class CameraController
{
	static CameraController::get(){//...//}

	enum CamType
	{
		FREE,
		CIGI,
		VR
	};

	Map<int64_t, CameraComponent *> cameras;

	void registrate(int64_t entity_id, CameraComponent * component)	{ cameras[entity_id] = component; }

	void deregistrate(int64_t entity_id) 
	{ 
		cameras.remove(entity_id); 
		// may be checked as needed, that current camera is not removed
	}

	bool setCamera(int64_t entity_id, CamType type)
	{
      	// here you know about all cameras in all entityes
		if (cameras.contains(entity_id))
		{
			PlayerPtr cam;
			if (type == CamType::FREE)
				cam = cameras[entity_id].getFree();
			else if (type == CamType::CIGI)
				cam = cameras[entity_id].getCigi();
			else if (type == CamType::VR)
				cam = cameras[entity_id].getVR();

			if (cam)
			{
				Game::get()->setPlayer(cam);
              	// or just return this camera? what you need
				return true;
			}
		}
		return false;

		// or only 
		// Game::get()->getPlayer()->setWorldTransform(cam->getWorldTransform());
		// if its not Player

	}
}


class EntityCamera : public ComponentBase
{
	
public:
	COMPONENT(EntityCamera, ComponentBase);
	COMPONENT_INIT(init);
  	COMPONENT_SHUTDOWN(shutdown);

	PROP_NAME("EntityCamera");
	PROP_AUTOSAVE(0);
	PROP_PARAM(Node, free); // need specify in Editor 
	PROP_PARAM(Node, cigi);
	PROP_PARAM(Node, VR);

	PlayerPtr getFree()
	{
		PlayerPtr ret = Player::cast(free.get());
		if (ret) return ret;
		Log::error("free camera not found\n");
		return Game::get()->getPlayer();
	}
	PlayerPtr getCigi()
	{
		PlayerPtr ret = Player::cast(cigi.get());
		if (ret) return ret;
		Log::error("cigi camera not found\n");
		return Game::get()->getPlayer();
	}
	PlayerPtr getFree()
	{
		PlayerPtr ret = Player::cast(VR.get());
		if (ret) return ret;
		Log::error("VR camera not found\n");
		return Game::get()->getPlayer();
	}


private:
	
	int64_t entity_id = -1;

	void init()
	{
		IEntity * entity = IGManager::get()->findEntity(node->getRootNode()); // find entity id
		if (!entity) return;
		entity_id = entity->getID();
		CameraController::get()->registrate(entity_id, this); // register self
	}

  	void shutdown()
  	{
  		CameraController::get()->deregistrate(entity_id); // deregister self
  	}
};


/// anywhere in your code

int64_t entity_id = 123; // any way detect active camera? 
CameraController::get->setCamera(entity_id, CamType::CIGI); // switches to the CIGI camera  of entity 123

 

Link to comment

Hi,

Thanks, making some progress but not done yet.

In component, registration is fine.

void HCComponent::init()
{
	Log::message("HC init %s\n", node->getName());
	Util::find_nodes_in_children(node, Node::PLAYER_DUMMY, "refPos", &_cameras);
	CameraController::get()->registrate(node->getID(), this);
}

.. but after that, I have issue retrieving consistent ID in other modules, e.g. CIGI one.
In current test, I add 2 entities in CIGIHE, then from view panel ask to attach camera position to second entity.

void CIGIWorldLogic::view_control(IG::CIGI::ICigiViewControl* vc)
{
	if (vc->getEntityID() > 0) //only to react when attach on second entity
	{
		auto e = _ig_manager->getEntity(vc->getEntityID());
		auto n = e->getNode(); //crash here
		CameraController::get()->setCamera(n->getID(), CameraController::CamType::CIGI);
	}
}

What am I missing?

Kind regards,
Charles

Link to comment

look again at the code that I sent

	void init()
	{
		IEntity * entity = IGManager::get()->findEntity(node->getRootNode()); // find entity id
		if (!entity) return;
		entity_id = entity->getID();
		CameraController::get()->registrate(entity_id, this); // register self
	}

it shows how to get entity_id

Link to comment

Hi,

Ok, init updated but as follow, because I'm trying to separate IG and ComponentSystem, in the way that for example without CIGI but just loading a world, the logic is available.

void HCComponent::init()
{
	Log::message("HC init %s\n", node->getName());
	Util::find_nodes_in_children(node, Node::PLAYER_DUMMY, "refPos", &_cameras);
	CameraController::get()->registrate(node->getRootNode()->getID(), this);
}

But the issue / crash occurs in CIGI following code

void CIGIWorldLogic::view_control(IG::CIGI::ICigiViewControl* vc)
{
	if (vc->getEntityID() > 0)
	{
		IG::IEntity* e = _ig_manager->getEntity(vc->getEntityID());
		NodePtr n = e->getNode(); //c++ access location violation execution
		NodePtr nR = e->getNode()->getRootNode();
		volatile auto id = e->getNode()->getRootNode()->getID();

		CameraController::get()->setCamera(/*n->getID()*/id, CameraController::CamType::CIGI);
	}
}

On break point inspecting IG::IEntity* e I can see there is a node not null.

Kind regards,
Charles

Link to comment
13 hours ago, Lales.Charles said:

But the issue / crash occurs in CIGI following code
On break point inspecting IG::IEntity* e I can see there is a node not null.

this is strange. there can be no mistake in this place.
Can you send a more detailed description of the error?

Link to comment

Sure, I'll try but guess src sharing will be required / more efficient at one moment..

Here is entity inspection

image.png.71b3c22847f21af16d283aa6e8eb6a7c.png

Here is the error

image.png.fc4d990850874d7393a20214ba997869.png

And here the call stack

image.png.530f52e0527e5f7ab7c801d304f83dad.png

Important maybe: we are using extensively plugin system to encapsulate your plugin with any overlay required from our specific needs.
For example, CIGIConnector can be run directly up to the point we need additional logic.
So, instead mixing all features in one big project, we split in multiple plugins loadable or not for final exec.

Here is an overview, feel free to comment:

image.png.74b807699b71c2fa4b2e0068c7ce9fad.png

Kind regards,
Charles

Link to comment

why VS debugger show "e" as IViewBase?  Its look like something compilation error. 

please make sure, that IGInterface.h and IG_double_x64d.dll match one version from sdk. (UnigineSDK\sdks\-you_version-2.9.0.2\utils\project\template\ig)

Link to comment
  • silent changed the title to [SOLVED] CIGIClient to CIGIConnector migration, create component callback
×
×
  • Create New...