eris  1.4.0
A WorldForge client library.
Account.cpp
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #include "Account.h"
6 #include "Connection.h"
7 #include "LogStream.h"
8 #include "Exceptions.h"
9 #include "Avatar.h"
10 #include "Router.h"
11 #include "Response.h"
12 #include "EventService.h"
13 #include "SpawnPoint.h"
14 #include "TypeService.h"
15 
16 #include <Atlas/Objects/Entity.h>
17 #include <Atlas/Objects/Operation.h>
18 #include <Atlas/Objects/Anonymous.h>
19 
20 #include <algorithm>
21 #include <cassert>
22 #include <iostream>
23 #include <memory>
24 
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;
32 
33 namespace Eris {
34 
35 class AccountRouter : public Router {
36 public:
37  explicit AccountRouter(Account* pl) :
38  m_account(pl) {
39  m_account->getConnection().setDefaultRouter(this);
40  }
41 
42  ~AccountRouter() override {
43  m_account->getConnection().clearDefaultRouter();
44  }
45 
46  RouterResult handleOperation(const RootOperation& op) override {
47  // logout
48  if (op->getClassNo() == LOGOUT_NO) {
49  debug() << "Account received forced logout from server";
50  m_account->internalLogout(false);
51  return HANDLED;
52  }
53 
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);
58 
59  // refresh character data if it changed
60  if (!acc->isDefaultCharacters()) {
61  m_account->refreshCharacterInfo();
62  }
63 
64  return HANDLED;
65  }
66 
67  if (op->getClassNo() == CHANGE_NO) {
68  m_account->getConnection().getTypeService().handleOperation(op);
69  return HANDLED;
70  }
71 
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);
77  }
78 
79  return HANDLED;
80  }
81 
82  return IGNORED;
83  }
84 
85 private:
86  Account* m_account;
87 };
88 
89 Account::Account(Connection& con) :
90  m_con(con),
91  m_status(Status::DISCONNECTED),
92  m_router(std::make_unique<AccountRouter>(this)),
93  m_doingCharacterRefresh(false) {
94  m_con.Connected.connect(sigc::mem_fun(this, &Account::netConnected));
95  m_con.Failure.connect(sigc::mem_fun(this, &Account::netFailure));
96 }
97 
98 Account::~Account() {
99  ActiveCharacterMap::iterator it;
100  for (it = m_activeAvatars.begin(); it != m_activeAvatars.end();) {
101  auto cur = it++;
102  cur->second->deactivate(); // send logout op
103  }
104  //Don't wait for logout response, delete all avatars now.
105  while (!m_activeAvatars.empty()) {
106  destroyAvatar(m_activeAvatars.begin()->first);
107  }
108 
109  if (isLoggedIn()) {
110  logout();
111  }
112 }
113 
114 Result Account::login(const std::string& uname, const std::string& password) {
115  if (!m_con.isConnected()) {
116  error() << "called login on unconnected Connection";
117  return NOT_CONNECTED;
118  }
119 
121  error() << "called login, but state is not currently disconnected";
122  return ALREADY_LOGGED_IN;
123  }
124 
125  return internalLogin(uname, password);
126 }
127 
128 Result Account::createAccount(const std::string& uname,
129  const std::string& fullName,
130  const std::string& pwd) {
131  // store for re-logins
132  m_username = uname;
133  m_pass = pwd;
134 
135  //We should clarify that we want a player account.
136  Atlas::Objects::Entity::Player account;
137  account->setPassword(pwd);
138  account->setName(fullName);
139  account->setUsername(uname);
140 
141  return createAccount(account);
142 }
143 
144 Result Account::createAccount(const Atlas::Objects::Entity::Account& accountOp) {
145  if (!m_con.isConnected()) return NOT_CONNECTED;
147 
149 
150  Create c;
151  c->setSerialno(getNewSerialno());
152  c->setArgs1(accountOp);
153 
154  m_con.getResponder().await(c->getSerialno(), this, &Account::loginResponse);
155  m_con.send(c);
156 
157  m_timeout = std::make_unique<TimedEvent>(m_con.getEventService(), std::chrono::seconds(5),
158  [&]() { this->handleLoginTimeout(); });
159 
160  return NO_ERR;
161 }
162 
164  if (!m_con.isConnected()) {
165  error() << "called logout on bad connection ignoring";
166  return NOT_CONNECTED;
167  }
168 
169  if (m_status == Status::LOGGING_OUT) return NO_ERR;
170 
171  if (m_status != Status::LOGGED_IN) {
172  error() << "called logout on non-logged-in Account";
173  return NOT_LOGGED_IN;
174  }
175 
177 
178  //Send a Logout to the connection, with the Account as entity reference.
179  Logout l;
180  Anonymous arg;
181  arg->setId(m_accountId);
182  l->setArgs1(arg);
183  l->setSerialno(getNewSerialno());
184 
185  m_con.getResponder().await(l->getSerialno(), this, &Account::logoutResponse);
186  m_con.send(l);
187 
188  m_timeout = std::make_unique<TimedEvent>(m_con.getEventService(), std::chrono::seconds(5),
189  [&]() { this->handleLogoutTimeout(); });
190 
191  return NO_ERR;
192 }
193 
196  error() << "Not logged into an account : getCharacter returning empty dictionary";
197 
198  return _characters;
199 }
200 
202  if (!m_con.isConnected()) return NOT_CONNECTED;
203  if (m_status != Status::LOGGED_IN) {
204  return NOT_LOGGED_IN;
205  }
206 
207  // silently ignore overlapping refreshes
208  if (m_doingCharacterRefresh) return NO_ERR;
209 
210  _characters.clear();
211 
212  if (m_characterIds.empty()) {
213  GotAllCharacters.emit(); // we must emit the done signal
214  return NO_ERR;
215  }
216 
217 // okay, now we know we have at least one character to lookup, set the flag
219 
220  Look lk;
221  Anonymous obj;
222  lk->setFrom(m_accountId);
223 
224  for (const auto& id : m_characterIds) {
225  obj->setId(id);
226  lk->setArgs1(obj);
227  lk->setSerialno(getNewSerialno());
228  m_con.getResponder().await(lk->getSerialno(), this, &Account::sightCharacter);
229  m_con.send(lk);
230  }
231 
232  return NO_ERR;
233 }
234 
235 Result Account::createCharacterThroughEntity(const Atlas::Objects::Entity::RootEntity& ent) {
236  //Make sure we also possess the newly created character; we don't want to support non-possessed characters in the client for now.
237  ent->setAttr("__account", m_username);
238  Create c;
239  c->setArgs1(ent);
240  c->setFrom(m_accountId);
241  c->setTo(m_accountId);
242 
243  return createCharacterThroughOperation(c);
244 }
245 
246 Result Account::createCharacterThroughOperation(const Create& c) {
247  if (!m_con.isConnected()) return NOT_CONNECTED;
248  if (m_status != Status::LOGGED_IN) {
250  error() << "duplicate char creation / take";
251  return DUPLICATE_CHAR_ACTIVE;
252  } else {
253  error() << "called createCharacter on unconnected Account, ignoring";
254  return NOT_LOGGED_IN;
255  }
256  }
257 
258  c->setSerialno(getNewSerialno());
259  m_con.send(c);
260 
261  //First response should be a Sight of the newly created character, followed by an Info of the Mind created.
262  m_con.getResponder().await(c->getSerialno(), this, &Account::avatarCreateResponse);
264  return NO_ERR;
265 }
266 
267 Result Account::takeTransferredCharacter(const std::string& id, const std::string& key) {
268  if (!m_con.isConnected()) return NOT_CONNECTED;
269  if (m_status != Status::LOGGED_IN) {
271  error() << "duplicate char creation / take";
272  return DUPLICATE_CHAR_ACTIVE;
273  } else {
274  error() << "called takeCharacter on unconnected Account, ignoring";
275  return NOT_LOGGED_IN;
276  }
277  }
278 
279 
280  Anonymous what;
281  what->setId(id);
282  what->setAttr("possess_key", key);
283 
284  Atlas::Objects::Operation::Generic possessOp;
285  possessOp->setParent("possess");
286  possessOp->setFrom(m_accountId);
287  possessOp->setArgs1(what);
288  possessOp->setSerialno(getNewSerialno());
289  m_con.send(possessOp);
290 
291  m_con.getResponder().await(possessOp->getSerialno(), this, &Account::possessResponse);
293  return NO_ERR;
294 }
295 
296 Result Account::takeCharacter(const std::string& id) {
297 
298  if (!m_con.isConnected()) return NOT_CONNECTED;
301  error() << "duplicate char creation / take";
302  return DUPLICATE_CHAR_ACTIVE;
303  } else {
304  error() << "called takeCharacter on unconnected Account, ignoring";
305  return NOT_LOGGED_IN;
306  }
307  }
308 
309  Anonymous what;
310  what->setId(id);
311 
312  Atlas::Objects::Operation::Generic possessOp;
313  possessOp->setParent("possess");
314  possessOp->setFrom(m_accountId);
315  possessOp->setArgs1(what);
316  possessOp->setSerialno(getNewSerialno());
317  m_con.send(possessOp);
318 
319  m_con.getResponder().await(possessOp->getSerialno(), this, &Account::possessResponse);
321  return NO_ERR;
322 }
323 
324 bool Account::isLoggedIn() const {
325  return ((m_status == Status::LOGGED_IN) ||
327 }
328 
329 Result Account::internalLogin(const std::string& uname, const std::string& pwd) {
330  assert(m_status == Status::DISCONNECTED);
331 
333  m_username = uname;
334 
335  AtlasAccount account;
336  account->setPassword(pwd);
337  account->setUsername(uname);
338 
339  Login l;
340  l->setArgs1(account);
341  l->setSerialno(getNewSerialno());
342  m_con.getResponder().await(l->getSerialno(), this, &Account::loginResponse);
343  m_con.send(l);
344 
345  m_timeout = std::make_unique<TimedEvent>(m_con.getEventService(), std::chrono::seconds(5),
346  [&]() { this->handleLoginTimeout(); });
347 
348  return NO_ERR;
349 }
350 
351 void Account::logoutResponse(const RootOperation& op) {
352  if (!op->instanceOf(INFO_NO))
353  warning() << "received a logout response that is not an INFO";
354 
355  internalLogout(true);
356 }
357 
358 void Account::internalLogout(bool clean) {
359  if (clean) {
361  error() << "got clean logout, but not logging out already";
362  } else {
365  error() << "got forced logout, but not currently logged in";
366  }
367 
368  m_con.unregisterRouterForTo(m_router.get(), m_accountId);
370  m_timeout.reset();
371 
373  m_con.unlock();
374  } else {
375  LogoutComplete.emit(clean);
376  }
377 }
378 
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()));
385  } else
386  warning() << "received malformed login response: " << op->getClassNo();
387 }
388 
389 void Account::loginComplete(const AtlasAccount& p) {
390  if (m_status != Status::LOGGING_IN) {
391  error() << "got loginComplete, but not currently logging in!";
392  }
393 
394  if (!p.isValid()) {
395  error() << "no account in response.";
396  return;
397  }
398 
399  //The user name being different should not be a fatal thing.
400  if (p->getUsername() != m_username) {
401  warning() << "received username does not match existing";
402  m_username = p->getUsername();
403  }
404 
406  m_accountId = p->getId();
407 
408  m_con.registerRouterForTo(m_router.get(), m_accountId);
409  updateFromObject(p);
410 
411  // notify an people watching us
412  LoginSuccess.emit();
413 
414  m_con.Disconnecting.connect(sigc::mem_fun(this, &Account::netDisconnecting));
415  m_timeout.reset();
416 }
417 
419  destroyAvatar(avatar->getId());
420 }
421 
422 void Account::destroyAvatar(const std::string& avatarId) {
423  auto I = m_activeAvatars.find(avatarId);
424  //The avatar might have already have been deleted by another response; this is a normal case.
425  if (I != m_activeAvatars.end()) {
426  m_activeAvatars.erase(I);
427  AvatarDeactivated(avatarId);
428  }
429 }
430 
431 void Account::updateFromObject(const AtlasAccount& p) {
432  auto characters = std::set<std::string>(p->getCharacters().begin(), p->getCharacters().end());
433  std::string createdCharacterId;
435  //See which character was added
436  for (auto& character : characters) {
437  if (m_characterIds.find(character) == m_characterIds.end()) {
438  createdCharacterId = character;
439  break;
440  }
441  }
442  }
443  m_characterIds = std::move(characters);
444  m_parent = p->getParent();
445 
446  if (p->hasAttr("spawns")) {
447  m_spawnPoints.clear();
448  const auto& spawns = p->getAttr("spawns");
449 
450  if (spawns.isList()) {
451  auto& spawnsList = spawns.List();
452  for (const auto& spawnElement : spawnsList) {
453  if (spawnElement.isMap()) {
454  auto& spawnMap = spawnElement.Map();
455  std::string name;
456  std::string description;
457  std::string id;
458  std::vector<SpawnProperty> properties;
459  {
460  auto I = spawnMap.find("name");
461  if (I != spawnMap.end() && I->second.isString()) {
462  name = I->second.String();
463  }
464  }
465  {
466  auto I = spawnMap.find("description");
467  if (I != spawnMap.end() && I->second.isString()) {
468  description = I->second.String();
469  }
470  }
471  {
472  auto I = spawnMap.find("id");
473  if (I != spawnMap.end() && I->second.isString()) {
474  id = I->second.String();
475  }
476  }
477  {
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) {
482  if (entry.isMap()) {
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;
489 
490  {
491  auto J = entryMap.find("name");
492  if (J != entryMap.end() && J->second.isString()) {
493  propName = J->second.String();
494  }
495  }
496  {
497  auto J = entryMap.find("label");
498  if (J != entryMap.end() && J->second.isString()) {
499  propLabel = J->second.String();
500  }
501  }
502  {
503  auto J = entryMap.find("description");
504  if (J != entryMap.end() && J->second.isString()) {
505  propDescription = J->second.String();
506  }
507  }
508  {
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;
514  }
515  }
516  }
517  {
518  auto J = entryMap.find("options");
519  if (J != entryMap.end() && J->second.isList()) {
520  propOptions = J->second.List();
521  }
522  }
523  properties.emplace_back(SpawnProperty{propName, propLabel, propDescription, propType, propOptions});
524  }
525 
526  }
527  }
528  }
529  m_spawnPoints.emplace_back(SpawnPoint{id, name, description, properties});
530  }
531  }
532  } else {
533  error() << "Account has attribute \"spawns\" which is not of type List.";
534  }
535  }
536  if (m_status == Status::CREATING_CHAR && !createdCharacterId.empty()) {
538  takeCharacter(createdCharacterId);
539  }
540 }
541 
542 void Account::loginError(const Error& err) {
543  if (!err) {
544  warning() << "Got invalid error";
545  return;
546  }
547  if (m_status != Status::LOGGING_IN) {
548  error() << "got loginError while not logging in";
549  }
550 
551  std::string msg = getErrorMessage(err);
552 
553  // update state before emitting signal
555  m_timeout.reset();
556 
557  LoginFailure.emit(msg);
558 }
559 
560 void Account::handleLoginTimeout() {
562  m_timeout.reset();
563 
564  LoginFailure.emit("timed out waiting for server response");
565 }
566 
567 void Account::possessResponse(const RootOperation& op) {
568  if (op->instanceOf(ERROR_NO)) {
569  std::string msg = getErrorMessage(op);
570 
571  // creating or taking a character failed for some reason
572  AvatarFailure(msg);
574  } else if (op->instanceOf(INFO_NO)) {
575  const std::vector<Root>& args = op->getArgs();
576  if (args.empty()) {
577  warning() << "no args character possess response";
578  return;
579  }
580 
581  auto ent = smart_dynamic_cast<RootEntity>(args.front());
582  if (!ent.isValid()) {
583  warning() << "malformed character possess response";
584  return;
585  }
586 
587  if (!ent->hasAttr("entity")) {
588  warning() << "malformed character possess response";
589  return;
590  }
591 
592  auto entityMessage = ent->getAttr("entity");
593 
594  if (!entityMessage.isMap()) {
595  warning() << "malformed character possess response";
596  return;
597  }
598  auto entityObj = smart_dynamic_cast<RootEntity>(m_con.getFactories().createObject(entityMessage.Map()));
599 
600  if (!entityObj || entityObj->isDefaultId()) {
601  warning() << "malformed character possess response";
602  return;
603  }
604 
605  if (m_activeAvatars.find(ent->getId()) != m_activeAvatars.end()) {
606  warning() << "got possession response for character already created";
607  return;
608  }
609 
610  auto av = std::make_unique<Avatar>(*this, ent->getId(), entityObj->getId());
611  AvatarSuccess.emit(av.get());
613 
614  m_activeAvatars[av->getId()] = std::move(av);
615 
616  } else
617  warning() << "received incorrect avatar create/take response";
618 }
619 
620 void Account::avatarCreateResponse(const RootOperation& op) {
621  if (op->instanceOf(ERROR_NO)) {
622  std::string msg = getErrorMessage(op);
623 
624  // creating or taking a character failed for some reason
625  AvatarFailure(msg);
627  }
628 }
629 
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";
634  } else {
635  m_activeAvatars.erase(I);
636  }
637 }
638 
639 void Account::sightCharacter(const RootOperation& op) {
641  error() << "got sight of character outside a refresh, ignoring";
642  return;
643  }
644 
645  const std::vector<Root>& args = op->getArgs();
646  if (args.empty()) {
647  error() << "got sight of character with no args";
648  return;
649  }
650 
651  RootEntity ge = smart_dynamic_cast<RootEntity>(args.front());
652  if (!ge.isValid()) {
653  error() << "got sight of character with malformed args";
654  return;
655  }
656 
657  auto C = _characters.find(ge->getId());
658  if (C != _characters.end()) {
659  error() << "duplicate sight of character " << ge->getId();
660  return;
661  }
662 
663  // okay, we can now add it to our map
664  _characters.insert(C, CharacterMap::value_type(ge->getId(), ge));
665  GotCharacterInfo.emit(ge);
666 
667  // check if we're done
668  if (_characters.size() == m_characterIds.size()) {
669  m_doingCharacterRefresh = false;
670  GotAllCharacters.emit();
671  }
672 }
673 
674 /* this will only ever get encountered after the connection is initally up;
675 thus we use it to trigger a reconnection. Note that some actions by
676 Lobby and World are also required to get everything back into the correct
677 state */
678 
680  // re-connection
681  if (!m_username.empty() && !m_pass.empty() && (m_status == Status::DISCONNECTED)) {
682  debug() << "Account " << m_username << " got netConnected, doing reconnect";
683  internalLogin(m_username, m_pass);
684  }
685 }
686 
688  if (m_status == Status::LOGGED_IN) {
689  m_con.lock();
690  logout();
691  return false;
692  } else
693  return true;
694 }
695 
696 void Account::netFailure(const std::string& /*msg*/) {
697 
698 }
699 
700 void Account::handleLogoutTimeout() {
701  error() << "LOGOUT timed out waiting for response";
702 
704  m_timeout.reset();
705 
706  LogoutComplete.emit(false);
707 }
708 
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";
712  return;
713  }
714 
715  const std::vector<Root>& args(op->getArgs());
716 
717  if (args.empty() || (args.front()->getClassNo() != LOGOUT_NO)) {
718  warning() << "argument of avatar logout INFO is not a logout op";
719  return;
720  }
721 
722  RootOperation logout = smart_dynamic_cast<RootOperation>(args.front());
723  const std::vector<Root>& args2(logout->getArgs());
724  if (args2.empty()) {
725  warning() << "argument of avatar logout INFO is logout without args";
726  return;
727  }
728 
729  std::string charId = args2.front()->getId();
730  debug() << "got logout for character " << charId;
731 
732  if (m_characterIds.find(charId) == m_characterIds.end()) {
733  warning() << "character ID " << charId << " is unknown on account " << m_accountId;
734  }
735 
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.";
739  return;
740  }
741 
742  destroyAvatar(charId);
743 }
744 
745 } // of namespace Eris
Eris::NOT_LOGGED_IN
@ NOT_LOGGED_IN
Occurs when performing an operation that requires a valid server login.
Definition: Types.h:27
Eris::Account::m_accountId
std::string m_accountId
the account ID
Definition: Account.h:298
Eris::Account::GotAllCharacters
sigc::signal< void > GotAllCharacters
emitted when the entire character list had been updated
Definition: Account.h:190
Eris::Connection::Failure
sigc::signal< void, const std::string & > Failure
Definition: Connection.h:142
Eris::notice
Definition: LogStream.h:35
Eris::BaseConnection::Connected
sigc::signal< void > Connected
sent on successful negotiation of a game server connection
Definition: BaseConnection.h:95
Eris::Account::takeTransferredCharacter
Result takeTransferredCharacter(const std::string &id, const std::string &key)
Transfer all characters to this account and then do all steps in takeCharacter()
Definition: Account.cpp:267
Eris::Account::GotCharacterInfo
sigc::signal< void, const Atlas::Objects::Entity::RootEntity & > GotCharacterInfo
emitted when a character has been retrieved from the server
Definition: Account.h:187
Eris::Account::takeCharacter
Result takeCharacter(const std::string &id)
Enter the game using an existing character.
Definition: Account.cpp:296
Eris::Account::Status::CREATED_CHAR
@ CREATED_CHAR
a character was created, we now need to possess it
Eris::Account::avatarLogoutRequested
void avatarLogoutRequested(Avatar *avatar)
Called when a logout of the avatar has been requested by the server.
Definition: Account.cpp:418
Eris::Account::Status
Status
Definition: Account.h:279
Eris::Account::Status::LOGGING_OUT
@ LOGGING_OUT
Sent a logout op, waiting for the INFO response.
Eris::Account::refreshCharacterInfo
Result refreshCharacterInfo()
Definition: Account.cpp:201
Eris::Account
Encapsulates all the state of an Atlas Account, and methods that operation on that state.
Definition: Account.h:42
Eris::Router
Definition: Router.h:10
Eris::Account::m_doingCharacterRefresh
bool m_doingCharacterRefresh
set if we're refreshing character data
Definition: Account.h:305
Eris::Avatar
Definition: Avatar.h:39
Eris::Account::AvatarFailure
sigc::signal< void, const std::string & > AvatarFailure
Definition: Account.h:219
Eris::Account::m_username
std::string m_username
The player's username ( != account object's ID)
Definition: Account.h:299
Eris::error
Definition: LogStream.h:65
Eris::Account::LogoutComplete
sigc::signal< void, bool > LogoutComplete
Emitted when a logout completes.
Definition: Account.h:207
Eris::Account::Status::TAKING_CHAR
@ TAKING_CHAR
sent a LOOK op for a character, awaiting INFO response
Eris::Account::m_con
Connection & m_con
underlying connection instance
Definition: Account.h:294
Eris::Account::LoginFailure
sigc::signal< void, const std::string & > LoginFailure
Emitted when a server-side error occurs during account creation / login.
Definition: Account.h:197
Eris::ALREADY_LOGGED_IN
@ ALREADY_LOGGED_IN
Occurs when trying to log in to an Account which is already logged in.
Definition: Types.h:29
Eris::BaseConnection::isConnected
bool isConnected() const
Ascertain whether or not the connection is usable for transport.
Definition: BaseConnection.h:72
Eris::Account::Status::DISCONNECTED
@ DISCONNECTED
Default state, no server account active.
Eris::AccountRouter
Definition: Account.cpp:35
Eris::Account::isLoggedIn
bool isLoggedIn() const
Check if the account is logged in.
Definition: Account.cpp:324
Eris::getNewSerialno
std::int64_t getNewSerialno()
operation serial number sequencing
Definition: Connection.cpp:390
Eris::Account::Status::CREATING_CHAR
@ CREATING_CHAR
send a character CREATE op, awaiting INFO response
Eris
Definition: Account.cpp:33
Eris::Account::netConnected
void netConnected()
Callback for network re-establishment.
Definition: Account.cpp:679
Eris::Account::AvatarSuccess
sigc::signal< void, Avatar * > AvatarSuccess
Definition: Account.h:213
Eris::Connection::unlock
void unlock()
Definition: Connection.cpp:221
Eris::Avatar::getId
const std::string & getId() const
Get the Mind id of this Avatar. All interaction with the entity goes through the Mind.
Definition: Avatar.h:250
Eris::BaseConnection::DISCONNECTING
@ DISCONNECTING
clean disconnection in progress
Definition: BaseConnection.h:61
Eris::Result
Result
Definition: Types.h:22
Eris::Account::m_status
Status m_status
what the Player is currently doing
Definition: Account.h:295
Eris::Connection::Disconnecting
sigc::signal< bool > Disconnecting
Definition: Connection.h:134
Eris::CharacterMap
std::map< std::string, Atlas::Objects::Entity::RootEntity > CharacterMap
Definition: Account.h:26
Eris::Account::AvatarDeactivated
sigc::signal< void, const std::string & > AvatarDeactivated
Definition: Account.h:224
Eris::Account::m_spawnPoints
std::vector< SpawnPoint > m_spawnPoints
A map of available spawn points. These are points from which a new avatar can be created.
Definition: Account.h:314
Eris::BaseConnection::getStatus
Status getStatus() const
get the current status of the connection
Definition: BaseConnection.h:68
Eris::Connection::send
virtual void send(const Atlas::Objects::Root &obj)
Transmit an Atlas::Objects instance to the server.
Definition: Connection.cpp:160
Eris::Account::Status::LOGGING_IN
@ LOGGING_IN
Login sent, waiting for initial INFO response.
Eris::debug
Definition: LogStream.h:45
Eris::Account::destroyAvatar
void destroyAvatar(const std::string &avatarId)
Destroys the avatar with the specified id, if available.
Definition: Account.cpp:422
Eris::Account::login
Result login(const std::string &uname, const std::string &pwd)
Login to the server using user-supplied account information.
Definition: Account.cpp:114
Eris::Account::logout
Result logout()
Request logout from the server.
Definition: Account.cpp:163
Eris::Account::Status::LOGGED_IN
@ LOGGED_IN
Fully logged into a server-side account.
Eris::Account::createAccount
Result createAccount(const std::string &uname, const std::string &fullName, const std::string &pwd)
Attempt to create a new account on the server and log into it.
Definition: Account.cpp:128
Eris::Connection
Definition: Connection.h:44
Eris::Account::getCharacters
const CharacterMap & getCharacters()
Get the characters owned by this account.
Definition: Account.cpp:194
Eris::Connection::lock
void lock()
Definition: Connection.cpp:217
Eris::Account::createCharacterThroughEntity
Result createCharacterThroughEntity(const Atlas::Objects::Entity::RootEntity &character)
enter the game using a new character
Definition: Account.cpp:235
Eris::Account::netDisconnecting
bool netDisconnecting()
help! the plug is being pulled!
Definition: Account.cpp:687
Eris::Account::LoginSuccess
sigc::signal< void > LoginSuccess
Definition: Account.h:200
Eris::Account::_characters
CharacterMap _characters
characters belonging to this player
Definition: Account.h:303