Ticket #3433: 3433_replay_cache_v1.1.patch

File 3433_replay_cache_v1.1.patch, 4.0 KB (added by Imarok, 8 years ago)

Using .json instead of .txt

  • source/ps/VisualReplay.cpp

     
    6262}
    6363
    6464/**
    65  * Load all replays found in the directory.
    66  *
    67  * Since files are spread across the harddisk,
    68  * loading hundreds of them can consume a lot of time.
     65 * Load the replay cache and check if there are new/deleted ones
     66 * If so, update their data.
    6967 */
    7068JS::Value VisualReplay::GetReplays(ScriptInterface& scriptInterface)
    7169{
     
    7270    TIMER(L"GetReplays");
    7371    JSContext* cx = scriptInterface.GetContext();
    7472    JSAutoRequest rq(cx);
     73   
     74    std::map<CStr, u32> fileList;
    7575
     76    const OsPath cacheFileName = GetDirectoryName() / L"replayCache.json";
     77    JS::RootedObject cachedReplaysObject(cx);
     78
     79    bool cacheFound = FileExists(cacheFileName);
     80    if (cacheFound)
     81    {
     82        // Open cache file
     83        std::istream* cacheStream = new std::ifstream(cacheFileName.string8().c_str());
     84
     85        // Read file into chacheStr
     86        CStr cacheStr((std::istreambuf_iterator<char>(*cacheStream)), std::istreambuf_iterator<char>());
     87
     88        // Create empty JS object and parse the context of the cache into it
     89        JS::RootedValue cachedReplays(cx);
     90        scriptInterface.Eval("({})", &cachedReplays);
     91        scriptInterface.ParseJSON(cacheStr, &cachedReplays);
     92        SAFE_DELETE(cacheStream);
     93
     94        JS::RootedObject temp(cx, &cachedReplays.toObject());
     95        cachedReplaysObject = temp;
     96
     97        // Create list of files included in the cache
     98        u32 cacheLength = 0;
     99        JS_GetArrayLength(cx, cachedReplaysObject, &cacheLength);
     100        for (u32 a = 0; a < cacheLength ; a++)
     101        {
     102            JS::RootedValue replay(cx);
     103            JS_GetElement(cx, cachedReplaysObject, a, &replay);
     104
     105            JS::RootedObject replayObject(cx, &replay.toObject());
     106            JS::RootedValue file(cx);
     107            JS_GetProperty(cx, replayObject, "directory", &file);
     108
     109            CStr fileName;
     110            scriptInterface.FromJSVal(cx, file, fileName);
     111            fileList.emplace(fileName, a);
     112        }
     113    }
     114
     115    JS::RootedObject replays(cx, JS_NewArrayObject(cx, 0));
     116    bool newReplays = false;
     117    DirectoryNames directories;
    76118    u32 i = 0;
    77     DirectoryNames directories;
    78     JS::RootedObject replays(cx, JS_NewArrayObject(cx, 0));
    79 
    80119    if (GetDirectoryEntries(GetDirectoryName(), NULL, &directories) == INFO::OK)
     120    {
    81121        for (OsPath& directory : directories)
    82122        {
    83123            if (SDL_QuitRequested())
    84124                return JSVAL_NULL;
    85125
    86             JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, directory));
    87             if (!replayData.isNull())
    88                 JS_SetElement(cx, replays, i++, replayData);
     126            std::map<CStr, u32>::iterator it = fileList.find(directory.string8());
     127           
     128            // directory is not element of fileList
     129            if (it == fileList.end())
     130            {
     131                JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, directory));
     132                if (!replayData.isNull())
     133                {
     134                    JS_SetElement(cx, replays, i++, replayData);
     135                    newReplays = true;
     136                }
     137            }
     138            else
     139                fileList.erase(it);
    89140        }
     141
     142        // No replay was changed, so just return the cache
     143        if (!newReplays && fileList.empty())
     144            return JS::ObjectValue(*cachedReplaysObject);
     145        // Cache found, so copy the replays from the cache that are not deleted
     146        else if (cacheFound)
     147        {
     148            std::vector<u32> deleteIndices;
     149            for (auto const file : fileList)
     150                deleteIndices.push_back(file.second);
     151
     152            u32 cacheLength = 0;
     153            JS_GetArrayLength(cx, cachedReplaysObject, &cacheLength);
     154
     155            for (u32 a = 0; a < cacheLength; ++a)
     156                // a not in deleteIndices, so copy it into replays
     157                if (std::find(deleteIndices.begin(), deleteIndices.end(), a) == deleteIndices.end())
     158                {
     159                    JS::RootedValue replay(cx);
     160                    JS_GetElement(cx, cachedReplaysObject, a, &replay);
     161                    JS_SetElement(cx, replays, i++, replay);
     162                }
     163        }
     164
     165        JS::RootedValue replaysRooted(cx, JS::ObjectValue(*replays));
     166        std::ofstream stream(cacheFileName.string8().c_str(), std::ofstream::out | std::ofstream::trunc);
     167        stream << scriptInterface.StringifyJSON(&replaysRooted);
     168        stream.close();
     169    }
     170
    90171    return JS::ObjectValue(*replays);
    91172}
    92173