Ticket #3433: 3433_replay_cache_v1.5.patch
File 3433_replay_cache_v1.5.patch, 11.8 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/gui/replaymenu/replay_actions.js
127 127 }); 128 128 } 129 129 130 function reloadCache() 131 { 132 Engine.ReloadReplayCache(); 133 134 let selected = Engine.GetGUIObjectByName("replaySelection").selected; 135 Engine.SwitchGuiPage("page_replaymenu.xml", selected > 0 ? 136 { "replaySelectionData": createReplaySelectionData(g_ReplaysFiltered[selected].directory) } : ""); 137 } 138 130 139 /** 131 140 * Callback. 132 141 */ -
binaries/data/mods/public/gui/replaymenu/replay_menu.xml
240 240 <action on="Press">deleteReplayButtonPressed();</action> 241 241 </object> 242 242 243 <!-- Reload Cache Button --> 244 <object type="button" style="StoneButton" size="40%+25 0 57%+25 100%"> 245 <translatableAttribute id="caption">Reload Cache</translatableAttribute> 246 <action on="Press">reloadCache();</action> 247 </object> 248 243 249 <!-- Summary Button --> 244 250 <object name="summaryButton" type="button" style="StoneButton" size="65%-50 0 82%-50 100%"> 245 251 <translatableAttribute id="caption">Summary</translatableAttribute> -
binaries/data/mods/public/gui/session/session.js
537 537 538 538 Engine.EndGame(); 539 539 540 // After game is ended 541 if (!g_IsReplay) 542 Engine.AddReplayToCache(replayDirectory); 543 540 544 if (g_IsController && Engine.HasXmppClient()) 541 545 Engine.SendUnregisterGame(); 542 546 -
source/ps/scripting/JSInterface_VisualReplay.cpp
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 51 51 return VisualReplay::GetReplayMetadata(pCxPrivate, directoryName); 52 52 } 53 53 54 void JSI_VisualReplay::SaveReplayMetadata(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const CStrW& data)54 void JSI_VisualReplay::SaveReplayMetadata(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& data) 55 55 { 56 56 VisualReplay::SaveReplayMetadata(data); 57 57 } 58 58 59 void JSI_VisualReplay::AddReplayToCache(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& directoryName) 60 { 61 VisualReplay::AddReplayToCache(*(pCxPrivate->pScriptInterface), directoryName); 62 } 63 64 void JSI_VisualReplay::ReloadReplayCache(ScriptInterface::CxPrivate* pCxPrivate) 65 { 66 VisualReplay::ReloadReplayCache(*(pCxPrivate->pScriptInterface)); 67 } 68 59 69 void JSI_VisualReplay::RegisterScriptFunctions(ScriptInterface& scriptInterface) 60 70 { 61 71 scriptInterface.RegisterFunction<JS::Value, &GetReplays>("GetReplays"); … … 65 75 scriptInterface.RegisterFunction<JS::Value, CStrW, &GetReplayMetadata>("GetReplayMetadata"); 66 76 scriptInterface.RegisterFunction<bool, CStrW, &HasReplayMetadata>("HasReplayMetadata"); 67 77 scriptInterface.RegisterFunction<void, CStrW, &SaveReplayMetadata>("SaveReplayMetadata"); 78 scriptInterface.RegisterFunction<void, CStrW, &AddReplayToCache>("AddReplayToCache"); 79 scriptInterface.RegisterFunction<void, &ReloadReplayCache>("ReloadReplayCache"); 68 80 } -
source/ps/scripting/JSInterface_VisualReplay.h
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 30 30 bool HasReplayMetadata(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& directoryName); 31 31 JS::Value GetReplayMetadata(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& directoryName); 32 32 void SaveReplayMetadata(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& data); 33 void AddReplayToCache(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& directoryName); 34 void ReloadReplayCache(ScriptInterface::CxPrivate* pCxPrivate); 33 35 void RegisterScriptFunctions(ScriptInterface& scriptInterface); 34 36 } 35 37 -
source/ps/VisualReplay.cpp
62 62 } 63 63 64 64 /** 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. 69 67 */ 70 68 JS::Value VisualReplay::GetReplays(ScriptInterface& scriptInterface) 71 69 { … … 72 70 TIMER(L"GetReplays"); 73 71 JSContext* cx = scriptInterface.GetContext(); 74 72 JSAutoRequest rq(cx); 73 74 std::map<CStr, u32> fileList; 75 75 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.ParseJSON(cacheStr, &cachedReplays); 91 SAFE_DELETE(cacheStream); 92 93 JS::RootedObject temp(cx, &cachedReplays.toObject()); 94 cachedReplaysObject = temp; 95 96 // Create list of files included in the cache 97 u32 cacheLength = 0; 98 JS_GetArrayLength(cx, cachedReplaysObject, &cacheLength); 99 for (u32 j = 0; j < cacheLength ; ++j) 100 { 101 JS::RootedValue replay(cx); 102 JS_GetElement(cx, cachedReplaysObject, j, &replay); 103 104 JS::RootedObject replayObject(cx, &replay.toObject()); 105 JS::RootedValue file(cx); 106 JS_GetProperty(cx, replayObject, "directory", &file); 107 108 CStr fileName; 109 scriptInterface.FromJSVal(cx, file, fileName); 110 fileList.emplace(fileName, j); 111 } 112 } 113 114 JS::RootedObject replays(cx, JS_NewArrayObject(cx, 0)); 115 bool newReplays = false; 116 DirectoryNames directories; 76 117 u32 i = 0; 77 DirectoryNames directories;78 JS::RootedObject replays(cx, JS_NewArrayObject(cx, 0));79 80 118 if (GetDirectoryEntries(GetDirectoryName(), NULL, &directories) == INFO::OK) 119 { 81 120 for (OsPath& directory : directories) 82 121 { 83 122 if (SDL_QuitRequested()) 84 return JSVAL_NULL;123 break; 85 124 86 JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, directory)); 87 if (!replayData.isNull()) 88 JS_SetElement(cx, replays, i++, replayData); 125 std::map<CStr, u32>::iterator it = fileList.find(directory.string8()); 126 127 // directory is not element of fileList 128 if (it == fileList.end()) 129 { 130 JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, directory)); 131 if (!replayData.isNull()) 132 { 133 JS_SetElement(cx, replays, i++, replayData); 134 newReplays = true; 135 } 136 } 137 else 138 fileList.erase(it); 89 139 } 140 141 // No replay was changed, so just return the cache 142 if (!newReplays && fileList.empty()) 143 return JS::ObjectValue(*cachedReplaysObject); 144 145 // Cache found, so copy the replays from the cache that are not deleted 146 if (cacheFound) 147 { 148 std::vector<u32> deleteIndices; 149 for (const std::pair<CStr, u32>& file : fileList) 150 deleteIndices.push_back(file.second); 151 152 u32 cacheLength = 0; 153 JS_GetArrayLength(cx, cachedReplaysObject, &cacheLength); 154 155 for (u32 j = 0; j < cacheLength; ++j) 156 // a not in deleteIndices, so copy it into replays 157 if (std::find(deleteIndices.begin(), deleteIndices.end(), j) == deleteIndices.end()) 158 { 159 JS::RootedValue replay(cx); 160 JS_GetElement(cx, cachedReplaysObject, j, &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 90 171 return JS::ObjectValue(*replays); 91 172 } 92 173 … … 292 373 return attribs; 293 374 } 294 375 376 377 void VisualReplay::AddReplayToCache(ScriptInterface& scriptInterface, const CStrW& directoryName) 378 { 379 JSContext* cx = scriptInterface.GetContext(); 380 JSAutoRequest rq(cx); 381 382 JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, OsPath(directoryName))); 383 384 if (replayData.isNull()) 385 return; 386 387 const OsPath cacheFileName = GetDirectoryName() / L"replayCache.json"; 388 JS::RootedObject cachedReplaysObject(cx, JS_NewArrayObject(cx, 0)); 389 390 if (FileExists(cacheFileName)) 391 { 392 // Open cache file 393 std::istream* cacheStream = new std::ifstream(cacheFileName.string8().c_str()); 394 395 // Read file into chacheStr 396 CStr cacheStr((std::istreambuf_iterator<char>(*cacheStream)), std::istreambuf_iterator<char>()); 397 398 // Create empty JS object and parse the context of the cache into it 399 JS::RootedValue cachedReplays(cx); 400 scriptInterface.ParseJSON(cacheStr, &cachedReplays); 401 SAFE_DELETE(cacheStream); 402 403 JS::RootedObject temp(cx, &cachedReplays.toObject()); 404 cachedReplaysObject = temp; 405 } 406 407 u32 cacheLength = 0; 408 JS_GetArrayLength(cx, cachedReplaysObject, &cacheLength); 409 JS_SetElement(cx, cachedReplaysObject, cacheLength, replayData); 410 411 JS::RootedValue replaysRooted(cx, JS::ObjectValue(*cachedReplaysObject)); 412 std::ofstream cacheStream(cacheFileName.string8().c_str(), std::ofstream::out | std::ofstream::trunc); 413 cacheStream << scriptInterface.StringifyJSON(&replaysRooted); 414 cacheStream.close(); 415 } 416 417 void VisualReplay::ReloadReplayCache(ScriptInterface& scriptInterface) 418 { 419 JSContext* cx = scriptInterface.GetContext(); 420 JSAutoRequest rq(cx); 421 422 JS::RootedObject replays(cx, JS_NewArrayObject(cx, 0)); 423 DirectoryNames directories; 424 u32 i = 0; 425 426 if (GetDirectoryEntries(GetDirectoryName(), NULL, &directories) != INFO::OK) 427 return; 428 429 for (OsPath& directory : directories) 430 { 431 if (SDL_QuitRequested()) 432 break; 433 434 JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, directory)); 435 if (!replayData.isNull()) 436 JS_SetElement(cx, replays, i++, replayData); 437 } 438 439 const OsPath cacheFileName = GetDirectoryName() / L"replayCache.json"; 440 JS::RootedValue replaysRooted(cx, JS::ObjectValue(*replays)); 441 std::ofstream stream(cacheFileName.string8().c_str(), std::ofstream::out | std::ofstream::trunc); 442 stream << scriptInterface.StringifyJSON(&replaysRooted); 443 stream.close(); 444 } 445 295 446 // TODO: enhancement: how to save the data if the process is killed? (case SDL_QUIT in main.cpp) 296 447 void VisualReplay::SaveReplayMetadata(const CStrW& data) 297 448 { -
source/ps/VisualReplay.h
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 83 83 */ 84 84 void SaveReplayMetadata(const CStrW& data); 85 85 86 /** 87 * Saves the metadata from the session to metadata.json 88 */ 89 void AddReplayToCache(ScriptInterface& scriptInterface, const CStrW& directoryName); 90 91 /** 92 * Reloads the replay cache 93 */ 94 void ReloadReplayCache(ScriptInterface& scriptInterface); 95 86 96 } 87 97 88 98 #endif