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
25using Atlas::Objects::Root;
26using Atlas::Message::Element;
27using namespace Atlas::Objects::Operation;
28using Atlas::Objects::Entity::RootEntity;
29using Atlas::Objects::Entity::Anonymous;
30typedef Atlas::Objects::Entity::Account AtlasAccount;
31using Atlas::Objects::smart_dynamic_cast;
32
33namespace Eris {
34
35class AccountRouter : public Router {
36public:
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
85private:
86 Account* m_account;
87};
88
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
98Account::~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
114Result 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
128Result 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
144Result 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
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;
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
235Result 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
246Result Account::createCharacterThroughOperation(const Create& c) {
247 if (!m_con.isConnected()) return NOT_CONNECTED;
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
267Result Account::takeTransferredCharacter(const std::string& id, const std::string& key) {
268 if (!m_con.isConnected()) return NOT_CONNECTED;
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
296Result 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
325 return ((m_status == Status::LOGGED_IN) ||
327}
328
329Result Account::internalLogin(const std::string& uname, const std::string& pwd) {
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
351void 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
358void 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
379void 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
389void Account::loginComplete(const AtlasAccount& p) {
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
422void 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
431void 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
542void Account::loginError(const Error& err) {
543 if (!err) {
544 warning() << "Got invalid error";
545 return;
546 }
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
560void Account::handleLoginTimeout() {
562 m_timeout.reset();
563
564 LoginFailure.emit("timed out waiting for server response");
565}
566
567void 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
620void 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
630void 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
639void 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()) {
670 GotAllCharacters.emit();
671 }
672}
673
674/* this will only ever get encountered after the connection is initally up;
675thus we use it to trigger a reconnection. Note that some actions by
676Lobby and World are also required to get everything back into the correct
677state */
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
689 m_con.lock();
690 logout();
691 return false;
692 } else
693 return true;
694}
695
696void Account::netFailure(const std::string& /*msg*/) {
697
698}
699
700void Account::handleLogoutTimeout() {
701 error() << "LOGOUT timed out waiting for response";
702
704 m_timeout.reset();
705
706 LogoutComplete.emit(false);
707}
708
709void 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
Encapsulates all the state of an Atlas Account, and methods that operation on that state.
Definition: Account.h:42
CharacterMap _characters
characters belonging to this player
Definition: Account.h:303
Result refreshCharacterInfo()
Definition: Account.cpp:201
@ LOGGED_IN
Fully logged into a server-side account.
@ CREATED_CHAR
a character was created, we now need to possess it
@ DISCONNECTED
Default state, no server account active.
@ LOGGING_IN
Login sent, waiting for initial INFO response.
@ LOGGING_OUT
Sent a logout op, waiting for the INFO response.
@ CREATING_CHAR
send a character CREATE op, awaiting INFO response
@ TAKING_CHAR
sent a LOOK op for a character, awaiting INFO response
sigc::signal< void, const std::string & > AvatarDeactivated
Definition: Account.h:224
Result createCharacterThroughEntity(const Atlas::Objects::Entity::RootEntity &character)
enter the game using a new character
Definition: Account.cpp:235
Status m_status
what the Player is currently doing
Definition: Account.h:295
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
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
Result logout()
Request logout from the server.
Definition: Account.cpp:163
Connection & m_con
underlying connection instance
Definition: Account.h:294
sigc::signal< void, const std::string & > LoginFailure
Emitted when a server-side error occurs during account creation / login.
Definition: Account.h:197
sigc::signal< void > GotAllCharacters
emitted when the entire character list had been updated
Definition: Account.h:190
void destroyAvatar(const std::string &avatarId)
Destroys the avatar with the specified id, if available.
Definition: Account.cpp:422
const std::string & getId() const
returns the account ID if logged in
Definition: Account.h:325
void avatarLogoutRequested(Avatar *avatar)
Called when a logout of the avatar has been requested by the server.
Definition: Account.cpp:418
sigc::signal< void > LoginSuccess
Definition: Account.h:200
Connection & getConnection() const
Access the underlying Connection for this account.
Definition: Account.h:338
sigc::signal< void, const std::string & > ErrorMessage
Definition: Account.h:229
sigc::signal< void, bool > LogoutComplete
Emitted when a logout completes.
Definition: Account.h:207
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
Result takeCharacter(const std::string &id)
Enter the game using an existing character.
Definition: Account.cpp:296
sigc::signal< void, const Atlas::Objects::Entity::RootEntity & > GotCharacterInfo
emitted when a character has been retrieved from the server
Definition: Account.h:187
bool netDisconnecting()
help! the plug is being pulled!
Definition: Account.cpp:687
void netConnected()
Callback for network re-establishment.
Definition: Account.cpp:679
bool isLoggedIn() const
Check if the account is logged in.
Definition: Account.cpp:324
Result login(const std::string &uname, const std::string &pwd)
Login to the server using user-supplied account information.
Definition: Account.cpp:114
const CharacterMap & getCharacters()
Get the characters owned by this account.
Definition: Account.cpp:194
std::string m_username
The player's username ( != account object's ID)
Definition: Account.h:299
sigc::signal< void, const std::string & > AvatarFailure
Definition: Account.h:219
std::string m_accountId
the account ID
Definition: Account.h:298
bool m_doingCharacterRefresh
set if we're refreshing character data
Definition: Account.h:305
Account(Connection &con)
Create a new Account associated with a Connection object.
Definition: Account.cpp:89
sigc::signal< void, Avatar * > AvatarSuccess
Definition: Account.h:213
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
sigc::signal< void > Connected
sent on successful negotiation of a game server connection
bool isConnected() const
Ascertain whether or not the connection is usable for transport.
Status getStatus() const
get the current status of the connection
@ DISCONNECTING
clean disconnection in progress
sigc::signal< bool > Disconnecting
Definition: Connection.h:134
virtual void send(const Atlas::Objects::Root &obj)
Transmit an Atlas::Objects instance to the server.
Definition: Connection.cpp:160
sigc::signal< void, const std::string & > Failure
Definition: Connection.h:142
Definition: Account.cpp:33
Result
Definition: Types.h:23
@ ALREADY_LOGGED_IN
Occurs when trying to log in to an Account which is already logged in.
Definition: Types.h:29
@ NOT_LOGGED_IN
Occurs when performing an operation that requires a valid server login.
Definition: Types.h:27
std::int64_t getNewSerialno()
operation serial number sequencing
Definition: Connection.cpp:390
std::map< std::string, Atlas::Objects::Entity::RootEntity > CharacterMap
Definition: Account.h:29