6 #include "Connection.h"
8 #include "Exceptions.h"
12 #include "EventService.h"
13 #include "SpawnPoint.h"
14 #include "TypeService.h"
16 #include <Atlas/Objects/Entity.h>
17 #include <Atlas/Objects/Operation.h>
18 #include <Atlas/Objects/Anonymous.h>
25 using Atlas::Objects::Root;
26 using Atlas::Message::Element;
27 using namespace Atlas::Objects::Operation;
28 using Atlas::Objects::Entity::RootEntity;
29 using Atlas::Objects::Entity::Anonymous;
30 typedef Atlas::Objects::Entity::Account AtlasAccount;
31 using Atlas::Objects::smart_dynamic_cast;
39 m_account->getConnection().setDefaultRouter(
this);
43 m_account->getConnection().clearDefaultRouter();
46 RouterResult handleOperation(
const RootOperation& op)
override {
48 if (op->getClassNo() == LOGOUT_NO) {
49 debug() <<
"Account received forced logout from server";
50 m_account->internalLogout(
false);
54 if ((op->getClassNo() == SIGHT_NO) && (op->getTo() == m_account->getId())) {
55 const std::vector<Root>& args = op->getArgs();
56 AtlasAccount acc = smart_dynamic_cast<AtlasAccount>(args.front());
57 m_account->updateFromObject(acc);
60 if (!acc->isDefaultCharacters()) {
61 m_account->refreshCharacterInfo();
67 if (op->getClassNo() == CHANGE_NO) {
68 m_account->getConnection().getTypeService().handleOperation(op);
72 if (op->getClassNo() == ERROR_NO) {
73 auto message = getErrorMessage(op);
74 if (!message.empty()) {
75 notice() <<
"Got error message from server: " << message;
76 m_account->ErrorMessage.emit(message);
91 m_status(
Status::DISCONNECTED),
93 m_doingCharacterRefresh(false) {
95 m_con.
Failure.connect(sigc::mem_fun(
this, &Account::netFailure));
99 ActiveCharacterMap::iterator it;
100 for (it = m_activeAvatars.begin(); it != m_activeAvatars.end();) {
102 cur->second->deactivate();
105 while (!m_activeAvatars.empty()) {
116 error() <<
"called login on unconnected Connection";
117 return NOT_CONNECTED;
121 error() <<
"called login, but state is not currently disconnected";
125 return internalLogin(uname, password);
129 const std::string& fullName,
130 const std::string& pwd) {
136 Atlas::Objects::Entity::Player account;
137 account->setPassword(pwd);
138 account->setName(fullName);
139 account->setUsername(uname);
152 c->setArgs1(accountOp);
154 m_con.getResponder().await(c->getSerialno(),
this, &Account::loginResponse);
157 m_timeout = std::make_unique<TimedEvent>(
m_con.getEventService(), std::chrono::seconds(5),
158 [&]() { this->handleLoginTimeout(); });
165 error() <<
"called logout on bad connection ignoring";
166 return NOT_CONNECTED;
172 error() <<
"called logout on non-logged-in Account";
185 m_con.getResponder().await(l->getSerialno(),
this, &Account::logoutResponse);
188 m_timeout = std::make_unique<TimedEvent>(
m_con.getEventService(), std::chrono::seconds(5),
189 [&]() { this->handleLogoutTimeout(); });
196 error() <<
"Not logged into an account : getCharacter returning empty dictionary";
212 if (m_characterIds.empty()) {
224 for (
const auto&
id : m_characterIds) {
228 m_con.getResponder().await(lk->getSerialno(),
this, &Account::sightCharacter);
243 return createCharacterThroughOperation(c);
246 Result Account::createCharacterThroughOperation(
const Create& c) {
250 error() <<
"duplicate char creation / take";
251 return DUPLICATE_CHAR_ACTIVE;
253 error() <<
"called createCharacter on unconnected Account, ignoring";
262 m_con.getResponder().await(c->getSerialno(),
this, &Account::avatarCreateResponse);
271 error() <<
"duplicate char creation / take";
272 return DUPLICATE_CHAR_ACTIVE;
274 error() <<
"called takeCharacter on unconnected Account, ignoring";
282 what->setAttr(
"possess_key", key);
284 Atlas::Objects::Operation::Generic possessOp;
285 possessOp->setParent(
"possess");
287 possessOp->setArgs1(what);
291 m_con.getResponder().await(possessOp->getSerialno(),
this, &Account::possessResponse);
301 error() <<
"duplicate char creation / take";
302 return DUPLICATE_CHAR_ACTIVE;
304 error() <<
"called takeCharacter on unconnected Account, ignoring";
312 Atlas::Objects::Operation::Generic possessOp;
313 possessOp->setParent(
"possess");
315 possessOp->setArgs1(what);
319 m_con.getResponder().await(possessOp->getSerialno(),
this, &Account::possessResponse);
329 Result Account::internalLogin(
const std::string& uname,
const std::string& pwd) {
335 AtlasAccount account;
336 account->setPassword(pwd);
337 account->setUsername(uname);
340 l->setArgs1(account);
342 m_con.getResponder().await(l->getSerialno(),
this, &Account::loginResponse);
345 m_timeout = std::make_unique<TimedEvent>(
m_con.getEventService(), std::chrono::seconds(5),
346 [&]() { this->handleLoginTimeout(); });
351 void Account::logoutResponse(
const RootOperation& op) {
352 if (!op->instanceOf(INFO_NO))
353 warning() <<
"received a logout response that is not an INFO";
355 internalLogout(
true);
358 void Account::internalLogout(
bool clean) {
361 error() <<
"got clean logout, but not logging out already";
365 error() <<
"got forced logout, but not currently logged in";
379 void Account::loginResponse(
const RootOperation& op) {
380 if (op->instanceOf(ERROR_NO)) {
381 loginError(smart_dynamic_cast<Error>(op));
382 }
else if (op->instanceOf(INFO_NO)) {
383 const std::vector<Root>& args = op->getArgs();
384 loginComplete(smart_dynamic_cast<AtlasAccount>(args.front()));
386 warning() <<
"received malformed login response: " << op->getClassNo();
389 void Account::loginComplete(
const AtlasAccount& p) {
391 error() <<
"got loginComplete, but not currently logging in!";
395 error() <<
"no account in response.";
401 warning() <<
"received username does not match existing";
423 auto I = m_activeAvatars.find(avatarId);
425 if (I != m_activeAvatars.end()) {
426 m_activeAvatars.erase(I);
431 void Account::updateFromObject(
const AtlasAccount& p) {
432 auto characters = std::set<std::string>(p->getCharacters().begin(), p->getCharacters().end());
433 std::string createdCharacterId;
436 for (
auto& character : characters) {
437 if (m_characterIds.find(character) == m_characterIds.end()) {
438 createdCharacterId = character;
443 m_characterIds = std::move(characters);
444 m_parent = p->getParent();
446 if (p->hasAttr(
"spawns")) {
448 const auto& spawns = p->getAttr(
"spawns");
450 if (spawns.isList()) {
451 auto& spawnsList = spawns.List();
452 for (
const auto& spawnElement : spawnsList) {
453 if (spawnElement.isMap()) {
454 auto& spawnMap = spawnElement.Map();
456 std::string description;
458 std::vector<SpawnProperty> properties;
460 auto I = spawnMap.find(
"name");
461 if (I != spawnMap.end() && I->second.isString()) {
462 name = I->second.String();
466 auto I = spawnMap.find(
"description");
467 if (I != spawnMap.end() && I->second.isString()) {
468 description = I->second.String();
472 auto I = spawnMap.find(
"id");
473 if (I != spawnMap.end() && I->second.isString()) {
474 id = I->second.String();
478 auto I = spawnMap.find(
"properties");
479 if (I != spawnMap.end() && I->second.isList()) {
480 auto propList = I->second.List();
481 for (
auto& entry : propList) {
483 auto& entryMap = entry.Map();
484 std::string propName;
485 std::string propLabel;
486 std::string propDescription;
487 SpawnProperty::Type propType = SpawnProperty::Type::STRING;
488 std::vector<Atlas::Message::Element> propOptions;
491 auto J = entryMap.find(
"name");
492 if (J != entryMap.end() && J->second.isString()) {
493 propName = J->second.String();
497 auto J = entryMap.find(
"label");
498 if (J != entryMap.end() && J->second.isString()) {
499 propLabel = J->second.String();
503 auto J = entryMap.find(
"description");
504 if (J != entryMap.end() && J->second.isString()) {
505 propDescription = J->second.String();
509 auto J = entryMap.find(
"type");
510 if (J != entryMap.end() && J->second.isString()) {
511 auto& type = J->second.String();
512 if (type ==
"string") {
513 propType = SpawnProperty::Type::STRING;
518 auto J = entryMap.find(
"options");
519 if (J != entryMap.end() && J->second.isList()) {
520 propOptions = J->second.List();
523 properties.emplace_back(SpawnProperty{propName, propLabel, propDescription, propType, propOptions});
529 m_spawnPoints.emplace_back(SpawnPoint{id, name, description, properties});
533 error() <<
"Account has attribute \"spawns\" which is not of type List.";
542 void Account::loginError(
const Error& err) {
544 warning() <<
"Got invalid error";
548 error() <<
"got loginError while not logging in";
551 std::string msg = getErrorMessage(err);
560 void Account::handleLoginTimeout() {
564 LoginFailure.emit(
"timed out waiting for server response");
567 void Account::possessResponse(
const RootOperation& op) {
568 if (op->instanceOf(ERROR_NO)) {
569 std::string msg = getErrorMessage(op);
574 }
else if (op->instanceOf(INFO_NO)) {
575 const std::vector<Root>& args = op->getArgs();
577 warning() <<
"no args character possess response";
581 auto ent = smart_dynamic_cast<RootEntity>(args.front());
582 if (!ent.isValid()) {
583 warning() <<
"malformed character possess response";
587 if (!ent->hasAttr(
"entity")) {
588 warning() <<
"malformed character possess response";
592 auto entityMessage = ent->getAttr(
"entity");
594 if (!entityMessage.isMap()) {
595 warning() <<
"malformed character possess response";
598 auto entityObj = smart_dynamic_cast<RootEntity>(
m_con.getFactories().createObject(entityMessage.Map()));
600 if (!entityObj || entityObj->isDefaultId()) {
601 warning() <<
"malformed character possess response";
605 if (m_activeAvatars.find(ent->getId()) != m_activeAvatars.end()) {
606 warning() <<
"got possession response for character already created";
610 auto av = std::make_unique<Avatar>(*
this, ent->getId(), entityObj->getId());
614 m_activeAvatars[av->getId()] = std::move(av);
617 warning() <<
"received incorrect avatar create/take response";
620 void Account::avatarCreateResponse(
const RootOperation& op) {
621 if (op->instanceOf(ERROR_NO)) {
622 std::string msg = getErrorMessage(op);
630 void Account::internalDeactivateCharacter(
const std::string& avatarId) {
631 auto I = m_activeAvatars.find(avatarId);
632 if (I == m_activeAvatars.end()) {
633 warning() <<
"trying to deactivate non active character";
635 m_activeAvatars.erase(I);
639 void Account::sightCharacter(
const RootOperation& op) {
641 error() <<
"got sight of character outside a refresh, ignoring";
645 const std::vector<Root>& args = op->getArgs();
647 error() <<
"got sight of character with no args";
651 RootEntity ge = smart_dynamic_cast<RootEntity>(args.front());
653 error() <<
"got sight of character with malformed args";
659 error() <<
"duplicate sight of character " << ge->getId();
664 _characters.insert(C, CharacterMap::value_type(ge->getId(), ge));
682 debug() <<
"Account " <<
m_username <<
" got netConnected, doing reconnect";
696 void Account::netFailure(
const std::string& ) {
700 void Account::handleLogoutTimeout() {
701 error() <<
"LOGOUT timed out waiting for response";
709 void Account::avatarLogoutResponse(
const RootOperation& op) {
710 if (!op->instanceOf(INFO_NO)) {
711 warning() <<
"received an avatar logout response that is not an INFO";
715 const std::vector<Root>& args(op->getArgs());
717 if (args.empty() || (args.front()->getClassNo() != LOGOUT_NO)) {
718 warning() <<
"argument of avatar logout INFO is not a logout op";
722 RootOperation
logout = smart_dynamic_cast<RootOperation>(args.front());
723 const std::vector<Root>& args2(
logout->getArgs());
725 warning() <<
"argument of avatar logout INFO is logout without args";
729 std::string charId = args2.front()->getId();
730 debug() <<
"got logout for character " << charId;
732 if (m_characterIds.find(charId) == m_characterIds.end()) {
733 warning() <<
"character ID " << charId <<
" is unknown on account " <<
m_accountId;
736 auto it = m_activeAvatars.find(charId);
737 if (it == m_activeAvatars.end()) {
738 warning() <<
"character ID " << charId <<
" does not correspond to an active avatar.";