bool VRSDClientLuaImplementation::GetSubSymbolsForGlobal(char* GlobalName, DynArray_cl<VRSDScriptSymbol>& SubSymbols, unsigned int& SubSymbolCount)
{
  VASSERT(m_pLuaState);

  if(!m_pLuaState || !m_pActivationRecord)
    return false;

  SubSymbolCount = 0;

  // we can only get local symbols without a crash if we are really in a Lua code execution path
  if(strcmp(m_pActivationRecord->what, "Lua"))
    return true;

  ScopedBooleanToTrue disableDebugCallback(m_bDebuggerRetrievingValues);
  VLuaStackCleaner stackCleaner(m_pLuaState);

  VMemoryTempBuffer<512> copyBuffer(GlobalName); // operate on a copy string in the tokenizer
  
  VStringTokenizerInPlace Tokenizer(copyBuffer.AsChar(), '.');
  lua_getfield(m_pLuaState, LUA_GLOBALSINDEX, Tokenizer.Next());
  if(LookupPath(Tokenizer) != HKV_SUCCESS)
    return false;

  // now the variable should be at the top of the stack and we can get the subvariables of it
  
  // first key for the iteration
  lua_pushnil(m_pLuaState);
  
  while (lua_next(m_pLuaState, -2) != 0)
  {
    // after this the key is at -2 and the value at -1
    
    // we only want string fields and numeric fields
    // (lua_isstring returns also true for numbers, using
    // tostring later on will cast the number to a string)
    int iKeyType = lua_type(m_pLuaState, -2);
    if (iKeyType==LUA_TNUMBER || iKeyType==LUA_TSTRING)
    {  
      VString sKeyBuffer;

      //this if prevents a conversion of number on the Lua stack
      if(iKeyType==LUA_TNUMBER) sKeyBuffer.Format("%1.0f", lua_tonumber(m_pLuaState, -2));
      else                      sKeyBuffer = lua_tostring(m_pLuaState, -2);

      const char* pSymbolName = sKeyBuffer.AsChar();

      if(pSymbolName)
      {
        // table member variable
        if(lua_istable(m_pLuaState, -1))
        {
          // add a symbol for the table
          AddSymbol(SubSymbols, SubSymbolCount, pSymbolName, "table", VRSDScriptSymbol::SYMBOL_TABLE);
        }
        // numeric member variable
        else if(lua_type(m_pLuaState, -1) == LUA_TNUMBER)
        {
          char buffer[32];
          sprintf(buffer, "%f", lua_tonumber(m_pLuaState, -1));
          AddSymbol(SubSymbols, SubSymbolCount, pSymbolName, buffer, VRSDScriptSymbol::SYMBOL_NUMBER);
        }
        // string member variable
        else if(lua_type(m_pLuaState, -1) == LUA_TSTRING)
        {
          AddSymbol(SubSymbols, SubSymbolCount, pSymbolName, lua_tostring(m_pLuaState, -1), VRSDScriptSymbol::SYMBOL_STRING);
        }
        // function member variable
        else if(lua_isfunction(m_pLuaState, -1))
        {
          AddSymbol(SubSymbols, SubSymbolCount, pSymbolName, "function", VRSDScriptSymbol::SYMBOL_FUNCTION);
        }
        // userdata member variable
        else if(lua_isuserdata(m_pLuaState, -1))
        {
          char buffer[128];
          swig_type_info* type = (swig_type_info *)LUA_GetSwigType(m_pLuaState, -1);
          void * pUserData = lua_touserdata(m_pLuaState, -1);

          if(type)
          {
            vis_snprintf(buffer, 128, "userdata:0x%p [%s: 0x%p]", pUserData, type->str, ((swig_lua_userdata*)pUserData)->ptr);
          }
          else
          {
            vis_snprintf(buffer, 128, "userdata:0x%p", lua_touserdata(m_pLuaState, -1));
          }
          AddSymbol(SubSymbols, SubSymbolCount, pSymbolName, buffer, VRSDScriptSymbol::SYMBOL_USERDATA);
        }
        else if(lua_isboolean(m_pLuaState, -1))
        {
          int iBoolVal = lua_toboolean(m_pLuaState, -1);
          AddSymbol(SubSymbols, SubSymbolCount, pSymbolName, iBoolVal ? "true" : "false", VRSDScriptSymbol::SYMBOL_BOOLEAN);
        }
        else if(lua_isnil(m_pLuaState, -1))
        {
          AddSymbol(SubSymbols, SubSymbolCount, pSymbolName, "nil", VRSDScriptSymbol::SYMBOL_CLASS);
        }

      }
    }
    lua_pop(m_pLuaState, 1);  // remove the value, keep the key for the next iteration
  }

  return true;
}
bool VRSDClientLuaImplementation::GetGlobalSymbols(DynArray_cl<VRSDScriptSymbol>& GlobalSymbols, unsigned int& GlobalSymbolCount)
{
  VASSERT(m_pLuaState);

  if(!m_pLuaState || !m_pActivationRecord)
    return false;

  GlobalSymbolCount = 0;

  // we can only get local symbols without a crash if we are really in a Lua code execution path
  if(strcmp(m_pActivationRecord->what, "Lua"))
    return true;

  VLuaStackCleaner stackCleaner(m_pLuaState);
  // iterate through the globals table to get its keys
  
  // first key for the iteration
  lua_pushnil(m_pLuaState);
  
  while (lua_next(m_pLuaState, LUA_GLOBALSINDEX) != 0)
  {
    // after this the key is at -2 and the value at -1
    
    // we only want string fields and no other keys
    if (lua_isstring(m_pLuaState, -2))
    {  
      char* pSymbolName = (char*)lua_tostring(m_pLuaState, -2);

      if(pSymbolName != NULL)
      {
        // if the variable is a table, get all child variables (one level deep only)
        if(lua_istable(m_pLuaState, -1))
        {
          // add a symbol for the table
          AddSymbol(GlobalSymbols, GlobalSymbolCount, pSymbolName, "table", VRSDScriptSymbol::SYMBOL_TABLE);
        }
        // numeric member variable
        else if(lua_type(m_pLuaState, -1) == LUA_TNUMBER)
        {
          char buffer[32];
          vis_snprintf(buffer, 32, "%f", lua_tonumber(m_pLuaState, -1));
          AddSymbol(GlobalSymbols, GlobalSymbolCount, pSymbolName, buffer, VRSDScriptSymbol::SYMBOL_NUMBER);
        }
        // string member variable
        else if(lua_type(m_pLuaState, -1) == LUA_TSTRING)
        {
          AddSymbol(GlobalSymbols, GlobalSymbolCount, pSymbolName, lua_tostring(m_pLuaState, -1), VRSDScriptSymbol::SYMBOL_STRING);
        }
        else if(lua_isfunction(m_pLuaState, -1))
        {
          AddSymbol(GlobalSymbols, GlobalSymbolCount, pSymbolName, "function", VRSDScriptSymbol::SYMBOL_FUNCTION);
        }
        else if(lua_isuserdata(m_pLuaState, -1))
        {
          char buffer[128];
          swig_type_info* type = (swig_type_info *)LUA_GetSwigType(m_pLuaState, -1);
          void * pUserData = lua_touserdata(m_pLuaState, -1);

          if(type)
          {
            vis_snprintf(buffer, 128, "userdata:0x%p [%s: 0x%p]", pUserData, type->str, ((swig_lua_userdata*)pUserData)->ptr);
          }
          else
          {
            vis_snprintf(buffer, 128, "userdata:0x%p", lua_touserdata(m_pLuaState, -1));
          }
          AddSymbol(GlobalSymbols, GlobalSymbolCount, pSymbolName, buffer, VRSDScriptSymbol::SYMBOL_USERDATA);
        }
        else if(lua_isboolean(m_pLuaState, -1))
        {
          int iBoolVal = lua_toboolean(m_pLuaState, -1);
          AddSymbol(GlobalSymbols, GlobalSymbolCount, pSymbolName, iBoolVal ? "true" : "false", VRSDScriptSymbol::SYMBOL_BOOLEAN);
        }
        else if(lua_isnil(m_pLuaState, -1))
        {
          AddSymbol(GlobalSymbols, GlobalSymbolCount, pSymbolName, "nil", VRSDScriptSymbol::SYMBOL_CLASS);
        }
      }
    }
    lua_pop(m_pLuaState, 1);  // remove the value, keep the key for the next iteration
  }

  return true;
}
bool VRSDClientLuaImplementation::GetLocalSymbols(DynArray_cl<VRSDScriptSymbol>& LocalSymbols, unsigned int& LocalSymbolCount)
{
  VASSERT(m_pLuaState);

  if(!m_pLuaState || !m_pActivationRecord)
    return false;

  LocalSymbolCount = 0;

  // we can only get local symbols without a crash if we are really in a Lua code execution path
  if(strcmp(m_pActivationRecord->what, "Lua"))
    return true;

  const char* pSymbolName = NULL;
  int iLocalIndex = 1;

  while((pSymbolName = lua_getlocal(m_pLuaState, m_pActivationRecord, iLocalIndex)) != NULL)
  {
    // skip lua internal temporary variables (they start with an '(')
    if(pSymbolName[0] != '(')
    {
      // if the variable is a table, get all child variables (one level deep only)
      if(lua_istable(m_pLuaState, -1))
      {
        // add a symbol for the table
        AddSymbol(LocalSymbols, LocalSymbolCount, pSymbolName, "table", VRSDScriptSymbol::SYMBOL_TABLE);
      }
      // numeric member variable
      else if(lua_type(m_pLuaState, -1) == LUA_TNUMBER)
      {
        char buffer[32];
        sprintf(buffer, "%f", lua_tonumber(m_pLuaState, -1));
        AddSymbol(LocalSymbols, LocalSymbolCount, pSymbolName, buffer, VRSDScriptSymbol::SYMBOL_NUMBER);
      }
      // string member variable
      else if(lua_type(m_pLuaState, -1) == LUA_TSTRING)
      {
        AddSymbol(LocalSymbols, LocalSymbolCount, pSymbolName, lua_tostring(m_pLuaState, -1), VRSDScriptSymbol::SYMBOL_STRING);
      }
      else if(lua_isfunction(m_pLuaState, -1))
      {
        AddSymbol(LocalSymbols, LocalSymbolCount, pSymbolName, "function", VRSDScriptSymbol::SYMBOL_FUNCTION);
      }
      else if(lua_isuserdata(m_pLuaState, -1))
      {
        char buffer[128];
        swig_type_info* type = (swig_type_info *)LUA_GetSwigType(m_pLuaState, -1);
        void * pUserData = lua_touserdata(m_pLuaState, -1);

        if(type)
        {
          vis_snprintf(buffer, 128, "userdata:0x%p [%s: 0x%p]", pUserData, type->str, ((swig_lua_userdata*)pUserData)->ptr);
        }
        else
        {
          vis_snprintf(buffer, 128, "userdata:0x%p", lua_touserdata(m_pLuaState, -1));
        }
        AddSymbol(LocalSymbols, LocalSymbolCount, pSymbolName, buffer, VRSDScriptSymbol::SYMBOL_USERDATA);
      }
      else if(lua_isboolean(m_pLuaState, -1))
      {
        int iBoolVal = lua_toboolean(m_pLuaState, -1);
        AddSymbol(LocalSymbols, LocalSymbolCount, pSymbolName, iBoolVal ? "true" : "false", VRSDScriptSymbol::SYMBOL_BOOLEAN);
      }
      else if(lua_isnil(m_pLuaState, -1))
      {
        AddSymbol(LocalSymbols, LocalSymbolCount, pSymbolName, "nil", VRSDScriptSymbol::SYMBOL_CLASS);
      }
    }

    // clean up the stack and increment the index to get the next local variable
    lua_pop(m_pLuaState, 1);
    iLocalIndex++;
  }


  return true;
}
void VDataDirectoryHelper::ProcessManifestFile(bool bAddDataDirs, bool bLoadEnginePlugins)
{
  VFileAccessManager::NativePathResult manifestNativeResult;
  if (VFileAccessManager::GetInstance()->MakePathNative("vForgeManifest.txt", manifestNativeResult, VFileSystemAccessMode::READ, VFileSystemElementType::FILE) != HKV_SUCCESS)
    return;

  char szProjectDir[FS_MAX_PATH];
  VFileHelper::GetFileDir(manifestNativeResult.m_sNativePath, szProjectDir);

  VManifest manifest;
  if(manifest.LoadManifest(manifestNativeResult.m_sNativePath))
  {
    int iNumEntries;
    VManifest::VManifestEntry* pEntries;
    manifest.GetEntries(iNumEntries, pEntries);

    for(int iEntryIdx = 0; iEntryIdx < iNumEntries; iEntryIdx++)
    {
      VManifest::VManifestEntry& entry = pEntries[iEntryIdx];
      if (bAddDataDirs && (entry.m_command == "AddDataDir"))
      {
        static int iNextRootNo = 0;
        char rootName[VFileAccessManager::MAX_ROOT_NAME_LENGTH];
        char dataDir[FS_MAX_PATH];
        if (VFileAccessManager::IsPathRelative(entry.m_value))
        {
          VFileHelper::CombineDirAndDir(dataDir, szProjectDir, entry.m_value);
        }
        else
        {
          strcpy(dataDir, entry.m_value.AsChar());
        }
        
        if (VFileAccessManager::IsPathNative(dataDir))
        {
          VFileAccessManager::AbsolutePathResult outputAbsResult;
          if (VFileAccessManager::GetInstance()->MakePathAbsolute(dataDir, outputAbsResult, VFileSystemAccessMode::READ, VFileSystemElementType::DIRECTORY) == HKV_SUCCESS)
          {
            Vision::File.AddSearchPath(outputAbsResult.m_sAbsolutePath);
          }
          else
          {
            vis_snprintf(rootName, VFileAccessManager::MAX_ROOT_NAME_LENGTH, "manifest_dir_%i", iNextRootNo++);
            Vision::File.AddFileSystem(rootName, dataDir, VFileSystemFlags::ADD_SEARCH_PATH);
          }
        }
        else if (VFileAccessManager::IsPathAbsolute(dataDir))
        {
          Vision::File.AddSearchPath(dataDir, VSearchPathFlags::PATH_MUST_EXIST);
        }
      }
      else if (bLoadEnginePlugins && (entry.m_command == "LoadEnginePlugin"))
      {
        bool pluginLoaded = Vision::Plugins.IsEnginePluginLoaded(entry.m_value) 
          || Vision::Plugins.GetRegisteredPlugin(entry.m_value.AsChar())
          || Vision::Plugins.LoadEnginePlugin(entry.m_value);

        if (!pluginLoaded)
        {
          hkvLog::Warning("Engine plugin '%s' referenced in vForgeManifest.txt file failed to load", entry.m_value.AsChar());
        }
      }
    }
  }
}