7 #include "Connection.h"
10 #include "LogStream.h"
12 #include "TypeBoundRedispatch.h"
13 #include "TransferInfo.h"
14 #include "TypeService.h"
16 #include <Atlas/Objects/Operation.h>
17 #include <Atlas/Objects/Entity.h>
19 using namespace Atlas::Objects::Operation;
20 using Atlas::Objects::Root;
21 using Atlas::Objects::Entity::RootEntity;
22 using Atlas::Objects::smart_dynamic_cast;
23 using Atlas::Message::Element;
27 IGRouter::IGRouter(Avatar& av, View& view) :
31 m_avatar.getConnection().registerRouterForTo(
this, m_avatar.getEntityId());
32 m_actionType = m_avatar.getConnection().getTypeService().getTypeByName(
"action");
37 m_avatar.getConnection().unregisterRouterForTo(
this, m_avatar.getEntityId());
40 Router::RouterResult IGRouter::handleOperation(
const RootOperation& op)
42 if (!op->isDefaultSeconds()) {
44 m_avatar.updateWorldTime(op->getSeconds());
47 const std::vector<Root>& args = op->getArgs();
49 if (op->getClassNo() == SIGHT_NO) {
51 warning() <<
"Avatar received sight with empty args";
55 for (
const auto& arg : args) {
56 if (arg->instanceOf(ROOT_OPERATION_NO)) {
57 handleSightOp(op, smart_dynamic_cast<RootOperation>(arg));
60 RootEntity gent = smart_dynamic_cast<RootEntity>(arg);
63 if (!gent->isDefaultId() && !gent->isDefaultParent()) {
64 TypeInfo* ty = m_avatar.getConnection().getTypeService().getTypeForAtlas(gent);
66 auto opCopy = op.copy();
67 opCopy->setArgs1(arg);
68 new TypeBoundRedispatch(m_avatar.getConnection(), opCopy, ty);
82 if (op->getClassNo() == APPEARANCE_NO) {
83 for (
const auto& arg : args) {
85 if (!arg->isDefaultStamp()) {
86 stamp = arg->getStamp();
89 if (!arg->isDefaultId()) {
90 m_view.appear(arg->getId(), stamp);
97 if (op->getClassNo() == DISAPPEARANCE_NO) {
98 for (
const auto& arg : args) {
99 if (!arg->isDefaultId()) {
100 m_view.disappear(arg->getId());
107 if (op->getClassNo() == UNSEEN_NO)
110 warning() <<
"Avatar received unseen with empty args";
113 for (
const auto& arg : args) {
114 if (!arg->isDefaultId()) {
115 m_view.unseen(arg->getId());
122 if (op->getClassNo() == LOGOUT_NO) {
123 debug() <<
"Avatar received forced logout from server";
125 if(args.size() >= 2) {
128 const Root & arg = args[1];
129 Element tp_host_attr;
130 Element tp_port_attr;
132 Element pentity_id_attr;
133 if(arg->copyAttr(
"teleport_host", tp_host_attr) != 0
134 || !tp_host_attr.isString()) {
135 debug() <<
"No teleport host specified. Doing normal logout."
136 << std::endl << std::flush;
138 }
else if (arg->copyAttr(
"teleport_port", tp_port_attr) != 0
139 || !tp_port_attr.isInt()) {
140 debug() <<
"No teleport port specified. Doing normal logout."
141 << std::endl << std::flush;
143 }
else if (arg->copyAttr(
"possess_key", pkey_attr) != 0
144 || !pkey_attr.isString()) {
145 debug() <<
"No possess key specified. Doing normal logout."
146 << std::endl << std::flush;
148 }
else if (arg->copyAttr(
"possess_entity_id", pentity_id_attr) != 0
149 || !pentity_id_attr.isString()) {
150 debug() <<
"No entity ID specified. Doing normal logout."
151 << std::endl << std::flush;
158 std::string teleport_host = tp_host_attr.String();
159 int teleport_port =
static_cast<int>(tp_port_attr.Int());
160 std::string possess_key = pkey_attr.String();
161 std::string possess_entity_id = pentity_id_attr.String();
162 debug() <<
"Server transfer data: Host: " << teleport_host
163 <<
", Port: " << teleport_port <<
", "
164 <<
"Key: " << possess_key <<
", "
165 <<
"ID: " << possess_entity_id << std::endl << std::flush;
167 TransferInfo transfer(teleport_host, teleport_port, possess_key
168 , possess_entity_id);
169 m_avatar.logoutRequested(transfer);
171 m_avatar.logoutRequested();
176 m_avatar.logoutRequested();
185 Router::RouterResult IGRouter::handleSightOp(
const RootOperation& sightOp,
const RootOperation& op)
187 const auto& args = op->getArgs();
191 if (op->getClassNo() == SET_NO) {
192 for (
const auto& arg : args) {
193 if (!arg->isDefaultId()) {
194 auto ent = m_view.getEntity(arg->getId());
196 if (m_view.isPending(arg->getId())) {
199 m_view.sendLookAt(arg->getId());
208 if (!ent->isVisible()) {
215 m_view.getEntityFromServer(arg->getId());
217 ent->setFromRoot(arg,
false);
224 if (!op->isDefaultParent()) {
227 TypeInfo* ty = m_avatar.getConnection().getTypeService().getTypeForAtlas(op);
228 if (!ty->isBound()) {
229 new TypeBoundRedispatch(m_avatar.getConnection(), sightOp, ty);
236 if (op->getClassNo() == HIT_NO) {
237 if (!op->isDefaultTo()) {
238 Entity* ent = m_view.getEntity(op->getTo());
240 ent->onHit(smart_dynamic_cast<Hit>(op), *ty);
243 warning() <<
"received hit with TO unset";
248 if (ty->isA(m_actionType)) {
249 if (op->isDefaultFrom()) {
250 warning() <<
"received op " << ty->getName() <<
" with FROM unset";
254 Entity* ent = m_view.getEntity(op->getFrom());
256 ent->onAction(op, *ty);