void HostedObject::disconnectFromSpace(const SpaceID &spaceID, const ObjectReference& oref) { if (stopped()) { HO_LOG(detailed,"Ignoring disconnection request after system stop requested."); return; } SpaceObjectReference sporef(spaceID, oref); Mutex::scoped_lock locker(presenceDataMutex); PresenceDataMap::iterator where; where=mPresenceData.find(sporef); if (where!=mPresenceData.end()) { // Need to actually send a disconnection request to the space. Note that // this occurse *before* getting rid of the other data so callbacks // invoked as a result still work. mObjectHost->disconnectObject(spaceID,oref); delete where->second; mPresenceData.erase(where); mObjectHost->unregisterHostedObject(sporef, this); } else { SILOG(cppoh,error,"Attempting to disconnect from space "<<spaceID<<" and object: "<< oref<<" when not connected to it..."); } }
void TimerSpeedBenchmark::start() { mForceStop = false; // Check throughput of timer calls Time start_time = Timer::now(); Time dummy_t = Time::null(); for(uint32 ii = 0; ii < ITERATIONS && !mForceStop; ii++) dummy_t = Timer::now(); if (mForceStop) return; Time end_time = Timer::now(); Duration dur = end_time - start_time; SILOG(benchmark,info, ITERATIONS << " timer invokations, " << dur << ": " << (dur.toMicroseconds()*1000/float(ITERATIONS)) << "ns/call, " << float(ITERATIONS)/dur.toSeconds() << " calls/s"); notifyFinished(); }
void CassandraStorage::StorageAction::execute(const Bucket& bucket, Columns* columns, Keys* eraseKeys, Keys* readKeys, const String& timestamp) { switch(type) { case Read: { (*readKeys).push_back(key); } break; case Write: { Column col = libcassandra::createColumn(key, *value); (*columns).push_back(col); } break; case Erase: { (*eraseKeys).push_back(key); } break; case Error: SILOG(cassandra-storage, fatal, "Tried to execute an invalid StorageAction."); break; }; }
Broadcast::BroadcastStream *Broadcast::establishBroadcast(const Network::Address&addy, const UUID&name, const std::tr1::function<void(BroadcastStream*, Network::Stream::ConnectionStatus, const std::string&reason)>& cb) { Broadcast::BroadcastStream * retval=NULL; Network::Stream*newBroadcastStream=NULL; while(newBroadcastStream==NULL) { boost::lock_guard<boost::mutex>lok(*mUniqueLock); std::tr1::weak_ptr<Network::Stream>*weak_topLevelStream=&mTopLevelStreams[addy]; std::tr1::shared_ptr<Network::Stream> topLevelStream; if ((topLevelStream=weak_topLevelStream->lock())) { }else{ std::tr1::shared_ptr<Network::Stream> tlstemp(Network::StreamFactory::getSingleton().getDefaultConstructor()(mIOService)); (topLevelStream=tlstemp)->connect(addy,&Network::Stream::ignoreSubstreamCallback,&Network::Stream::ignoreConnectionStatus,&Network::Stream::ignoreBytesReceived); *weak_topLevelStream=tlstemp; } newBroadcastStream=topLevelStream->clone(std::tr1::bind(&BroadcastStreamCallbacks::setBroadcastStreamCallbacks, retval=new BroadcastStream(topLevelStream,NULL), cb, _1, _2)); if (newBroadcastStream){ *weak_topLevelStream=topLevelStream; }else { if (mTopLevelStreams.find(addy)!=mTopLevelStreams.end()) { mTopLevelStreams.erase(mTopLevelStreams.find(addy)); } SILOG(broadcast,warning,"Toplevel stream failed to clone for address "<<addy.getHostName()<<':'<<addy.getService()); } } initiateHandshake(retval,addy,name); return retval; }
inline void execute_finished(std::tr1::shared_ptr<RemoteFileMetadata> response, ExecuteFinished cb) { mRemoteFileMetadata = response; cb(); SILOG(transfer, detailed, "done MetadataRequest execute_finished"); }
void HostedObject::handleProximityUpdate(const SpaceObjectReference& spaceobj, const Sirikata::Protocol::Prox::ProximityUpdate& update) { HostedObject* self = this; SpaceID space = spaceobj.space(); ProxyManagerPtr proxy_manager = self->getProxyManager(spaceobj.space(),spaceobj.object()); if (!proxy_manager) { HO_LOG(warn,"Hosted Object received a message for a presence without a proxy manager."); return; } for(int32 aidx = 0; aidx < update.addition_size(); aidx++) { Sirikata::Protocol::Prox::ObjectAddition addition = update.addition(aidx); ProxProtocolLocUpdate add(addition); SpaceObjectReference proximateID(spaceobj.space(), add.object()); TimedMotionVector3f loc(add.locationWithLocalTime(this, spaceobj.space())); CONTEXT_OHTRACE(prox, spaceobj.object().getAsUUID(), //getUUID(), addition.object(), true, loc ); TimedMotionQuaternion orient(add.orientationWithLocalTime(this, spaceobj.space())); BoundingSphere3f bnds = add.bounds(); String mesh = add.meshOrDefault(); String phy = add.physicsOrDefault(); bool isAggregate = (addition.type() == Sirikata::Protocol::Prox::ObjectAddition::Aggregate) ? true : false; ProxyObjectPtr proxy_obj = proxy_manager->getProxyObject(proximateID); if (!proxy_obj) { Transfer::URI meshuri; if (addition.has_mesh()) meshuri = Transfer::URI(addition.mesh()); // FIXME use weak_ptr instead of raw uint64 proxyAddSeqNo = add.location_seqno(); assert( add.location_seqno() == add.orientation_seqno() && add.location_seqno() == add.bounds_seqno() && add.location_seqno() == add.mesh_seqno() && add.location_seqno() == add.physics_seqno()); proxy_obj = self->createProxy(proximateID, spaceobj, meshuri, loc, orient, bnds, phy, "", isAggregate, proxyAddSeqNo); } else { // We need to handle optional values properly -- they // shouldn't get overwritten. String* mesh_ptr = (addition.has_mesh() ? &mesh : NULL); String* phy_ptr = (addition.has_physics() ? &phy : NULL); self->processLocationUpdate(space, proxy_obj, false, &loc, add.location_seqno(), &orient, add.orientation_seqno(), &bnds, add.bounds_seqno(), mesh_ptr, add.mesh_seqno(), phy_ptr, add.physics_seqno() ); } // Always mark the object as valid (either revalidated, or just // valid for the first time) if (proxy_obj) proxy_obj->validate(); //tells the object script that something that was close has come //into view if(self->mObjectScript) self->mObjectScript->notifyProximate(proxy_obj,spaceobj); } for(int32 ridx = 0; ridx < update.removal_size(); ridx++) { Sirikata::Protocol::Prox::ObjectRemoval removal = update.removal(ridx); SpaceObjectReference removed_obj_ref(spaceobj.space(), ObjectReference(removal.object())); bool permanent = (removal.has_type() && (removal.type() == Sirikata::Protocol::Prox::ObjectRemoval::Permanent)); if (removed_obj_ref == spaceobj) { // We want to ignore removal of ourself -- we should // always be in our result set, and we don't want to // delete our own proxy. SILOG(oh,detailed,"Ignoring self removal from proximity results."); } else { ProxyObjectPtr proxy_obj = proxy_manager->getProxyObject(removed_obj_ref); if (proxy_obj) { // NOTE: We *don't* reset the proxy object // here. Resetting it puts the seqnos back at 0, // but if we get an addition while still on this // space server, we actually want the old ones to // stay in place, in case of unordered prox/loc // updates. Resetting only happens when we move // across space servers (see handleMigrated). proxy_manager->destroyObject(proxy_obj); if (self->mObjectScript) self->mObjectScript->notifyProximateGone(proxy_obj,spaceobj); proxy_obj->invalidate(permanent); } } CONTEXT_OHTRACE(prox, spaceobj.object().getAsUUID(), //getUUID(), removal.object(), false, TimedMotionVector3f() ); } }
/** Object packs are our own custom format for simple, fixed, object tests. The file format is * a simple binary dump of each objects information: * * struct ObjectInformation { * uint64 object_id; * double x; * double y; * double z; * double radius; * }; * * This gives the minimal information for a static object and allows you to seek directly to any * object in the file, making it easy to split the file across multiple object hosts. */ void ObjectFactory::generatePackObjects(const BoundingBox3f& region, const Duration& duration) { bool dump_pack = GetOptionValue<bool>(OBJECT_PACK_DUMP); if (dump_pack) return; // If we're dumping objects, don't load // from a pack Time start(Time::null()); uint32 nobjects = GetOptionValue<uint32>(OBJECT_PACK_NUM); if (nobjects == 0) return; String pack_filename = GetOptionValue<String>(OBJECT_PACK); assert(!pack_filename.empty()); String pack_dir = GetOptionValue<String>(OBJECT_PACK_DIR); pack_filename = pack_dir + pack_filename; FILE* pack_file = fopen(pack_filename.c_str(), "rb"); if (pack_file == NULL) { SILOG(objectfactory,error,"Couldn't open object pack file, not generating any objects."); assert(false); return; } // First offset ourselves into the file uint32 pack_offset = GetOptionValue<uint32>(OBJECT_PACK_OFFSET); uint32 obj_pack_size = 8 + // objid 8 + // radius 8 + // x 8 + // y 8 + // z 0; int seek_success = fseek( pack_file, obj_pack_size * pack_offset, SEEK_SET ); if (seek_success != 0) { SILOG(objectfactory,error,"Couldn't seek to appropriate offset in object pack file."); fclose(pack_file); return; } for(uint32 i = 0; i < nobjects; i++) { ObjectInputs* inputs = new ObjectInputs; uint64 pack_objid = 0; double x = 0, y = 0, z = 0, rad = 0; fread( &pack_objid, sizeof(uint64), 1, pack_file ); fread( &x, sizeof(double), 1, pack_file ); fread( &y, sizeof(double), 1, pack_file ); fread( &z, sizeof(double), 1, pack_file ); fread( &rad, sizeof(double), 1, pack_file ); UUID id = pack2UUID(pack_objid); Vector3f startpos((float)x, (float)y, (float)z); float bounds_radius = (float)rad; //SILOG(oh,error,"Preating "<<id.toString()<<" radius "<<bounds_radius); inputs->localID = mLocalIDSource++; inputs->motion = new StaticMotionPath(start, startpos); inputs->bounds = BoundingSphere3f( Vector3f(0, 0, 0), bounds_radius ); inputs->registerQuery = false; inputs->queryAngle = SolidAngle::Max; inputs->connectAt = Duration::seconds(0.f); inputs->startTimer = Network::IOTimer::create(mContext->ioService); mObjectIDs.insert(id); mInputs[id] = inputs; } fclose(pack_file); }
/** * Process a message that may be meant for the proximity system * \returns true if object was deleted */ OpaqueMessageReturnValue internalProcessOpaqueProximityMessage( const ObjectReference*object, const RoutableMessageHeader& hdr, const void *serializedMessageBody, size_t serializedMessageBodySize, bool trusted) { try { RoutableMessage msg(hdr,serializedMessageBody,serializedMessageBodySize); MessageBundle sendState=DELIVER_TO_UNKNOWN; bool deliverAllMessages=true; int len=msg.body().message_size(); OpaqueMessageReturnValue obj_is_deleted=OBJECT_NOT_DESTROYED; bool disconnection=false; bool registration=false; for (int i=0;i<len;++i) { if (trusted||(hdr.has_source_object()&&hdr.source_object()==ObjectReference::spaceServiceID()&&hdr.source_port()==mRegistrationPort)) { if(msg.body().message_names(i)=="DelObj") { disconnection=true; obj_is_deleted=OBJECT_DELETED; } if(msg.body().message_names(i)=="RetObj") { registration=true; Sirikata::Protocol::RetObj ro; ro.ParseFromString(msg.body().message_arguments(i)); newObj(ro,msg.body().message_arguments(i).data(),msg.body().message_arguments(i).size()); } } if (!forwardThisName(disconnection,msg.body().message_names(i))) { if (len==1) return obj_is_deleted; deliverAllMessages=false; }else { if (msg.body().message_names(i)==proxCallbackName()) { if (sendState==DELIVER_TO_UNKNOWN||sendState==DELIVER_TO_OBJECT) sendState=DELIVER_TO_OBJECT; else sendState=DELIVER_TO_BOTH; }else{ if (sendState==DELIVER_TO_UNKNOWN||sendState==DELIVER_TO_PROX) sendState=DELIVER_TO_PROX; else sendState=DELIVER_TO_BOTH; } } } if (sendState==DELIVER_TO_UNKNOWN) return obj_is_deleted;//no messages considered worth forwarding to the proximity system if (sendState==DELIVER_TO_BOTH) { SILOG(prox,info,"Message with recipients both proximity and object bundled into the same message: not delivering."); return obj_is_deleted; } /* NOT SURE THIS IS NECESSARY -- do these messages already have addresses on them?*/ DidAlterMessage alteration; if (sendState==DELIVER_TO_PROX) alteration=addressMessage(msg,object,NULL); else alteration=addressMessage(msg,NULL,object); if (deliverAllMessages&&sendState==DELIVER_TO_PROX) { sendMessage(*object,msg,serializedMessageBody,serializedMessageBodySize); } else if (deliverAllMessages&&sendState==DELIVER_TO_OBJECT) { deliverMessage(*object,msg,serializedMessageBody,serializedMessageBodySize); }else { //some messages are not considered worth forwarding to the proximity system or there's a mishmash of destinations if (msg.body().message_size()<len) { len=msg.body().message_size(); } RoutableMessage newMsg (msg); newMsg.body().clear_message(); for (int i=0;i<len;++i) { if (forwardThisName(registration||disconnection,msg.body().message_names(i))) { newMsg.body().add_message(msg.body().message_names(i), msg.body().message_arguments(i)); } } if (sendState==DELIVER_TO_OBJECT) deliverMessage(*object,newMsg,NULL,0); if (sendState==DELIVER_TO_PROX) sendMessage(*object,newMsg,NULL,0); } return obj_is_deleted; }catch(std::invalid_argument&ia) { SILOG(proximity,warning,"Could not parse message"); return OBJECT_NOT_DESTROYED; } }
///gets called when a complete 24 byte header is actually received: uses the UUID within to match up appropriate sockets void buildStream(TcpSstHeaderArray *buffer, TCPSocket *socket, std::tr1::shared_ptr<TCPStreamListener::Data> data, const boost::system::error_code &error, std::size_t bytes_transferred) { // Buffer always needs to be cleaned up when we get out of this method std::auto_ptr<TcpSstHeaderArray> buffer_ptr(buffer); // Sanity check start if (error || bytes_transferred < 5 || std::string((const char*)buffer->begin(), 5) != std::string("GET /")) { SILOG(tcpsst,warning,"Connection received with truncated header: "<<error); delete socket; return; } // Sanity check end: 8 bytes from WebSocket spec after headers, then // \r\n\r\n before that. std::string buffer_str((const char*)buffer->begin(), bytes_transferred); if (buffer_str[ bytes_transferred - 12] != '\r' || buffer_str[ bytes_transferred - 11] != '\n' || buffer_str[ bytes_transferred - 10] != '\r' || buffer_str[ bytes_transferred - 9] != '\n') { SILOG(tcpsst,warning,"Request doesn't end properly:\n" << buffer_str << "\n"); delete socket; return; } std::string headers_str = buffer_str.substr(0, bytes_transferred - 10); // Parse headers UUID context; std::map<std::string, std::string> headers; std::string::size_type offset = 0; while(offset < headers_str.size()) { std::string::size_type last_offset = offset; offset = headers_str.find("\r\n", offset); if (offset == std::string::npos) { SILOG(tcpsst,warning,"Error parsing headers."); delete socket; return; } std::string line = headers_str.substr(last_offset, offset - last_offset); // Special case the initial GET line if (line.substr(0, 5) == "GET /") { std::string::size_type uuid_end = line.find(' ', 5); if (uuid_end == std::string::npos) { SILOG(tcpsst,warning,"Error parsing headers: invalid get line."); delete socket; return; } std::string uuid_str = line.substr(5, uuid_end - 5); try { context = UUID(uuid_str,UUID::HumanReadable()); } catch(...) { SILOG(tcpsst,warning,"Error parsing headers: invalid get uuid."); delete socket; return; } offset += 2; continue; } std::string::size_type colon = line.find(":"); if (colon == std::string::npos) { SILOG(tcpsst,warning,"Error parsing headers: missing colon."); delete socket; return; } std::string head = line.substr(0, colon); std::string val = line.substr(colon+2); headers[head] = val; // Advance to get past the \r\n offset += 2; } if (headers.find("Host") == headers.end() || headers.find("Origin") == headers.end() || headers.find("Sec-WebSocket-Key1") == headers.end() || headers.find("Sec-WebSocket-Key2") == headers.end()) { SILOG(tcpsst,warning,"Connection request didn't specify all required fields."); delete socket; return; } std::string host = headers["Host"]; std::string origin = headers["Origin"]; std::string protocol = "wssst1"; if (headers.find("Sec-WebSocket-Protocol") != headers.end()) protocol = headers["Sec-WebSocket-Protocol"]; std::string key1 = headers["Sec-WebSocket-Key1"]; std::string key2 = headers["Sec-WebSocket-Key2"]; std::string key3 = buffer_str.substr(bytes_transferred - 8); assert(key3.size() == 8); std::string reply_str = getWebSocketSecReply(key1, key2, key3); bool binaryStream=protocol.find("sst")==0; bool base64Stream=!binaryStream; boost::asio::ip::tcp::no_delay option(data->mNoDelay); socket->set_option(option); IncompleteStreamMap::iterator where=sIncompleteStreams.find(context); unsigned int numConnections=1; for (std::string::iterator i=protocol.begin(),ie=protocol.end();i!=ie;++i) { if (*i>='0'&&*i<='9') { char* endptr=NULL; const char *start=protocol.c_str(); size_t offset=(i-protocol.begin()); start+=offset; numConnections=strtol(start,&endptr,10); size_t numberlen=endptr-start; if (numConnections>data->mMaxSimultaneousSockets) { numConnections=data->mMaxSimultaneousSockets; char numcon[256]; sprintf(numcon,"%d",numConnections); protocol=protocol.substr(0,offset)+numcon+protocol.substr(offset+numberlen); } break; } } if (where==sIncompleteStreams.end()){ sIncompleteStreams[context].mNumSockets=numConnections; where=sIncompleteStreams.find(context); assert(where!=sIncompleteStreams.end()); // Setup a timer to clean up the sockets if we don't complete it in time data->strand->post( Duration::seconds(10), std::tr1::bind(&handleBuildStreamTimeout, context) ); } if ((int)numConnections!=where->second.mNumSockets) { SILOG(tcpsst,warning,"Single client disagrees on number of connections to establish: "<<numConnections<<" != "<<where->second.mNumSockets); sIncompleteStreams.erase(where); }else { where->second.mSockets.push_back(socket); where->second.mWebSocketResponses[socket] = reply_str; if (numConnections==(unsigned int)where->second.mSockets.size()) { MultiplexedSocketPtr shared_socket( MultiplexedSocket::construct<MultiplexedSocket>(data->strand,context,data->cb,base64Stream)); shared_socket->initFromSockets(where->second.mSockets,data->mSendBufferSize); std::string port=shared_socket->getASIOSocketWrapper(0).getLocalEndpoint().getService(); std::string resource_name='/'+context.toString(); MultiplexedSocket::sendAllProtocolHeaders(shared_socket,origin,host,port,resource_name,protocol, where->second.mWebSocketResponses); sIncompleteStreams.erase(where); Stream::StreamID newID=Stream::StreamID(1); TCPStream * strm=new TCPStream(shared_socket,newID); TCPSetCallbacks setCallbackFunctor(&*shared_socket,strm); data->cb(strm,setCallbackFunctor); if (setCallbackFunctor.mCallbacks==NULL) { SILOG(tcpsst,error,"Client code for stream "<<newID.read()<<" did not set listener on socket"); shared_socket->closeStream(shared_socket,newID); } }else{ sStaleUUIDs.push_back(context); } } }
boost::any JSInvokableObjectInt::invoke(std::vector<boost::any> ¶ms) { /* Invoke the invokable version */ SILOG(js,detailed,"JSInvokableObjectInt::invoke(): invokable_ type is " << typeid(invokable_).name()); return invokable_->invoke(params); }
void SingleStreamProximityConnection::streamDisconnected() { SILOG(proximity,error,"Lost connection with proximity manager"); }
void InternalIOWork::logEvent(const String& evt) { if (mName != "") SILOG(io,insane,"IOWork event: " << mName << " -> " << evt); }
Stream::ReceivedResponse MultiplexedSocket::receiveFullChunk(unsigned int whichSocket, Stream::StreamID id,Chunk&newChunk){ Stream::ReceivedResponse retval = Stream::AcceptedData; if (id==Stream::StreamID()) {//control packet if(newChunk.size()) { unsigned int controlCode=*newChunk.begin(); switch (controlCode) { case TCPStream::TCPStreamCloseStream: case TCPStream::TCPStreamAckCloseStream: if (newChunk.size()>1) { unsigned int avail_len=newChunk.size()-1; id.unserialize((const uint8*)&(newChunk[1]),avail_len); if (avail_len+1>newChunk.size()) { SILOG(tcpsst,warning,"Control Chunk too short"); } } if (id!=Stream::StreamID()) { std::tr1::unordered_map<Stream::StreamID,unsigned int>::iterator where=mAckedClosingStreams.find(id); if (where!=mAckedClosingStreams.end()){ where->second++; int how_much=where->second; if (where->second==mSockets.size()) { mAckedClosingStreams.erase(where); shutDownClosedStream(controlCode,id); if (controlCode==TCPStream::TCPStreamCloseStream) { closeStream(getSharedPtr(),id,TCPStream::TCPStreamAckCloseStream); } } }else{ if (mSockets.size()==1) { shutDownClosedStream(controlCode,id); if (controlCode==TCPStream::TCPStreamCloseStream) { closeStream(getSharedPtr(),id,TCPStream::TCPStreamAckCloseStream); } }else { mAckedClosingStreams[id]=1; } } } break; default: break; } } }else { std::deque<StreamIDCallbackPair> registrations; CommitCallbacks(registrations,CONNECTED,false); CallbackMap::iterator where=mCallbacks.find(id); if (where!=mCallbacks.end()) { retval=where->second->mBytesReceivedCallback(newChunk); }else if (mOneSidedClosingStreams.find(id)==mOneSidedClosingStreams.end()) { //new substream TCPStream*newStream=new TCPStream(getSharedPtr(),id); TCPSetCallbacks setCallbackFunctor(this,newStream); mNewSubstreamCallback(newStream,setCallbackFunctor); if (setCallbackFunctor.mCallbacks != NULL) { CommitCallbacks(registrations,CONNECTED,false);//make sure bytes are received retval=setCallbackFunctor.mCallbacks->mBytesReceivedCallback(newChunk); }else { closeStream(getSharedPtr(),id); } }else { //IGNORED MESSAGE } } return retval; }
MonoVWObjectScript::MonoVWObjectScript(Mono::MonoSystem*mono_system, HostedObject*ho, const ObjectScriptManager::Arguments&args):mDomain(mono_system->createDomain()){ mParent=ho; int ignored_args=0; String reserved_string_assembly="Assembly"; String reserved_string_class="Class"; String reserved_string_namespace="Namespace"; String reserved_string_function="Function"; String assembly_name;//="Sirikata.Runtime"; ObjectScriptManager::Arguments::const_iterator i=args.begin(),j,func_iter; if ((i=args.find(reserved_string_assembly))!=args.end()) { assembly_name=i->second; ++ignored_args; } mono_system->loadAssembly(assembly_name); try { Mono::Assembly ass=mDomain.getAssembly(i->second); String class_name;//="PythonObject"; String namespace_name;//="Sirikata.Runtime"; if ((i=args.find(reserved_string_class))!=args.end()) { ++ignored_args; class_name=i->second; } if ((i=args.find(reserved_string_namespace))!=args.end()) { ++ignored_args; namespace_name=i->second; } if ((func_iter=args.find(reserved_string_function))!=args.end()) { ++ignored_args; } MonoContext::getSingleton().push(MonoContextData()); MonoContext::getSingleton().setVWObject(ho,mDomain); try { Mono::Class class_type=ass.getClass(namespace_name,class_name); Mono::Object exampleString=mDomain.String(String()); Mono::Array mono_args=Mono::Array(mDomain.Array(exampleString.type(),(args.size()-ignored_args)*2)); unsigned int mono_count=0; for (i=args.begin(),j=args.end();i!=j;++i) { if (i->first!=reserved_string_assembly&&i->first!=reserved_string_class&&i->first!=reserved_string_namespace&&i->first!=reserved_string_function) { mono_args.set(mono_count++,mDomain.String(i->first)); mono_args.set(mono_count++,mDomain.String(i->second)); } } try { if (func_iter==args.end()) { mObject=class_type.instance(mono_args); }else { mObject=class_type.send(func_iter->second,mono_args); } }catch(Mono::Exception&e) { SILOG(mono,warning,"Making new object: Cannot locate method "<<(func_iter==args.end()?String("constructor"):func_iter->second) <<" in class "<<namespace_name<<"::"<<class_name<<"with "<<mono_args.length()<<" arguments."<<e); } } catch (Mono::Exception&e) { SILOG(mono,warning,"Making new object: Cannot locate class "<<namespace_name<<"::"<<class_name<<"."<<e); } MonoContext::getSingleton().pop(); } catch (Mono::Exception&e) { SILOG(mono,warning,"Making new object: Cannot locate assembly "<<i->second<<"."<<e); //no assembly could be loaded } }
inline void execute_finished(std::tr1::shared_ptr<const DenseData> response, ExecuteFinished cb) { SILOG(transfer, detailed, "execute_finished in ChunkRequest called"); mDenseData = response; HttpManager::getSingleton().postCallback(cb); SILOG(transfer, detailed, "done ChunkRequest execute_finished"); }
inline void notifyCaller(std::tr1::shared_ptr<TransferRequest> from) { std::tr1::shared_ptr<ChunkRequest> fromC = std::tr1::static_pointer_cast<ChunkRequest, TransferRequest>(from); HttpManager::getSingleton().postCallback(std::tr1::bind(mCallback, fromC, fromC->mDenseData)); SILOG(transfer, detailed, "done ChunkRequest notifyCaller"); }
void EventManager<T>::temporary_processEventQueue(AbsTime forceCompletionBy) { AbsTime startTime = AbsTime::now(); SILOG(task,insane," >>> Processing events."); // swaps to allow people to keep adding new events typename EventList::NodeIterator processingList(mUnprocessed); // The events are swapped first to guarantee that listeners are at least as up-to-date as events. // Events can be delayed, but we cannot allow any lost subscriptions/unsubscriptions. { typename ListenerRequestList::NodeIterator procListeners(mListenerRequests); const ListenerRequest *req; while ((req = procListeners.next()) != NULL) { if (req->subscription) { SILOG(task,debug," >>>\tDoing subscription listener "<< req->listenerId << " for event " << req->eventId << " (" << req->onlyPrimary << ")."); doSubscribeId(*req); } else { SILOGNOCR(task,debug," >>>\t"); if (req->notifyListener) { SILOGNOCR(task,debug,"Notifying"); } SILOG(task,debug,"UNSUBSCRIBED listener " << req->listenerId << "."); doUnsubscribe(req->listenerId, req->notifyListener); } } } if (SILOGP(task,insane)){ SILOG(task,insane,"==== All Event Subscribers for " << (intptr_t)this << " ===="); typename PrimaryListenerMap::const_iterator priIter = mListeners.begin(); while (priIter != mListeners.end()) { SILOG(task,insane," ID " << (*priIter).first << ":"); PartiallyOrderedListenerList *primaryLists = &((*priIter).second->first); SecondaryListenerMap *secondaryMap = &((*priIter).second->second); for (int i = 0; i < NUM_EVENTORDER; i++) { ListenerList *currentList = &(primaryLists->get(i)); for (typename ListenerList::const_iterator iter = currentList->begin(); iter != currentList->end(); ++iter) { SILOG(task,insane," \t" "[" << (i==MIDDLE?'=':i<MIDDLE?'*':'/') << "] " << (*iter).second); } } typename SecondaryListenerMap::const_iterator secIter; secIter = secondaryMap->begin(); while (secIter != secondaryMap->end()) { SILOG(task,insane,"\tSec ID " << (*secIter).first << ":"); for (int i = 0; i < NUM_EVENTORDER; i++) { ListenerList *currentList = &((*secIter).second->get(i)); for (typename ListenerList::const_iterator iter = currentList->begin(); iter != currentList->end(); ++iter) { SILOG(task,insane," \t\t" "[" << (i==MIDDLE?'=':i<MIDDLE?'*':'/') << "] " << (*iter).second); } } ++secIter; } ++priIter; } SILOG(task,insane,"==== ---------------------------------- ===="); } EventPtr *evTemp; int numProcessed = 0; while ((evTemp = processingList.next())!=NULL) { EventPtr ev (*evTemp); ++numProcessed; typename PrimaryListenerMap::iterator priIter = mListeners.find(ev->getId().mPriId); if (priIter == mListeners.end()) { // FIXME: Should this ever happen? SILOG(task,warning," >>>\tWARNING: No listeners for type " << "event type " << ev->getId().mPriId); continue; } PartiallyOrderedListenerList *primaryLists = &((*priIter).second->first); SecondaryListenerMap *secondaryMap = &((*priIter).second->second); typename SecondaryListenerMap::iterator secIter; secIter = secondaryMap->find(ev->getId().mSecId); bool cancel = false; EventHistory eventHistory=EVENT_UNHANDLED; // Call once per event order. for (int i = 0; i < NUM_EVENTORDER && cancel == false; i++) { SILOG(task,debug," >>>\tFiring " << ev << ": " << ev->getId() << " [order " << i << "]"); ListenerList *currentList = &(primaryLists->get(i)); if (!currentList->empty()) eventHistory=EVENT_HANDLED; if (callAllListeners(ev, currentList, forceCompletionBy)) { cancel = cancel || true; } if (secIter != secondaryMap->end() && !(*secIter).second->get(i).empty()) { currentList = &((*secIter).second->get(i)); if (!currentList->empty()) eventHistory=EVENT_HANDLED; if (callAllListeners(ev, currentList, forceCompletionBy)) { cancel = cancel || true; } // all listeners may have returned false. // cleanUp(secondaryMap, secIter); // secIter = secondaryMap->find(ev->getId().mSecId); } if (cancel) { SILOG(task,debug," >>>\tCancelling " << ev->getId()); } } if (secIter != secondaryMap->end()) { cleanUp(secondaryMap, secIter); } if (cancel) eventHistory=EVENT_CANCELED; (*ev)(eventHistory); SILOG(task,debug," >>>\tFinished " << ev->getId()); } if (mEventCV) { mPendingEvents -= numProcessed; } AbsTime finishTime = AbsTime::now(); SILOG(task,insane, "**** Done processing events this round. " << "Took " << (finishTime-startTime).toSeconds() << " seconds."); }
String Get(Key key) { switch(key) { case FILE_EXE: { #if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC // Executable path can have relative references ("..") depending on // how the app was launched. uint32_t executable_length = 0; _NSGetExecutablePath(NULL, &executable_length); std::string executable_path(executable_length, '\0'); char* executable_path_c = (char*)executable_path.c_str(); int rv = _NSGetExecutablePath(executable_path_c, &executable_length); assert(rv == 0); if ((rv != 0) || (executable_path.empty())) return ""; // _NSGetExecutablePath will return whatever gets execed, so if // the command line is ./foo, you'll get the '.'. We use the // aggressive mode here to handle '..' parts that could interfere // with finding other paths that start from FILE_EXE. return canonicalize(executable_path, true); #elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX // boost::filesystem can't chase symlinks, do it manually const char* selfExe = "/proc/self/exe"; char bin_dir[MAX_PATH + 1]; int bin_dir_size = readlink(selfExe, bin_dir, MAX_PATH); if (bin_dir_size < 0 || bin_dir_size > MAX_PATH) { SILOG(core,fatal,"Couldn't read self symlink to setup dynamic loading paths."); return ""; } bin_dir[bin_dir_size] = 0; return String(bin_dir, bin_dir_size); #elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS char system_buffer[MAX_PATH]; system_buffer[0] = 0; GetModuleFileName(NULL, system_buffer, MAX_PATH); return String(system_buffer); #else return ""; #endif } break; case DIR_EXE: { String exe_file = Get(FILE_EXE); if (exe_file.empty()) return ""; boost::filesystem::path exe_file_path(exe_file); return exe_file_path.parent_path().string(); } break; case DIR_EXE_BUNDLE: { #if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX // Windows and Linux don't have bundles return Get(DIR_EXE); #elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC // On mac we need to detect that we're in a .app. We assume this // only applies if the binaries are in the standard location, // i.e. foo.app/Contents/MacOS/bar_binary String exe_dir = Get(DIR_EXE); boost::filesystem::path exe_dir_path(exe_dir); // Work our way back up verifying the path names, finally // returning if we actually find the .app. if (exe_dir_path.has_filename() && exe_dir_path.filename() == "MacOS") { exe_dir_path = exe_dir_path.parent_path(); if (exe_dir_path.has_filename() && exe_dir_path.filename() == "Contents") { exe_dir_path = exe_dir_path.parent_path(); if (exe_dir_path.has_filename()) { String app_dir_name = exe_dir_path.filename(); if (app_dir_name.substr(app_dir_name.size()-4, 4) == ".app") return exe_dir_path.parent_path().string(); } } } // Otherwise dump the original return exe_dir; #endif } break; case DIR_CURRENT: { #if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX char system_buffer[MAX_PATH] = ""; if (!getcwd(system_buffer, sizeof(system_buffer))) { return ""; } return String(system_buffer); #elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS char system_buffer[MAX_PATH]; system_buffer[0] = 0; DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer); if (len == 0 || len > MAX_PATH) return ""; return String(system_buffer); #else return "."; #endif } break; case DIR_USER: { #if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC uid_t uid = getuid(); passwd* pw = getpwuid(uid); if (pw != NULL && pw->pw_dir != NULL) { boost::filesystem::path homedir(pw->pw_dir); if (boost::filesystem::exists(homedir) && boost::filesystem::is_directory(homedir)) return homedir.string(); } #elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS char system_buffer[MAX_PATH]; system_buffer[0] = 0; if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, system_buffer))) return ""; std::string appdata_str(system_buffer); boost::filesystem::path user_appdata(appdata_str); user_appdata /= "Sirikata"; if (!boost::filesystem::exists(user_appdata)) boost::filesystem::create_directory(user_appdata); if (boost::filesystem::exists(user_appdata) && boost::filesystem::is_directory(user_appdata)) return user_appdata.string(); #endif // Last resort (and default for unknown platform) is to try to use // the current directory return "."; } break; case DIR_USER_HIDDEN: { #if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS // On windows there's no difference from the user-specific data directory since that's already hidden. return Get(DIR_USER); #else // We just compute this as an offset from the user directory boost::filesystem::path user_dir(Get(DIR_USER)); user_dir /= ".sirikata"; if (!boost::filesystem::exists(user_dir)) boost::filesystem::create_directory(user_dir); if (boost::filesystem::exists(user_dir) && boost::filesystem::is_directory(user_dir)) return user_dir.string(); #endif return "."; } case DIR_TEMP: { #if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC // On Mac and Linux we try to work under tmp using our own directory boost::filesystem::path tmp_path("/tmp"); if (boost::filesystem::exists(tmp_path) && boost::filesystem::is_directory(tmp_path)) { tmp_path /= "sirikata"; // If it doesn't exist, try creating it if (!boost::filesystem::exists(tmp_path)) boost::filesystem::create_directory(tmp_path); if (boost::filesystem::exists(tmp_path) && boost::filesystem::is_directory(tmp_path)) return tmp_path.string(); } #elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS // Windows doesn't seem to suggest a good location for this, so we // put it under the app data directory in its own temp directory boost::filesystem::path sirikata_temp_dir = boost::filesystem::path(Get(DIR_USER_HIDDEN)) / "temp"; if (!boost::filesystem::exists(sirikata_temp_dir)) boost::filesystem::create_directory(sirikata_temp_dir); if (boost::filesystem::exists(sirikata_temp_dir) && boost::filesystem::is_directory(sirikata_temp_dir)) return sirikata_temp_dir.string(); #endif // Last resort (and default for unknown platform) is to try to use // the current directory return "."; } break; case DIR_SYSTEM_CONFIG: { #if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC // This is sirikata specific, so we're looking for more // than just /etc. if (boost::filesystem::exists("/etc") && boost::filesystem::is_directory("/etc") && boost::filesystem::exists("/etc/sirikata") && boost::filesystem::is_directory("/etc/sirikata")) return "/etc/sirikata"; return ""; #else // Other platforms don't have an equivalent? return ""; #endif } break; case RESOURCE: { SILOG(core,fatal,"Can't request RESOURCE without specifiying an in-tree path and path to resource."); assert(key != RESOURCE); return ""; } break; default: return ""; } }
void MeerkatChunkHandler::request_finished(std::tr1::shared_ptr<HttpManager::HttpResponse> response, HttpManager::ERR_TYPE error, const boost::system::error_code& boost_error, const URI& uri, std::tr1::shared_ptr<Chunk> chunk, bool chunkReq, ChunkCallback callback) { std::tr1::shared_ptr<DenseData> bad; std::string reqType = "file request"; if(chunkReq) reqType = "chunk request"; if (error == Transfer::HttpManager::REQUEST_PARSING_FAILED) { SILOG(transfer, error, "Request parsing failed during an HTTP " << reqType << " (" << uri << ")"); callback(bad); return; } else if (error == Transfer::HttpManager::RESPONSE_PARSING_FAILED) { SILOG(transfer, error, "Response parsing failed during an HTTP " << reqType << " (" << uri << ")"); callback(bad); return; } else if (error == Transfer::HttpManager::BOOST_ERROR) { SILOG(transfer, error, "A boost error happened during an HTTP " << reqType << ". Boost error = " << boost_error.message() << " (" << uri << ")"); callback(bad); return; } else if (error != HttpManager::SUCCESS) { SILOG(transfer, error, "An unknown error happened during an HTTP " << reqType << " (" << uri << ")"); callback(bad); return; } if (response->getHeaders().size() == 0) { SILOG(transfer, error, "There were no headers returned during an HTTP " << reqType << " (" << uri << ")"); callback(bad); return; } HttpManager::Headers::const_iterator it; it = response->getHeaders().find("Content-Length"); if (it == response->getHeaders().end()) { SILOG(transfer, error, "Content-Length header was not present when it should be during an HTTP " << reqType << " (" << uri << ")"); callback(bad); return; } if (response->getStatusCode() != 200) { SILOG(transfer, error, "HTTP status code = " << response->getStatusCode() << " instead of 200 during an HTTP " << reqType << " (" << uri << ")"); callback(bad); return; } if (!response->getData()) { SILOG(transfer, error, "Body not present during an HTTP " << reqType << " (" << uri << ")"); callback(bad); return; } it = response->getHeaders().find("Content-Range"); if (chunkReq && it == response->getHeaders().end()) { SILOG(transfer, error, "Expected Content-Range header not present during an HTTP " << reqType << " (" << uri << ")"); callback(bad); return; } else if (chunkReq) { std::string range_str = it->second; bool range_parsed = false; if (range_str.substr(0,6) == "bytes ") { range_str = range_str.substr(6); size_type dashPos = range_str.find('-'); if (dashPos != std::string::npos) { range_str.replace(dashPos, 1, " "); //total file size is optional size_type slashPos = range_str.find('/'); if (slashPos != std::string::npos) { range_str.replace(slashPos, 1, " "); } std::istringstream instream(range_str); uint64 range_start; uint64 range_end; instream >> range_start; instream >> range_end; if (range_start == chunk->getRange().startbyte() && range_end == chunk->getRange().endbyte() && response->getData()->length() == chunk->getRange().length()) { range_parsed = true; } } }
static void defaultCallback(const Duration&offset){ SILOG(objecthost,debug,"New offset is "<<offset); }
void MeerkatNameHandler::request_finished(std::tr1::shared_ptr<HttpManager::HttpResponse> response, HttpManager::ERR_TYPE error, const boost::system::error_code& boost_error, std::tr1::shared_ptr<MetadataRequest> request, NameCallback callback) { std::tr1::shared_ptr<RemoteFileMetadata> bad; if (error == Transfer::HttpManager::REQUEST_PARSING_FAILED) { SILOG(transfer, error, "Request parsing failed during an HTTP name lookup (" << request->getURI() << ")"); callback(bad); return; } else if (error == Transfer::HttpManager::RESPONSE_PARSING_FAILED) { SILOG(transfer, error, "Response parsing failed during an HTTP name lookup (" << request->getURI() << ")"); callback(bad); return; } else if (error == Transfer::HttpManager::BOOST_ERROR) { SILOG(transfer, error, "A boost error happened during an HTTP name lookup (" << request->getURI() << "). Boost error = " << boost_error.message()); callback(bad); return; } else if (error != HttpManager::SUCCESS) { SILOG(transfer, error, "An unknown error happened during an HTTP name lookup. (" << request->getURI() << ")"); callback(bad); return; } if (response->getHeaders().size() == 0) { SILOG(transfer, error, "There were no headers returned during an HTTP name lookup (" << request->getURI() << ")"); callback(bad); return; } HttpManager::Headers::const_iterator it; it = response->getHeaders().find("Content-Length"); if (it != response->getHeaders().end()) { SILOG(transfer, error, "Content-Length header was present when it shouldn't be during an HTTP name lookup (" << request->getURI() << ")"); callback(bad); return; } if (response->getStatusCode() != 200) { SILOG(transfer, error, "HTTP status code = " << response->getStatusCode() << " instead of 200 during an HTTP name lookup (" << request->getURI() << ")"); callback(bad); return; } it = response->getHeaders().find("File-Size"); if (it == response->getHeaders().end()) { SILOG(transfer, error, "Expected File-Size header not present during an HTTP name lookup (" << request->getURI() << ")"); callback(bad); return; } std::string file_size_str = it->second; it = response->getHeaders().find("Hash"); if (it == response->getHeaders().end()) { SILOG(transfer, error, "Expected Hash header not present during an HTTP name lookup (" << request->getURI() << ")"); callback(bad); return; } std::string hash = it->second; if (response->getData()) { SILOG(transfer, error, "Body present during an HTTP name lookup (" << request->getURI() << ")"); callback(bad); return; } Fingerprint fp; try { fp = Fingerprint::convertFromHex(hash); } catch(std::invalid_argument e) { SILOG(transfer, error, "Hash header didn't contain a valid Fingerprint string (" << request->getURI() << ")"); callback(bad); return; } std::istringstream istream(file_size_str); uint64 file_size; istream >> file_size; std::ostringstream ostream; ostream << file_size; if(ostream.str() != file_size_str) { SILOG(transfer, error, "Error converting File-Size header string to integer (" << request->getURI() << ")"); callback(bad); return; } //Just treat everything as a single chunk for now Range whole(0, file_size, LENGTH, true); Chunk chunk(fp, whole); ChunkList chunkList; chunkList.push_back(chunk); std::tr1::shared_ptr<RemoteFileMetadata> met(new RemoteFileMetadata(fp, request->getURI(), file_size, chunkList, response->getRawHeaders())); callback(met); SILOG(transfer, detailed, "done http name handler request_finished"); }
void operationCompleted (Ogre::BackgroundProcessTicket) { SILOG(resource,insane, "Skeleton Load Task opComplete(), waited " << mName); signalCompletion(); }
Poller::~Poller() { #if SIRIKATA_DEBUG if (mPollerRunCount > 0) SILOG(poller, error, "Poller is being destroyed with mismatching start/stop calls: " << (mCBTag ? mCBTag : "(unknown)")); #endif }
void ObjectFactory::generateStaticTraceObjects(const BoundingBox3f& region, const Duration& duration) { Time start(Time::null()); uint32 nobjects = GetOptionValue<uint32>(OBJECT_SL_NUM); if (nobjects == 0) return; String pack_filename = GetOptionValue<String>(OBJECT_SL_FILE); assert(!pack_filename.empty()); String pack_dir = GetOptionValue<String>(OBJECT_PACK_DIR); pack_filename = pack_dir + pack_filename; Vector3f sim_center = GetOptionValue<Vector3f>(OBJECT_SL_CENTER); // First, load in all the objects. FILE* pack_file = fopen(pack_filename.c_str(), "rb"); if (pack_file == NULL) { SILOG(objectfactory,error,"Couldn't open object pack file, not generating any objects."); assert(false); return; } TraceObjectMap trace_objects; // parse each line: uuid x y z t rad SLEntry ent; char uuid[256]; while( !feof(pack_file) && fscanf(pack_file, "%s %f %f %f %d %f", uuid, &ent.pos.x, &ent.pos.y, &ent.pos.z, &ent.t, &ent.rad) ) { ent.uuid = UUID(std::string(uuid), UUID::HumanReadable()); //SILOG(oh,error,"Preating "<<ent.uuid.toString()<<" radius "<<ent.rad); TraceObjectMap::iterator obj_it = trace_objects.find(ent.uuid); if (obj_it == trace_objects.end()) { trace_objects[ent.uuid] = ObjectUpdateList(); obj_it = trace_objects.find(ent.uuid); } obj_it->second[ent.t] = ent; } fclose(pack_file); // Now get a version sorted by distance from typedef std::set<ObjectUpdateList, SortObjectUpdateListByDist> ObjectsByDistanceList; ObjectsByDistanceList objs_by_dist = ObjectsByDistanceList( SortObjectUpdateListByDist(sim_center) ); for(TraceObjectMap::iterator obj_it = trace_objects.begin(); obj_it != trace_objects.end(); obj_it++) objs_by_dist.insert(obj_it->second); // Finally, for the number of objects requested, insert the data ObjectsByDistanceList::iterator obj_it = objs_by_dist.begin(); for(uint32 i = 0; i < nobjects; i++, obj_it++) { ObjectInputs* inputs = new ObjectInputs; SLEntry first = (obj_it->begin())->second; inputs->localID = mLocalIDSource++; inputs->motion = new StaticMotionPath(Time::microseconds(first.t*1000), first.pos); inputs->bounds = BoundingSphere3f( Vector3f(0, 0, 0), first.rad ); inputs->registerQuery = false; inputs->queryAngle = SolidAngle::Max; inputs->connectAt = Duration::seconds(0.f); inputs->startTimer = Network::IOTimer::create(mContext->ioService); mObjectIDs.insert(first.uuid); mInputs[first.uuid] = inputs; } }
void AssetDownloadTask::handleAssetParsed(Mesh::VisualPtr vis) { mAsset = vis; if (!vis) { SILOG(ogre,error,"Failed to parse mesh " << mAssetURI.toString()); mCB(); return; } // Now we need to handle downloads for each type of Visual. MeshdataPtr md( std::tr1::dynamic_pointer_cast<Meshdata>(vis) ); if (md) { // This is a sanity check. There's no way Ogre can reasonably handle meshes // that require a ton of draw calls. Estimate them here and if its too high, // destroy the data and invoke the callback to make it look like failure. { // Draw calls = // Number of instances * number of primitives in instance uint32 draw_calls = 0; Meshdata::GeometryInstanceIterator geoinst_it = md->getGeometryInstanceIterator(); uint32 geoinst_idx; Matrix4x4f pos_xform; while( geoinst_it.next(&geoinst_idx, &pos_xform) ) draw_calls += md->geometry[ md->instances[geoinst_idx].geometryIndex ].primitives.size(); // Arbitrary number, but probably more than we should even allow given // that there are probably hundreds or thousands of other objects if (draw_calls > 500) { SILOG(ogre,error,"Excessively complicated mesh: " << mAssetURI.toString() << " has " << draw_calls << " draw calls. Ignoring this mesh."); mAsset = Mesh::VisualPtr(); mCB(); return; } } // Another sanity check: if we have an excessive number of textures, // we're probably going to hit some memory constraints { // Complete arbitrary number if (md->textures.size() > 100) { SILOG(ogre,error, "Mesh with excessive number of textures: " << mAssetURI.toString() << " has " << md->textures.size() << " textures. Ignoring this mesh."); mAsset = Mesh::VisualPtr(); mCB(); return; } } // Special case for no dependent downloads if (md->textures.size() == 0) { mCB(); return; } for(TextureList::const_iterator it = md->textures.begin(); it != md->textures.end(); it++) { const std::string& texName = *it; Transfer::URI texURI( getURL(mAssetURI, texName) ); ProgressiveMipmapMap::const_iterator findProgTex; if (md->progressiveData) { findProgTex = md->progressiveData->mipmaps.find(texName); } if (md->progressiveData && findProgTex != md->progressiveData->mipmaps.end()) { const ProgressiveMipmaps& progMipmaps = findProgTex->second.mipmaps; uint32 mipmapLevel = 0; for ( ; mipmapLevel < progMipmaps.size(); mipmapLevel++) { if (progMipmaps.find(mipmapLevel)->second.width >= 128 || progMipmaps.find(mipmapLevel)->second.height >= 128) { break; } } uint32 offset = progMipmaps.find(mipmapLevel)->second.offset; uint32 length = progMipmaps.find(mipmapLevel)->second.length; Transfer::Fingerprint hash = findProgTex->second.archiveHash; addDependentDownload(texURI, Transfer::Chunk(hash, Transfer::Range(offset, length, Transfer::LENGTH))); } else { addDependentDownload(texURI); } } startDependentDownloads(); return; } BillboardPtr bboard( std::tr1::dynamic_pointer_cast<Billboard>(vis) ); if (bboard) { // For billboards, we have to download at least the image to display on // it Transfer::URI texURI( getURL(mAssetURI, bboard->image) ); addDependentDownload(texURI); startDependentDownloads(); return; } // If we've gotten here, then we haven't handled the specific type of visual // and we need to issue a warning and callback. SILOG(ogre, error, "Tried to use AssetDownloadTask for a visual type it doesn't handle (" << vis->type() << "). Not downloading dependent resources."); mCB(); }