#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "agent.h" #include "clientConnection.h" #include "stubServer.h" #include "objectSummary.h" #include "testUtils.h" #include #include #include #include #include #include using Atlas::Objects::Root; using Atlas::Objects::smart_dynamic_cast; using namespace Atlas::Objects::Operation; using namespace Eris; using Atlas::Objects::Entity::RootEntity; using Atlas::Objects::Entity::Anonymous; using std::endl; using std::cout; using std::cerr; Agent::StringStringMmap Agent::static_futureVisible; Agent::AgentSet Agent::static_allAgents; Agent::Agent(ClientConnection* con, const std::string& charId) : m_character(charId), m_con(con), m_server(con->getServer()) { static_allAgents.insert(this); m_visible.insert("_world"); m_visible.insert(charId); StringStringMmap::iterator lower = static_futureVisible.lower_bound(charId), upper = static_futureVisible.upper_bound(charId); // load them all in for (; lower != upper; ++lower) m_visible.insert(lower->second); // blow them all away. static_futureVisible.erase(static_futureVisible.lower_bound(charId), upper); } Agent::~Agent() { static_allAgents.erase(this); } void Agent::processOp(const RootOperation& op) { switch (op->getClassNo()) { case LOOK_NO: processLook(smart_dynamic_cast(op)); return; case WIELD_NO: processWield(op); return; default: debug() << "un-handled in-game op"; } } void Agent::setEntityVisible(const std::string& eid, bool vis) { if (vis) { if (m_visible.count(eid) != 0) return; m_visible.insert(eid); if (isVisible(eid)) { Appearance app; app->setFrom(m_character); app->setTo(m_character); Root obj; obj->setId(eid); app->setArgs1(obj); m_con->send(app); } // of Appearance op send } else { if (m_visible.count(eid) == 0) return; bool wasVisible = isVisible(eid); m_visible.erase(eid); bool nowVis = isVisible(eid); if (!nowVis && wasVisible) { Disappearance dap; dap->setFrom(m_character); dap->setTo(m_character); Root obj; obj->setId(eid); dap->setArgs1(obj); m_con->send(dap); } // of disapearance op send } } #pragma mark - void Agent::setEntityVisibleForFutureAgent(const std::string& eid, const std::string& agentId) { static_futureVisible.insert(StringStringMmap::value_type(agentId, eid)); } void Agent::broadcastSight(const RootOperation& op) { Sight st; st->setArgs1(op); st->setFrom(op->getFrom()); for (AgentSet::iterator it=static_allAgents.begin(); it != static_allAgents.end(); ++it) { st->setTo((*it)->m_character); (*it)->m_con->send(st); } } void Agent::broadcastSound(const RootOperation& op) { Sound snd; snd->setArgs1(op); snd->setFrom(op->getFrom()); for (AgentSet::iterator it=static_allAgents.begin(); it != static_allAgents.end(); ++it) { snd->setTo((*it)->m_character); (*it)->m_con->send(snd); } } #pragma mark - void Agent::processLook(const Look& look) { const std::vector& args = look->getArgs(); std::string lookTarget; if (args.empty()) { //cout << "got anonymous IG look" << endl; lookTarget = "_world"; } else { lookTarget = args.front()->getId(); //cout << "IG look at " << lookTarget << endl; } if (m_server->m_world.count(lookTarget) == 0) { m_con->sendError("unknown object ID:" + lookTarget, look); return; } if (!isVisible(lookTarget)) { std::cout << "agent for " << m_character << " got look at invsible entity ID: " << lookTarget << std::endl; return; } typedef std::list StringList; RootEntity ge = m_server->m_world[lookTarget].copy(); StringList contents = ge->getContains(); // prune based on visibility for (StringList::iterator it=contents.begin(); it != contents.end(); ) { if (m_visible.count(*it) == 0) { it = contents.erase(it); } else { ++it; } } ge->setContains(contents); Sight st; st->setArgs1(ge); st->setFrom(lookTarget); st->setTo(look->getFrom()); st->setRefno(look->getSerialno()); m_con->send(st); } bool Agent::isVisible(const std::string& lookTarget) const { if (lookTarget == "_world") return true; // base-case, should be TLVE if (lookTarget == m_character) return true; if (m_visible.count(lookTarget) == 0) return false; std::string locId = m_server->m_world[lookTarget]->getLoc(); return isVisible(locId); // recurse up } void Agent::processWield(const RootOperation& op) { const std::vector& args = op->getArgs(); assert(!args.empty()); m_server->m_world[m_character]->setAttr("right_hand_wield", args.front()->getId()); Set setWield; Anonymous setArgs; setArgs->setId(m_character); setArgs->setAttr("right_hand_wield", args.front()->getId()); setWield->setArgs1(setArgs); setWield->setTo(m_character); broadcastSight(setWield); } #pragma mark - const char* strings[] = { "stilton", "emmental", "tenten", "wendslydale", "cheddar", "edam", "gouda", "brie", "jarlsberg", "canadian extra mature cheddar" }; Atlas::Message::Element randomValue() { switch (random() % 3) { case 0: return Atlas::Message::Element(random() % 10000); case 1: return Atlas::Message::Element(drand48() * 1e6); case 2: return Atlas::Message::Element(strings[random() % 10]); } return Atlas::Message::Element(); } /* void Agent::spam(unsigned int opsToSend) { while (opsToSend--) { } } const char* names[] = { "foo", "bar", "wibble", "stamina", "taupe", "mana", "effervesence", "personality", "moxie", "mojo" }; RootOperation Agent::generateRandomOp() { switch (opType) { case MOVE: { Move mv; mv->setFrom(randomVisibleEntity()); Root arg; std::vector arg->setAttr("pos"); // some % of the time, change a loc arg->setAttr("loc", randomVisibleEntity()); Sight; sight->setArgs1(mv); return sight; } case SET: Set st; st->setFrom(randomVisibleEntity()); Root arg; arg->setId(st->getFrom()); unsigned int attrCount = random() % 10; while (--attrCount) arg->setAttr(names[attrCount], randomValue()); st->setArgs1(arg); broadcastSight(st); break; case APPEAR: setEntityVisible(randomInvisibleEntity(), true); break; case DISAPPEAR: setEntityVisible(randomVisibleEntity(), false); break; } // of switch } */ std::string Agent::randomVisibleEntity() const { unsigned int tries = 100; while (--tries) { unsigned index = random() % m_visible.size(); EntityIdSet::const_iterator it = m_visible.begin(); while (--index) ++it; // yech if (*it == "_world") continue; if (*it == m_character) continue; // check proper visibility (i.e parent chain) if (isVisible(*it)) return *it; } return std::string(); } std::string Agent::randomInvisibleEntity() const { unsigned int tries = 100; while (--tries) { StubServer::EntityMap::const_iterator it = m_server->m_world.begin(); unsigned int index = random() % m_server->m_world.size(); while (--index) ++it; if (!isVisible(it->first)) return it->first; } return std::string(); }