void ServerInfo::processServer(const RootEntity &svr) { Atlas::Message::Element element; if (!svr->copyAttr("ruleset", element) && element.isString()) { _ruleset = element.String(); } else { return; } _name = svr->getName(); if (!svr->copyAttr("clients", element) && element.isInt()) { _clients = (int)element.Int(); } else { return; } if (!svr->copyAttr("server", element) && element.isString()) { _server = element.String(); } else { return; } if (!svr->copyAttr("uptime", element) && element.isFloat()) { _uptime = element.Float(); } else { return; } m_status = VALID; if (!svr->copyAttr("entities", element) && element.isInt()) { _entities = element.Int(); } if (!svr->copyAttr("version", element) && element.isString()) { m_version = element.String(); } if (!svr->copyAttr("builddate", element) && element.isString()) { m_buildDate = element.String(); } if (!svr->copyAttr("assets", element) && element.isList()) { for (auto& url : element.List()) { if (url.isString()) { m_assets.emplace_back(url.String()); } } } }
Py::Object CyPy_Element::wrap(Atlas::Message::Element value) { if (value.isNone()) { return Py::None(); } else if (value.isString()) { return Py::String(value.String()); } else if (value.isInt()) { return Py::Long(value.Int()); } else if (value.isFloat()) { return Py::Float(value.Float()); } else if (value.isList()) { return CyPy_ElementList::wrap(value.List()); } else { return CyPy_ElementMap::wrap(value.Map()); } }
Py::Object CyPy_Element::asPyObject(const Atlas::Message::Element& obj, bool useNativePythonType) { switch (obj.getType()) { case Element::TYPE_INT: return Py::Long(obj.Int()); case Element::TYPE_FLOAT: return Py::Float(obj.Float()); case Element::TYPE_STRING: return Py::String(obj.String()); case Element::TYPE_MAP: return mapAsPyObject(obj.Map(), useNativePythonType); case Element::TYPE_LIST: return listAsPyObject(obj.List(), useNativePythonType); default: break; } return Py::None(); }
void EntityImporterBase::sendMinds() { if (!mResolvedMindMapping.empty()) { S_LOG_INFO("Sending minds."); for (auto mind : mResolvedMindMapping) { Atlas::Message::MapType message; mind.second->addToMessage(message); Atlas::Message::Element thoughtsElem = message["thoughts"]; Atlas::Message::ListType thoughtArgs; if (thoughtsElem.isList()) { Atlas::Message::ListType thoughtList = thoughtsElem.List(); for (auto& thought : thoughtList) { //If the thought is a list of things the entity owns, we should adjust it with the new entity ids. if (thought.isMap()) { auto& thoughtMap = thought.Map(); if (thoughtMap.count("things") > 0) { auto& thingsElement = thoughtMap.find("things")->second; if (thingsElement.isMap()) { for (auto& thingI : thingsElement.asMap()) { if (thingI.second.isList()) { Atlas::Message::ListType newList; for (auto& thingId : thingI.second.asList()) { if (thingId.isString()) { const auto& entityIdLookupI = mEntityIdMap.find(thingId.asString()); //Check if the owned entity has been created with a new id. If so, replace the data. if (entityIdLookupI != mEntityIdMap.end()) { newList.emplace_back(entityIdLookupI->second); } else { newList.push_back(thingId); } } else { newList.push_back(thingId); } } thingI.second = newList; } } } } if (thoughtMap.count("pending_things") > 0) { //things that the entity owns, but haven't yet discovered are expressed as a list of entity ids auto& pendingThingsElement = thoughtMap.find("pending_things")->second; if (pendingThingsElement.isList()) { Atlas::Message::ListType newList; for (auto& thingId : pendingThingsElement.asList()) { if (thingId.isString()) { const auto& entityIdLookupI = mEntityIdMap.find(thingId.asString()); //Check if the owned entity has been created with a new id. If so, replace the data. if (entityIdLookupI != mEntityIdMap.end()) { newList.emplace_back(entityIdLookupI->second); } else { newList.push_back(thingId); } } else { newList.push_back(thingId); } } pendingThingsElement = newList; } } if (thoughtMap.count("object") > 0) { auto& objectElement = thoughtMap.find("object")->second; if (objectElement.isString()) { std::string& objectString = objectElement.String(); //Other entities are referred to using the syntax "'$eid:...'". //For example, the entity with id 2 would be "'$eid:2'". auto pos = objectString.find("$eid:"); if (pos != std::string::npos) { auto quotePos = objectString.find('\'', pos); if (quotePos != std::string::npos) { auto id = objectString.substr(pos + 5, quotePos - pos - 5); auto I = mEntityIdMap.find(id); if (I != mEntityIdMap.end()) { objectString.replace(pos + 5, quotePos - 7, I->second); } } } } } } thoughtArgs.push_back(thought); } } Atlas::Objects::Operation::RootOperation thinkOp; thinkOp->setParent("think"); thinkOp->setTo(mind.first); //By setting it TO an entity and FROM our avatar we'll make the server deliver it as //if it came from the entity itself (the server rewrites the FROM to be of the entity). thinkOp->setFrom(mAvatarId); thinkOp->setSerialno(newSerialNumber()); Atlas::Objects::Operation::Set setOp; setOp->setArgsAsList(thoughtArgs); thinkOp->setArgs1(setOp); mStats.mindsProcessedCount++; S_LOG_VERBOSE("Restoring mind of " << mind.first); mThoughtOpsInTransit++; sigc::slot<void, const Operation&> slot = sigc::mem_fun(*this, &EntityImporterBase::operationThinkResult); sendAndAwaitResponse(thinkOp, slot); EventProgress.emit(); } mResolvedMindMapping.clear(); } else { complete(); } }
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; }