#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Eris/IGRouter.h>
#include <Eris/Avatar.h>
#include <Eris/Connection.h>
#include <Eris/View.h>
#include <Eris/Entity.h>
#include <Eris/LogStream.h>
#include <Eris/TypeService.h>
#include <Eris/TypeInfo.h>
#include <Eris/TypeBoundRedispatch.h>
#include <Eris/Operations.h>
#include <Atlas/Objects/Operation.h>
#include <Atlas/Objects/Entity.h>
using namespace Atlas::Objects::Operation;
using Atlas::Objects::Root;
using Atlas::Objects::Entity::RootEntity;
using Atlas::Objects::smart_dynamic_cast;
namespace Eris {
IGRouter::IGRouter(Avatar* av) :
m_avatar(av),
m_view(av->getView())
{
m_avatar->getConnection()->registerRouterForTo(this, m_avatar->getId());
m_actionType = m_avatar->getConnection()->getTypeService()->getTypeByName("action");
}
IGRouter::~IGRouter()
{
m_avatar->getConnection()->unregisterRouterForTo(this, m_avatar->getId());
}
#pragma mark -
Router::RouterResult IGRouter::handleOperation(const RootOperation& op)
{
if (!op->isDefaultSeconds()) {
// grab out world time
m_avatar->updateWorldTime(op->getSeconds());
}
const std::vector<Root>& args = op->getArgs();
if (op->getClassNo() == SIGHT_NO) {
assert(!args.empty());
if (args.front()->instanceOf(ROOT_OPERATION_NO)) return handleSightOp(op);
// initial sight of entities
RootEntity gent = smart_dynamic_cast<RootEntity>(args.front());
if (gent.isValid()) {
// View needs a bound TypeInfo for the entity
TypeInfo* ty = m_avatar->getConnection()->getTypeService()->getTypeForAtlas(gent);
if (!ty->isBound()) {
new TypeBoundRedispatch(m_avatar->getConnection(), op, ty);
return WILL_REDISPATCH;
}
m_view->sight(gent);
return HANDLED;
}
}
if (op->getClassNo() == APPEARANCE_NO) {
for (unsigned int A=0; A < args.size(); ++A) {
float stamp = -1;
if (args[A]->hasAttr("stamp")) {
stamp = args[A]->getAttr("stamp").asFloat();
}
m_view->appear(args[A]->getId(), stamp);
}
return HANDLED;
}
if (op->getClassNo() == DISAPPEARANCE_NO) {
for (unsigned int A=0; A < args.size(); ++A) {
m_view->disappear(args[A]->getId());
}
return HANDLED;
}
if (op->getClassNo() == UNSEEN_NO)
{
m_view->unseen(args.front()->getId());
return HANDLED;
}
return IGNORED;
}
Router::RouterResult IGRouter::handleSightOp(const RootOperation& sightOp)
{
RootOperation op = smart_dynamic_cast<RootOperation>(sightOp->getArgs().front());
const std::vector<Root>& args = op->getArgs();
if (op->getClassNo() == CREATE_NO) {
assert(!args.empty());
RootEntity gent = smart_dynamic_cast<RootEntity>(args.front());
if (gent.isValid()) {
// View needs a bound TypeInfo for the entity
TypeInfo* ty = m_avatar->getConnection()->getTypeService()->getTypeForAtlas(gent);
if (!ty->isBound()) {
new TypeBoundRedispatch(m_avatar->getConnection(), sightOp, ty);
return WILL_REDISPATCH;
}
m_view->create(gent);
return HANDLED;
}
}
if (op->getClassNo() == DELETE_NO) {
assert(!args.empty());
m_view->deleteEntity(args.front()->getId());
return HANDLED;
}
// becuase a SET op can potentially (legally) update multiple entities,
// we decode it here, not in the entity router
if (op->getClassNo() == SET_NO) {
for (unsigned int A=0; A < args.size(); ++A) {
Entity* ent = m_view->getEntity(args[A]->getId());
if (!ent) {
if (m_view->isPending(args[A]->getId())) {
/* no-op, we'll get the state later */
} else {
warning() << " got SET for completely unknown entity " << args[A]->getId();
}
continue; // we don't have it, ignore
}
ent->setFromRoot(args[A], false);
}
return HANDLED;
}
// we have to handle generic 'actions' late, to avoid trapping interesting
// such as create or divide
TypeInfo* ty = m_avatar->getConnection()->getTypeService()->getTypeForAtlas(op);
if (!ty->isBound()) {
new TypeBoundRedispatch(m_avatar->getConnection(), sightOp, ty);
return WILL_REDISPATCH;
}
if (ty->isA(m_actionType)) {
if (op->isDefaultFrom()) {
warning() << "recieved op " << ty->getName() << " with FROM unset";
return IGNORED;
}
Entity* ent = m_view->getEntity(op->getFrom());
if (ent) ent->onAction(op);
return HANDLED;
}
return IGNORED;
}
} // of namespace Eris
syntax highlighted by Code2HTML, v. 0.9.1