Beispiel #1
0
void DLLEXPORT assetAgent_command(const char *cmd)
{
    if (strstr(cmd, ".sendall") != 0)
    {
        postAllFiles();
    }
    else if (strstr(cmd, ".clients") != 0)
    {
        listClients();
    }
    else if (strstr(cmd, ".telemetry") != 0)
    {
        TelemetryServer::isRunning() ? TelemetryServer::stop() : TelemetryServer::start();
        assetAgent_command(TelemetryServer::isRunning() ? "telemetryEnable" : "telemetryDisable");
    }
    else if (cmd[0] != 0)
    {
        loom_mutex_lock(gActiveSocketsMutex);

        if (gActiveHandlers.size() == 0)
        {
            if (strcmp(cmd, "terminate") != 0) sendIgnoredError();
        }

        for (UTsize i = 0; i < gActiveHandlers.size(); i++)
        {
            gActiveHandlers[i]->sendCommand(cmd);
        }

        loom_mutex_unlock(gActiveSocketsMutex);
    }
}
Beispiel #2
0
void LSLuaState::finalizeAssemblyLoad(Assembly *assembly, utArray<Type *>& types)
{
    for (UTsize j = 0; j < types.size(); j++)
    {
        Type *type = types.at(j);

        if (type->isNative() || type->hasStaticNativeMember())
        {
            // we're native
            NativeInterface::resolveScriptType(type);
        }
    }

    declareLuaTypes(types);
    initializeLuaTypes(types);

    // we avoid runtime validation on mobile, this works but should be unnecessary
    // as issues with be caught on OSX/WINDOWS development platforms
#if LOOM_PLATFORM == LOOM_PLATFORM_OSX || LOOM_PLATFORM == LOOM_PLATFORM_WIN32
    for (UTsize j = 0; j < types.size(); j++)
    {
        Type            *type = types.at(j);
        TypeValidatorRT tv(this, type);
        tv.validate();
    }
#endif

    assembly->bootstrap();
}
Beispiel #3
0
void LSLuaState::initializeLuaTypes(const utArray<Type *>& types)
{
    for (UTsize i = 0; i < types.size(); i++)
    {
        types[i]->cache();
    }

    // initialize all classes
    for (UTsize i = 0; i < types.size(); i++)
    {
        initializeClass(types[i]);
    }

    // run static initializers now that all classes have been initialized
    for (UTsize i = 0; i < types.size(); i++)
    {
        lsr_classinitializestatic(VM(), types[i]);
    }
}
Beispiel #4
0
void loom_asset_pump()
{
   // Currently we only want to do this on the main thread so piggy back on the
   // native delegate sanity check to bail if on secondary thread.
   if(platform_getCurrentThreadId() != LS::NativeDelegate::smMainThreadID && LS::NativeDelegate::smMainThreadID != 0xBAADF00D)
      return;

   loom_mutex_lock(gAssetLock);

   // Talk to the asset server.
   loom_asset_serviceServer();

   // For now just blast all the data from each file into the asset.
   while(gAssetLoadQueue.size())
   {
      loom_asset_t *asset = gAssetLoadQueue.front();

      // Figure out the type from the path.
      utString path = asset->name;
      int type = loom_asset_recognizeAssetTypeFromPath(path);
      
      if(type == 0)
      {
         lmLog(gAssetLogGroup, "Could not infer type of resource '%s', skipping it...", path.c_str());
         asset->state = loom_asset_t::Unloaded;
         gAssetLoadQueue.erase((UTsize)0, true);
         continue;
      }

      // Open the file.
      void *ptr;
      long size;
      if(!platform_mapFile(asset->name.c_str(), &ptr, &size))
      {
         lmAssert(false, "Could not open file '%s'.", asset->name.c_str());
      }

      // Deserialize it.
      LoomAssetCleanupCallback dtor = NULL;
      void *assetBits = loom_asset_deserializeAsset(path, type, size, ptr, &dtor);

      // Close the file.
      platform_unmapFile(ptr);

      // Instate the asset.
      asset->instate(type, assetBits, dtor);

      // Done! Update queue.
      gAssetLoadQueue.erase((UTsize)0, true);
   }

   loom_mutex_unlock(gAssetLock);
}
Beispiel #5
0
void LSLuaState::declareLuaTypes(const utArray<Type *>& types)
{
    for (UTsize i = 0; i < types.size(); i++)
    {
        declareClass(types[i]);
    }

    // validate/initialize native types
    for (UTsize i = 0; i < types.size(); i++)
    {
        Type *type = types.at(i);

        if (type->isNative() || type->hasStaticNativeMember())
        {
            NativeTypeBase *ntb = NativeInterface::getNativeType(type);

            if (!ntb)
            {
                LSError("Unable to get NativeTypeBase for type %s", type->getFullName().c_str());
            }

            if (type->isNativeManaged() != ntb->isManaged())
            {
                if (type->isNativeManaged())
                {
                    LSError("Managed mismatch for type %s, script declaration specifies native while native bindings are unmanaged", type->getFullName().c_str());
                }
                else
                {
                    LSError("Managed mismatch for type %s, script declaration specifies unmanaged while native bindings are managed", type->getFullName().c_str());
                }
            }

            ntb->validate(type);
            type->setCTypeName(ntb->getCTypeName());
        }
    }
}
Beispiel #6
0
// Dump connected clients to the console; useful for telling who is connected to the console!
static void listClients()
{
    loom_mutex_lock(gActiveSocketsMutex);

    // Blast it out to all clients.
    lmLog(gAssetAgentLogGroup, "Clients");

    for (UTsize i = 0; i < gActiveHandlers.size(); i++)
    {
        lmLog(gAssetAgentLogGroup, "   #%d - %s", gActiveHandlers[i]->getId(), gActiveHandlers[i]->description().c_str());
    }

    loom_mutex_unlock(gActiveSocketsMutex);
}
Beispiel #7
0
void gkBlenderSceneConverter::applyParents(utArray<Blender::Object*> &children)
{
	UTsize i;
	for (i = 0; i < children.size(); i++)
	{
		Blender::Object* bchild = children.at(i);
		gkGameObject*    gchild = m_gscene->getObject(GKB_IDNAME(bchild));

		if (gchild)
		{
			gkGameObject* gpar = m_gscene->getObject(GKB_IDNAME(bchild->parent));
			if (gpar && !gpar->getProperties().hasBoneParent())
				gchild->setParent(gpar);
		}
	}
}
Beispiel #8
0
// Helper to recognize an asset's type from its path/name.
static int loom_asset_recognizeAssetTypeFromPath(utString& path)
{
    // Easy out - empty strings are no good!
    if (path.length() == 0)
    {
        return 0;
    }

    // Walk backwards to first dot.
    size_t firstDotPos = path.size() - 1;
    for (size_t pos = path.size() - 1; pos > 0; pos--)
    {
        if (path.at(pos) != '.')
        {
            continue;
        }

        firstDotPos = pos;
        break;
    }

    // Split out the extension.
    utString pathExt = path.substr(firstDotPos + 1);

    // See if we can get a type out of any of the recognizers.
    int type = 0;
    for (UTsize i = 0; i < gRecognizerList.size(); i++)
    {
        type = gRecognizerList[i](pathExt.c_str());
        if (type)
        {
            break;
        }
    }

    // No match, so let's use text.
    if (type == 0)
    {
        lmLogInfo(gAssetLogGroup, "Couldn't recognize '%s', defaulting to LATText...", path.c_str());
        type = LATText;
    }

    return type;
}
void NativeDelegate::executeDeferredCalls(lua_State *L)
{
    ensureQueueInit();
    loom_mutex_lock(gCallNoteMutex);

    // Try to resolve the delegate pointer.
    utArray<NativeDelegate *> *delegates = NULL;
    if (sActiveNativeDelegates.find(L) != UT_NPOS)
    {
        delegates = *(sActiveNativeDelegates.get(L));
    }
    else
    {
        // No delegate list, can't do it.
        loom_mutex_unlock(gCallNoteMutex);
        return;
    }

    for(unsigned int i=0; i<gNDCallNoteQueue.size(); i++)
    {
        NativeDelegateCallNote *ndcn = gNDCallNoteQueue[i];

        bool found = false;
        for(unsigned int i=0; i<delegates->size(); i++)
        {
            // Look for our delegate.
            if((*delegates)[i] != ndcn->delegate)
                continue;

            // If key mismatches, warn and bail.
            if((*delegates)[i]->_key != ndcn->delegateKey)
            {
                lmLogError(gNativeDelegateGroup, "Found delegate call note with key mismatch (delegate=%x actualKey=%x expectedKey=%x), ignoring...", (*delegates)[i], (*delegates)[i]->_key, ndcn->delegateKey);
                break;
            }

            // Match!
            found = true;
            break;
        }

        // Bail if no match.
        if(!found)
            continue;

        // Otherwise, let's call it.
        const NativeDelegate *theDelegate = ndcn->delegate;
        for(;;)
        {
            unsigned char actionType = ndcn->readByte();
            bool done = false;
            char *str = NULL;
            utByteArray *bytes;
            switch(actionType)
            {
                case MSG_Nop:
                    lmLogError(gNativeDelegateGroup, "Got a nop in delegate data stream.");
                break;

                case MSG_PushString:
                    str = ndcn->readString();
                    theDelegate->pushArgument(str);
                    free(str);
                    break;

                case MSG_PushByteArray:
                    bytes = ndcn->readByteArray();
                    theDelegate->pushArgument(bytes);
                    free(bytes);
                    break;

                case MSG_PushDouble:
                    theDelegate->pushArgument(ndcn->readDouble());
                    break;

                case MSG_PushFloat:
                    theDelegate->pushArgument(ndcn->readFloat());
                    break;
                
                case MSG_PushInt:
                    theDelegate->pushArgument((int)ndcn->readInt());
                    break;
                
                case MSG_PushBool:
                    theDelegate->pushArgument(ndcn->readBool());
                    break;

                case MSG_Invoke:
                    theDelegate->invoke();
                    done = true;
                    break;
            }

            if(done)
                break;
        }

    }

    // Purge queue.
    gNDCallNoteQueue.clear();

    loom_mutex_unlock(gCallNoteMutex);
}
Beispiel #10
0
int loom_asset_queryPendingLoads()
{
    return gAssetLoadQueue.size() > 0 ? 1 : 0;
}
Beispiel #11
0
// Entry point for the socket thread. Listen for connections and incoming data,
// and route it to the protocol handlers.
static int socketListeningThread(void *payload)
{
    // Listen for incoming connections.
    int listenPort = 12340;

    gListenSocket = (loom_socketId_t)-1;
    for ( ; ; )
    {
        gListenSocket = loom_net_listenTCPSocket(listenPort);

        if (gListenSocket != (loom_socketId_t)-1)
        {
            break;
        }

        lmLogWarn(gAssetAgentLogGroup, "   - Failed to acquire port %d, trying port %d", listenPort, listenPort + 1);
        listenPort++;
    }

    lmLog(gAssetAgentLogGroup, "Listening on port %d", listenPort);

    while (loom_socketId_t acceptedSocket = loom_net_acceptTCPSocket(gListenSocket))
    {
        // Check to see if we got anybody...
        if (!acceptedSocket || ((int)(long)acceptedSocket == -1))
        {
            // Process the connections.
            loom_mutex_lock(gActiveSocketsMutex);
            
            for (UTsize i = 0; i < gActiveHandlers.size(); i++)
            {
                AssetProtocolHandler* aph = gActiveHandlers[i];
                aph->process();

                // Check for ping timeout
                int msSincePing = loom_readTimer(aph->lastActiveTime);
                if (msSincePing > socketPingTimeoutMs)
                {
                    gActiveHandlers.erase(i);
                    i--;
                    lmLog(gAssetAgentLogGroup, "Client timed out (%x)", aph->socket);
                    loom_net_closeTCPSocket(aph->socket);
                    lmDelete(NULL, aph);
                }
            }

            loom_mutex_unlock(gActiveSocketsMutex);

            loom_thread_sleep(10);
            continue;
        }

        lmLog(gAssetAgentLogGroup, "Client connected (%x)", acceptedSocket);

        loom_mutex_lock(gActiveSocketsMutex);
        gActiveHandlers.push_back(lmNew(NULL) AssetProtocolHandler(acceptedSocket));

        AssetProtocolHandler *handler = gActiveHandlers.back();
        handler->registerListener(lmNew(NULL) TelemetryListener());
        if (TelemetryServer::isRunning()) handler->sendCommand("telemetryEnable");

        // Send it all of our files.
        // postAllFiles(gActiveHandlers[gActiveHandlers.size()-1]->getId());

        loom_mutex_unlock(gActiveSocketsMutex);
    }

    return 0;
}
Beispiel #12
0
// Take a difference report from compareFileEntries and issue appropriate
// file modification notes, and check whether they have settled. If so,
// transmit updates to clients.
static void processFileEntryDeltas(utArray<FileEntryDelta> *deltas)
{
    int curTime = platform_getMilliseconds();

    loom_mutex_lock(gFileScannerLock);

    // Update the pending list with all the stuff we've seen.
    for (UTsize i = 0; i < deltas->size(); i++)
    {
        // Get the delta.
        const FileEntryDelta& fed = deltas->at(i);

        // If it's removal, we don't currently send a notification.
        if (fed.action == FileEntryDelta::Removed)
        {
            continue;
        }

        // If it's not whitelisted, ignore it.
        if (!checkInWhitelist(fed.path))
        {
            continue;
        }

        // Note it in the pending modification list.
        bool sawInList = false;
        for (UTsize i = 0; i < gPendingModifications.size(); i++)
        {
            FileModificationNote& fmn = gPendingModifications.at(i);
            if (strcmp(fmn.path, fed.path.c_str()))
            {
                continue;
            }

            // Match - update time.
            lmLogDebug(gAssetAgentLogGroup, "FILE CHANGING - '%s'", fed.path.c_str());
            fmn.lastSeenTime = curTime;
            sawInList        = true;
        }

        if (!sawInList)
        {
            FileModificationNote fmn;
            fmn.path         = stringtable_insert(fed.path.c_str());
            fmn.lastSeenTime = curTime;
            gPendingModifications.push_back(fmn);
            lmLogDebug(gAssetAgentLogGroup, "FILE CHANGED  - '%s'", fed.path.c_str());
        }
    }

    // Now, walk the pending list and send everyone who hasn't been touched for the settling period.

    // See how many files we're sending and note that state.
    const int settleTimeMs = 750;

    int transferStartTime     = platform_getMilliseconds();
    int totalPendingTransfers = 0;
    for (UTsize i = 0; i < gPendingModifications.size(); i++)
    {
        // Only consider pending items that have aged out.
        FileModificationNote& fmn = gPendingModifications.at(i);
        if (curTime - fmn.lastSeenTime < settleTimeMs)
        {
            continue;
        }

        totalPendingTransfers++;
    }

    bool didWeNotifyUserAboutPending = false;

    for (UTsize i = 0; i < gPendingModifications.size(); i++)
    {
        // Only consider pending items that have aged out.
        FileModificationNote& fmn = gPendingModifications.at(i);
        if (curTime - fmn.lastSeenTime < settleTimeMs)
        {
            continue;
        }

        // Make the path canonical.
        utString filename = fmn.path;
        char     canonicalFile[MAXPATHLEN];
        makeAssetPathCanonical(filename.c_str(), canonicalFile);

        // Note: we don't deal with deleted files properly (by uploading new state) because realpath
        // only works right when the file exists. So we just skip doing anything about it.
        // Note we are using gActiveHandlers.size() outside of a lock, but this is ok as it's a word.
        if ((strstr(canonicalFile, ".loom") || strstr(canonicalFile, ".ls")) && (gActiveHandlers.size() > 0))
        {
            lmLog(gAssetAgentLogGroup, "Changed '%s'", canonicalFile);
        }

        if (canonicalFile[0] == 0)
        {
            lmLog(gAssetAgentLogGroup, "   o Ignoring file missing from the asset folder!");

            // Remove from the pending list.
            gPendingModifications.erase(i);
            i--;

            continue;
        }

        // Queue the callback.
        enqueueFileChangeCallback(canonicalFile);

        // Map the file.
        void *fileBits      = NULL;
        long fileBitsLength = 0;
        if (!platform_mapFile(canonicalFile, &fileBits, &fileBitsLength))
        {
            lmLog(gAssetAgentLogGroup, "   o Skipping due to file failing to map.");
            continue;
        }

        // Loop over the active sockets.
        loom_mutex_lock(gActiveSocketsMutex);

        // Blast it out to all clients.
        for (UTsize j = 0; j < gActiveHandlers.size(); j++)
        {
            // If it's for a specific client then only send to that client.
            if ((fmn.onlyForClient != -1) && (fmn.onlyForClient != gActiveHandlers[j]->getId()))
            {
                continue;
            }

            gActiveHandlers[j]->sendFile(canonicalFile, fileBits, fileBitsLength, totalPendingTransfers);

            // If it has been more than a second, note that we are still working.
            const int remainingTransferCount = (totalPendingTransfers * gActiveHandlers.size()) - j;
            if (((platform_getMilliseconds() - transferStartTime) > 2000) && (remainingTransferCount > 1))
            {
                transferStartTime = platform_getMilliseconds();
                lmLog(gAssetAgentLogGroup, "Still transferring files. %d to go!", remainingTransferCount - 1);
                didWeNotifyUserAboutPending = true;
            }
        }

        loom_mutex_unlock(gActiveSocketsMutex);

        totalPendingTransfers--;

        // Unmap the file.
        platform_unmapFile(fileBits);

        // Remove from the pending list.
        gPendingModifications.erase(i);
        i--;
    }

    loom_mutex_unlock(gFileScannerLock);

    if (didWeNotifyUserAboutPending)
    {
        lmLog(gAssetAgentLogGroup, "Done transferring files!");
    }
}
Beispiel #13
0
void LSLuaState::cacheAssemblyTypes(Assembly *assembly, utArray<Type *>& types)
{
    // setup assembly type lookup field
    lua_rawgeti(L, LUA_GLOBALSINDEX, LSASSEMBLYLOOKUP);
    lua_pushlightuserdata(L, assembly);
    lua_setfield(L, -2, assembly->getName().c_str());
    lua_pop(L, 1);

    assembly->ordinalTypes = new Type *[types.size() + 1];

    for (UTsize j = 0; j < types.size(); j++)
    {
        Type *type = types.at(j);

        assembly->types.insert(type->getName(), type);

        lmAssert(type->getTypeID() > 0 && type->getTypeID() <= (LSTYPEID)types.size(), "LSLuaState::cacheAssemblyTypes TypeID out of range");

        assembly->ordinalTypes[type->getTypeID()] = type;

        const char *typeName = type->getFullName().c_str();

        // fast access cache
        if (!strcmp(typeName, "system.Object"))
        {
            objectType = type;
        }
        else if (!strcmp(typeName, "system.Null"))
        {
            nullType = type;
        }
        else if (!strcmp(typeName, "system.Boolean"))
        {
            booleanType = type;
        }
        else if (!strcmp(typeName, "system.Number"))
        {
            numberType = type;
        }
        else if (!strcmp(typeName, "system.String"))
        {
            stringType = type;
        }
        else if (!strcmp(typeName, "system.Function"))
        {
            functionType = type;
        }
        else if (!strcmp(typeName, "system.Vector"))
        {
            vectorType = type;
        }

        lua_rawgeti(L, LUA_GLOBALSINDEX, LSINDEXMEMBERINFONAME);
        lua_pushlightuserdata(L, type);
        lua_gettable(L, -2);

        // cache all members for fast lookup of memberinfo -> pre-interned
        // lua string (interning strings is the devil's work)
        if (lua_isnil(L, -1))
        {
            lua_pop(L, 1);

            utArray<MemberInfo *> members;
            MemberTypes           types;
            types.method   = true;
            types.field    = true;
            types.property = true;
            type->findMembers(types, members, false);

            // cache the type to member info table
            lua_pushlightuserdata(L, type);
            lua_pushstring(L, type->getName());
            lua_settable(L, -3);

            for (UTsize i = 0; i < members.size(); i++)
            {
                MemberInfo *mi = members.at(i);

                lua_pushlightuserdata(L, mi);
                lua_pushstring(L, mi->getName());
                lua_settable(L, -3);
            }
        }
        else
        {
            lua_pop(L, 1);
        }

        lua_pop(L, 1);

        // if we weren't cached during assembly load, cache now
        if (!typeCache.get(type->getFullName()))
        {
            typeCache.insert(type->getFullName(), type);
        }
    }

    lmAssert(nullType, "LSLuaState::cacheAssemblyTypes - system.Null not found");
    lmAssert(booleanType, "LSLuaState::cacheAssemblyTypes - system.Boolean not found");
    lmAssert(numberType, "LSLuaState::cacheAssemblyTypes - system.Number not found");
    lmAssert(stringType, "LSLuaState::cacheAssemblyTypes - system.String not found");
    lmAssert(functionType, "LSLuaState::cacheAssemblyTypes - system.Function not found");
    lmAssert(vectorType, "LSLuaState::cacheAssemblyTypes - system.Vector not found");
}