예제 #1
0
void World::LookOperation(const Operation & op, OpVector & res)
{
    // We must be the top level entity
    assert(m_location.m_parent == nullptr);
    // We must contains something, or where the hell did the look come from?
    assert(m_contains != nullptr);

    //The top level entity is a little special, since its properties can be inspected by all entities, although it's children can not.
    //First check if there's a movement domain. If so we'll handle Look ops just like usually. However, if not we'll send the properties sans the "contains" property.
    auto from = BaseWorld::instance().getEntity(op->getFrom());
    if (!from) {
        log(ERROR, String::compose("Look op has invalid from %1. %2", op->getFrom(), describeEntity()));
        return;
    }

    Domain* domain = nullptr;
    if (m_location.m_parent) {
        domain = m_location.m_parent->getDomain();
    }
    if (domain) {
        generateSightOp(*from, op, res);
    } else {
        Sight s;

        Anonymous sarg;
        addToEntity(sarg);
        //Hide all contents of the root entity.
        sarg->removeAttr("contains");
        s->setArgs1(sarg);
        s->setTo(op->getFrom());
        res.push_back(s);
    }
}
예제 #2
0
void World::RelayOperation(const Operation & op, OpVector & res)
{
    //A Relay operation with refno sent to ourselves signals that we should prune
    //our registered relays in m_relays. This is a feature to allow for a timeout; if
    //no Relay has been received from the destination Entity after a certain period
    //we'll shut down the relay link.
    if (op->getTo() == getId() && op->getFrom() == getId() && !op->isDefaultRefno()) {
        auto I = m_relays.find(op->getRefno());
        if (I != m_relays.end()) {

            //Send an empty operation to signal that the relay has expired.
            I->second.callback(Operation(), I->second.entityId);
            m_relays.erase(I);
        }
    } else {
        if (op->getArgs().empty()) {
            log(ERROR, "World::RelayOperation no args.");
            return;
        }
        Operation relayedOp = Atlas::Objects::smart_dynamic_cast<Operation>(
                op->getArgs().front());

        if (!relayedOp.isValid()) {
            log(ERROR,
                    "World::RelayOperation first arg is not an operation.");
            return;
        }


        //If a relay op has a refno, it's a response to a Relay op previously sent out to another
        //entity, and we should signal that we have an incoming relayed op.
        if (!op->isDefaultRefno()) {
            //Note that the relayed op should be considered untrusted in this case, as it has originated
            //from a random entity or its mind.
            auto I = m_relays.find(op->getRefno());
            if (I == m_relays.end()) {
                log(WARNING,
                        "World::RelayOperation could not find registrered Relay with refno.");
                return;
            }

            //Make sure that this op really comes from the entity the original Relay op was sent to.
            if (op->getFrom() != I->second.entityId) {
                log(WARNING,
                        "World::RelayOperation got relay op with mismatching 'from'.");
                return;
            }

            //Get the relayed operation and call the callback.
            I->second.callback(relayedOp, I->second.entityId);

            m_relays.erase(I);

        } else {
            //Send it on to the basic Entity relay mechanism
            Entity::RelayOperation(op, res);
        }
    }

}
예제 #3
0
/// \brief Handle a relay operation
void Entity::RelayOperation(const Operation & op, OpVector & res)
{
    if (op->getArgs().empty()) {
        log(ERROR, "Entity::RelayOperation no args.");
        return;
    }
    Operation relayedOp = Atlas::Objects::smart_dynamic_cast<Operation>(
            op->getArgs().front());

    if (!relayedOp.isValid()) {
        log(ERROR,
                "Entity::RelayOperation first arg is not an operation.");
        return;
    }

    if (op->isDefaultSerialno()) {
        log(ERROR, "Entity::RelayOperation no serial number.");
        return;
    }

    //Add a sight of the operation
    Sight sight;
    sight->setArgs1(relayedOp);

    Atlas::Objects::Operation::Generic responseOp;
    responseOp->setType("relay", Atlas::Objects::Operation::RELAY_NO);
    responseOp->setArgs1(sight);
    responseOp->setTo(op->getFrom());
    res.push_back(responseOp);

    //Make sure that the contained op is addressed to the entity
    relayedOp->setTo(getId());
    operation(relayedOp, res);

}
예제 #4
0
void World::EatOperation(const Operation & op, OpVector & res)
{
    const std::string & from_id = op->getFrom();
    Entity * from = BaseWorld::instance().getEntity(from_id);
    if (from == 0) {
        log(ERROR, String::compose("World got eat op from non-existant "
                                   "entity %1.", from_id));
        return;
    }

    TerrainProperty * tp = modPropertyClass<TerrainProperty>("terrain");
    if (tp == 0) {
        log(ERROR, "No terrain in getSurface");
        return;
    }
    Point3D from_pos = relativePos(m_location, from->m_location);
    int material;
    if (tp->getSurface(from_pos, material) != 0) {
        debug(std::cout << "no surface hit" << std::endl << std::flush;);
예제 #5
0
/// \brief Add an operation to the ordered op queue.
///
/// Any time adjustment required is made to the operation, and it
/// is added to the apropriate place in the chronologically ordered
/// queue. The From attribute of the operation is set to the id of
/// the entity that is responsible for adding the operation to the
/// queue.
void OperationsDispatcher::addOperationToQueue(const Operation & op, LocatedEntity & ent)
{
    assert(op.isValid());
    assert(op->getFrom() != "cheat");

    m_operation_queues_dirty = true;
    op->setFrom(ent.getId());
    if (!op->hasAttrFlag(Atlas::Objects::Operation::FUTURE_SECONDS_FLAG)) {
        op->setSeconds(getTime());
        m_immediateQueue.push(OpQueEntry(op, ent));
        return;
    }
    double t = getTime() + (op->getFutureSeconds() * consts::time_multiplier);
    op->setSeconds(t);
    op->setFutureSeconds(0.);
    m_operationQueue.push(OpQueEntry(op, ent));
    if (debug_flag) {
        std::cout << "WorldRouter::addOperationToQueue {" << std::endl;
        debug_dump(op, std::cout);
        std::cout << "}" << std::endl << std::flush;
    }
}
예제 #6
0
void Interactive::exec(const std::string & cmd, const std::string & arg)
{
    bool reply_expected = true;
    reply_flag = false;
    error_flag = false;

    boost::shared_ptr<ObjectContext> command_context = m_currentContext.lock();
    if (!command_context) {
        std::cout << "ERROR: Context free" << std::endl << std::flush;
        return;
    }

    if (cmd == "stat") {
        Get g;
        send(g);
    } else if (cmd == "install") {
        size_t space = arg.find(' ');
        if (space == std::string::npos || space >= (arg.size() - 1)) {
            std::cout << "usage: install <type id> <parent id>"
                      << std::endl << std::flush;
        } else {
            Create c;
            c->setFrom(m_accountId);
            Anonymous ent;
            ent->setId(std::string(arg, 0, space));
            ent->setObjtype("class");
            ent->setParents(std::list<std::string>(1, std::string(arg, space + 1)));
            c->setArgs1(ent);
            send(c);
        }
        reply_expected = false;
    } else if (cmd == "look") {
        Look l;
        if (!arg.empty()) {
            Anonymous cmap;
            cmap->setId(arg);
            l->setArgs1(cmap);
        }
        l->setSerialno(newSerialNo());
        command_context->setFromContext(l);
        send(l);
        reply_expected = false;
    } else if (cmd == "logout") {
        Logout l;
        l->setFrom(m_accountId);
        if (!arg.empty()) {
            Anonymous lmap;
            lmap->setId(arg);
            l->setArgs1(lmap);
            reply_expected = false;
        }
        send(l);
    } else if (cmd == "say") {
        Talk t;
        Anonymous ent;
        ent->setAttr("say", arg);
        t->setArgs1(ent);
        t->setFrom(m_accountId);
        send(t);
    } else if (cmd == "help" || cmd == "?") {
        reply_expected = false;
        help();
    } else if (cmd == "query") {
        Get g;

        if (!arg.empty()) {
            Anonymous cmap;
            if (::isdigit(arg[0])) {
                cmap->setObjtype("obj");
            } else {
                cmap->setObjtype("meta");
            }
            cmap->setId(arg);
            g->setArgs1(cmap);
        }
        g->setFrom(m_accountId);

        send(g);
    } else if (cmd == "reload") {
        if (arg.empty()) {
            reply_expected = false;
            std::cout << "reload: Argument required" << std::endl << std::flush;
        } else {
            Set s;

            Anonymous tmap;
            tmap->setObjtype("class");
            tmap->setId(arg);
            s->setArgs1(tmap);
            s->setFrom(m_accountId);

            send(s);
        }
    } else if (cmd == "get") {
        Get g;

        if (!arg.empty()) {
            Anonymous cmap;
            if (::isdigit(arg[0])) {
                cmap->setObjtype("obj");
            } else {
                cmap->setObjtype("meta");
            }
            cmap->setId(arg);
            g->setArgs1(cmap);
        }
        g->setFrom(m_accountId);

        send(g);
    } else if (cmd == "monitor") {
        ClientTask * task = new OperationMonitor;
        if (runTask(task, arg) == 0) {
            Monitor m;

            m->setArgs1(Anonymous());
            m->setFrom(m_accountId);

            send(m);
        }

        reply_expected = false;
    } else if (cmd == "unmonitor") {
        OperationMonitor * om = dynamic_cast<OperationMonitor *>(m_currentTask);

        if (om != 0) {
            Monitor m;

            m->setFrom(m_accountId);

            send(m);

            reply_expected = false;

            SystemTime now;
            now.update();

            time_t monitor_time = now.seconds() - om->startTime();

            std::cout << om->count() << " operations monitored in "
                      << monitor_time << " seconds = "
                      << om->count() / monitor_time
                      << " operations per second"
                      << std::endl << std::flush;

            endTask();
        }
    } else if (cmd == "connect") {
        std::vector<std::string> args;
        tokenize(arg, args);

        if (args.size() != 2) {
            std::cout << "usage: connect <hostname> <port>"
                      << std::endl << std::flush;

            reply_expected = false;
        } else {
            Anonymous cmap;
            cmap->setAttr("hostname", args[0]);
            cmap->setAttr("port", strtol(args[1].c_str(), 0, 10));

            Connect m;
            m->setArgs1(cmap);
            // No serialno yet
            // FIXME add serialno once Juncture context can handle this

            command_context->setFromContext(m);

            send(m);
        }
    } else if (cmd == "add_agent") {
        std::string agent_type("creator");

        if (!arg.empty()) {
            agent_type = arg;
        }
        
        Create c;

        Anonymous cmap;
        cmap->setParents(std::list<std::string>(1, agent_type));
        cmap->setName("cycmd agent");
        cmap->setObjtype("obj");
        c->setArgs1(cmap);
        c->setSerialno(newSerialNo());

        command_context->setFromContext(c);

        send(c);
    } else if (cmd == "delete") {
        if (arg.empty()) {
            std::cout << "Please specify the entity to delete" << std::endl << std::flush;
            reply_expected = false;
        } else {
            Delete del;

            Anonymous del_arg;
            del_arg->setId(arg);
            del->setArgs1(del_arg);

            command_context->setFromContext(del);

            send(del);

            reply_expected = false;
        }
    } else if (cmd == "find_by_name") {
        if (arg.empty()) {
            std::cout << "Please specify the name to search for" << std::endl << std::flush;
            reply_expected = false;
        } else {
            Look l;

            Anonymous lmap;
            lmap->setName(arg);
            l->setArgs1(lmap);
            l->setSerialno(newSerialNo());

            command_context->setFromContext(l);

            send(l);

            reply_expected = false;
        }
    } else if (cmd == "find_by_type") {
        if (arg.empty()) {
            std::cout << "Please specify the type to search for" << std::endl << std::flush;
            reply_expected = false;
        } else {
            Look l;

            Anonymous lmap;
            lmap->setParents(std::list<std::string>(1, arg));
            l->setArgs1(lmap);
            l->setSerialno(newSerialNo());

            command_context->setFromContext(l);

            send(l);

            reply_expected = false;
        }
    } else if (cmd == "flush") {
        if (arg.empty()) {
            // FIXME usage
            std::cout << "Please specify the type to flush" << std::endl << std::flush;
            reply_expected = false;
        } else {
            ClientTask * task = new Flusher(command_context);
            runTask(task, arg);
            reply_expected = false;
        }
    } else if (cmd == "cancel") {
        if (endTask() != 0) {
            std::cout << "No task currently running" << std::endl << std::flush;
        }
    } else if (cmd == "dump") {
        if (command_context->repr() != "avatar") {
            std::cout << "You must have an agent in the world in order to dump the world." << std::endl << std::flush;
        } else {
            //Extract the avatar id by "misusing" the setFromContext method
            Operation op;
            command_context->setFromContext(op);
            ClientTask * task = new EntityExporter(m_accountId, op->getFrom());
            runTask(task, "world.xml");
            reply_expected = false;
        }
    } else if (cmd == "restore") {
        if (command_context->repr() != "avatar") {
            std::cout << "You must have an agent in the world in order to dump the world." << std::endl << std::flush;
        } else {
            //Extract the avatar id by "misusing" the setFromContext method
            Operation op;
            command_context->setFromContext(op);
            ClientTask * task = new EntityImporter(m_accountId, op->getFrom());
            runTask(task, "world.xml");
            reply_expected = false;
        }
    } else if (cmd == "create") {
        std::vector<std::string> args;
        tokenize(arg, args);

        if (args.size() < 1) {
            std::cout << "usage: create <type> <params> ... "
                      << std::endl << std::flush;
        } else {
            Anonymous cmap;
            cmap->setParents(std::list<std::string>(1, args[0]));
            cmap->setObjtype("obj");

            Create c;
            c->setArgs1(cmap);
            c->setSerialno(newSerialNo());
            command_context->setFromContext(c);

            send(c);
        }
        reply_expected = false;
    } else if (cmd == "login") {
        std::vector<std::string> args;
        tokenize(arg, args);

        if (args.size() != 2) {
            std::cout << "usage: login <username> <password>"
                      << std::endl << std::flush;
            reply_expected = false;
        } else {
            Anonymous cmap;
            cmap->setAttr("username", args[0]);
            cmap->setAttr("password", args[1]);

            Login m;
            m->setArgs1(cmap);
            m->setSerialno(newSerialNo());

            command_context->setFromContext(m);

            send(m);
        }
    } else {
        reply_expected = false;
        std::cout << cmd << ": Command not known" << std::endl << std::flush;
    }

    if (!reply_expected) {
        updatePrompt();
        return;
    }
    // Wait for reply
    time_t wait_start_time = time(NULL);
    while (!reply_flag) {
       if (time(NULL) - wait_start_time > 5) {
           std::cout << cmd << ": No reply from server" << std::endl << std::flush;
           return;
       }
       if (select(false) != 0) {
           return;
       }
    }
}
예제 #7
0
HandlerResult UsagesProperty::use_handler(LocatedEntity* e,
                                          const Operation& op, OpVector& res)
{


    auto actor = BaseWorld::instance().getEntity(op->getFrom());
    if (!actor) {
        e->error(op, "Could not find 'from' entity.", res, e->getId());
        return OPERATION_IGNORED;
    }

    if (op->isDefaultFrom()) {
        actor->error(op, "Top op has no 'from' attribute.", res, actor->getId());
        return OPERATION_IGNORED;
    }

    if (!op->getArgs().empty()) {
        auto& arg = op->getArgs().front();
        auto argOp = smart_dynamic_cast<Atlas::Objects::Operation::RootOperation>(arg);
        if (!argOp) {
            actor->error(op, "First arg wasn't an operation.", res, actor->getId());
            return OPERATION_IGNORED;
        }


        if (!argOp->hasAttrFlag(Atlas::Objects::PARENT_FLAG)) {
            actor->error(op, "Use arg op has malformed parent", res, actor->getId());
            return OPERATION_IGNORED;
        }
        auto op_type = argOp->getParent();
        debug_print("Got op type " << op_type << " from arg");

        auto obj = Atlas::Objects::Factories::instance()->createObject(op_type);
        if (!obj.isValid()) {
            log(ERROR, String::compose("Character::UseOperation Unknown op type "
                                       "\"%1\".", op_type));
            return OPERATION_IGNORED;
        }

        auto rop = smart_dynamic_cast<Operation>(obj);
        if (!rop.isValid()) {
            log(ERROR, String::compose("Character::UseOperation Op type "
                                       "\"%1\" but it is not an operation type. ", op_type));
            return OPERATION_IGNORED;
        }
        rop->setFrom(actor->getId());
        rop->setTo(e->getId());
        rop->setSeconds(op->getSeconds());

        if (argOp->getArgs().empty()) {
            actor->error(op, "Use arg op has no arguments; one expected.", res, actor->getId());
            return OPERATION_IGNORED;
        }

        auto arguments = argOp->getArgs().front();

        //Check that there's an action registered for this operation
        auto usagesI = m_usages.find(op_type);
        if (usagesI != m_usages.end()) {
            auto& usage = usagesI->second;

            //Check that the tool is ready
            auto toolReadyAtProp = e->getPropertyType<double>("ready_at");
            if (toolReadyAtProp) {
                if (toolReadyAtProp->data() > BaseWorld::instance().getTime()) {
                    actor->clientError(op, "Tool is not ready yet.", res, actor->getId());
                    return OPERATION_IGNORED;
                }
            }

            //Check if the tools is attached, and if so the attachment is ready
            auto actorReadyAtProp = actor->getPropertyType<MapType>("_ready_at_attached");
            if (actorReadyAtProp) {

                auto plantedOnProp = e->getPropertyClassFixed<PlantedOnProperty>();
                //First check if the tool is attached to the actor at an attach point
                if (plantedOnProp && plantedOnProp->data().entity.get() == actor.get() && plantedOnProp->data().attachment) {
                    auto attachPoint = *plantedOnProp->data().attachment;
                    //Lastly check if there's a value for this attach point.
                    auto attachI = actorReadyAtProp->data().find(attachPoint);
                    if (attachI != actorReadyAtProp->data().end()) {
                        if (attachI->second.isFloat() && attachI->second.Float() > BaseWorld::instance().getTime()) {
                            actor->clientError(op, "Actor is not ready yet.", res, actor->getId());
                            return OPERATION_IGNORED;
                        }
                    }
                }
            }

            //Populate the usage arguments
            std::map<std::string, std::vector<UsageInstance::UsageArg>> usage_instance_args;

            for (auto& param : usage.params) {
                Atlas::Message::Element element;
                if (arguments->copyAttr(param.first, element) != 0 || !element.isList()) {
                    actor->clientError(op, String::compose("Could not find required list argument '%1'.", param.first), res, actor->getId());
                    return OPERATION_IGNORED;
                }

                auto& argVector = usage_instance_args[param.first];

                for (auto& argElement : element.List()) {
                    switch (param.second.type) {
                        case UsageParameter::Type::ENTITY: {
                            if (!argElement.isMap()) {
                                actor->clientError(op, String::compose("Inner argument in list of arguments for '%1' was not a map.", param.first), res, actor->getId());
                                return OPERATION_IGNORED;
                            }
                            //The arg is for an RootEntity, expressed as a message. Extract id and pos.
                            auto idI = argElement.Map().find("id");
                            if (idI == argElement.Map().end() || !idI->second.isString()) {
                                actor->clientError(op, String::compose("Inner argument in list of arguments for '%1' had no id string.", param.first), res, actor->getId());
                                return OPERATION_IGNORED;
                            }

                            auto involved = BaseWorld::instance().getEntity(idI->second.String());
                            if (!involved) {
                                actor->error(op, "Involved entity does not exist", res, actor->getId());
                                return OPERATION_IGNORED;
                            }

                            auto posI = argElement.Map().find("pos");
                            if (posI != argElement.Map().end() && posI->second.isList()) {
                                argVector.emplace_back(EntityLocation(involved, WFMath::Point<3>(posI->second)));
                            } else {
                                argVector.emplace_back(EntityLocation(involved));
                            }
                        }
                            break;
                        case UsageParameter::Type::ENTITYLOCATION:
                            argVector.emplace_back(WFMath::Point<3>(argElement));
                            break;
                        case UsageParameter::Type::POSITION:
                            argVector.emplace_back(WFMath::Point<3>(argElement));
                            break;
                        case UsageParameter::Type::DIRECTION:
                            argVector.emplace_back(WFMath::Vector<3>(argElement));
                            break;
                    }
                }

            }


            UsageInstance usageInstance{usage, actor, e, std::move(usage_instance_args), rop};
            //Check that the usage is valid before continuing
            auto validRes = usageInstance.isValid();
            if (!validRes.first) {
                actor->clientError(op, validRes.second, res, actor->getId());
            } else {
                auto lastSeparatorPos = usage.handler.find_last_of('.');
                if (lastSeparatorPos != std::string::npos) {
                    auto moduleName = usage.handler.substr(0, lastSeparatorPos);
                    auto functionName = usage.handler.substr(lastSeparatorPos + 1);
                    //Py::Module module(moduleName);
                    Py::Module module(PyImport_Import(Py::String(moduleName).ptr()));
                    //PyImport_ReloadModule(module.ptr());
                    auto functionObject = module.getDict()[functionName];
                    if (!functionObject.isCallable()) {
                        actor->error(op, String::compose("Could not find Python function %1", usage.handler), res, actor->getId());
                        return OPERATION_IGNORED;
                    }

                    try {

                        PythonLogGuard logGuard([functionName, actor]() {
                            return String::compose("Usage '%1', entity %2: ", functionName, actor->describeEntity());
                        });
                        auto ret = Py::Callable(functionObject).apply(Py::TupleN(UsageInstance::scriptCreator(std::move(usageInstance))));
                        return ScriptUtils::processScriptResult(usage.handler, ret, res, e);
                    } catch (const Py::BaseException& py_ex) {
                        log(ERROR, String::compose("Python error calling \"%1\" for entity %2", usage.handler, e->describeEntity()));
                        if (PyErr_Occurred()) {
                            PyErr_Print();
                        }
                    }
                }
            }
            return OPERATION_BLOCKED;

        }
    }
    //We couldn't find any suitable task.
    return OPERATION_IGNORED;
}
예제 #8
0
void OperationMonitor::operation(const Operation & op, OpVector &) {
    ++op_count;
    std::cout << op->getParents().front() << "(from=\"" << op->getFrom()
              << "\",to=\"" << op->getTo() << "\")"
              << std::endl << std::flush;
}