Index: ps/trunk/source/graphics/MapGenerator.cpp =================================================================== --- ps/trunk/source/graphics/MapGenerator.cpp (revision 20506) +++ ps/trunk/source/graphics/MapGenerator.cpp (revision 20507) @@ -1,345 +1,330 @@ /* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "MapGenerator.h" #include "graphics/Terrain.h" #include "lib/timer.h" #include "ps/CLogger.h" #include "ps/Profile.h" - +#include "ps/scripting/JSInterface_VFS.h" // TODO: what's a good default? perhaps based on map size #define RMS_RUNTIME_SIZE 96 * 1024 * 1024 CMapGeneratorWorker::CMapGeneratorWorker() { // If something happens before we initialize, that's a failure m_Progress = -1; } CMapGeneratorWorker::~CMapGeneratorWorker() { // Wait for thread to end pthread_join(m_WorkerThread, NULL); } void CMapGeneratorWorker::Initialize(const VfsPath& scriptFile, const std::string& settings) { CScopeLock lock(m_WorkerMutex); // Set progress to positive value m_Progress = 1; m_ScriptPath = scriptFile; m_Settings = settings; // Launch the worker thread int ret = pthread_create(&m_WorkerThread, NULL, &RunThread, this); ENSURE(ret == 0); } void* CMapGeneratorWorker::RunThread(void *data) { debug_SetThreadName("MapGenerator"); g_Profiler2.RegisterCurrentThread("MapGenerator"); CMapGeneratorWorker* self = static_cast(data); self->m_ScriptInterface = new ScriptInterface("RMS", "MapGenerator", ScriptInterface::CreateRuntime(g_ScriptRuntime, RMS_RUNTIME_SIZE)); // Run map generation scripts if (!self->Run() || self->m_Progress > 0) { // Don't leave progress in an unknown state, if generator failed, set it to -1 CScopeLock lock(self->m_WorkerMutex); self->m_Progress = -1; } // At this point the random map scripts are done running, so the thread has no further purpose // and can die. The data will be stored in m_MapData already if successful, or m_Progress // will contain an error value on failure. return NULL; } bool CMapGeneratorWorker::Run() { // We must destroy the ScriptInterface in the same thread because the JSAPI requires that! // Also we must not be in a request when calling the ScriptInterface destructor, so the autoFree object // must be instantiated before the request (destructors are called in reverse order of instantiation) struct AutoFree { AutoFree(ScriptInterface* p) : m_p(p) {} ~AutoFree() { SAFE_DELETE(m_p); } ScriptInterface* m_p; } autoFree(m_ScriptInterface); JSContext* cx = m_ScriptInterface->GetContext(); JSAutoRequest rq(cx); m_ScriptInterface->SetCallbackData(static_cast (this)); // Replace RNG with a seeded deterministic function m_ScriptInterface->ReplaceNondeterministicRNG(m_MapGenRNG); m_ScriptInterface->LoadGlobalScripts(); // Functions for RMS + JSI_VFS::RegisterReadOnlyScriptFunctions(*m_ScriptInterface); m_ScriptInterface->RegisterFunction("LoadLibrary"); m_ScriptInterface->RegisterFunction("ExportMap"); m_ScriptInterface->RegisterFunction("SetProgress"); m_ScriptInterface->RegisterFunction("MaybeGC"); - m_ScriptInterface->RegisterFunction("FileExists"); - m_ScriptInterface->RegisterFunction ("ReadJSONFile"); m_ScriptInterface->RegisterFunction, CMapGeneratorWorker::GetCivData>("GetCivData"); m_ScriptInterface->RegisterFunction("GetTemplate"); m_ScriptInterface->RegisterFunction("TemplateExists"); m_ScriptInterface->RegisterFunction, std::string, bool, CMapGeneratorWorker::FindTemplates>("FindTemplates"); m_ScriptInterface->RegisterFunction, std::string, bool, CMapGeneratorWorker::FindActorTemplates>("FindActorTemplates"); m_ScriptInterface->RegisterFunction("GetTerrainTileSize"); // Parse settings JS::RootedValue settingsVal(cx); if (!m_ScriptInterface->ParseJSON(m_Settings, &settingsVal) && settingsVal.isUndefined()) { LOGERROR("CMapGeneratorWorker::Run: Failed to parse settings"); return false; } // Prevent unintentional modifications to the settings object by random map scripts if (!m_ScriptInterface->FreezeObject(settingsVal, true)) { LOGERROR("CMapGeneratorWorker::Run: Failed to deepfreeze settings"); return false; } // Init RNG seed u32 seed = 0; if (!m_ScriptInterface->HasProperty(settingsVal, "Seed") || !m_ScriptInterface->GetProperty(settingsVal, "Seed", seed)) LOGWARNING("CMapGeneratorWorker::Run: No seed value specified - using 0"); m_MapGenRNG.seed(seed); // Copy settings to global variable JS::RootedValue global(cx, m_ScriptInterface->GetGlobalObject()); if (!m_ScriptInterface->SetProperty(global, "g_MapSettings", settingsVal, true, true)) { LOGERROR("CMapGeneratorWorker::Run: Failed to define g_MapSettings"); return false; } // Load RMS LOGMESSAGE("Loading RMS '%s'", m_ScriptPath.string8()); if (!m_ScriptInterface->LoadGlobalScriptFile(m_ScriptPath)) { LOGERROR("CMapGeneratorWorker::Run: Failed to load RMS '%s'", m_ScriptPath.string8()); return false; } return true; } int CMapGeneratorWorker::GetProgress() { CScopeLock lock(m_WorkerMutex); return m_Progress; } shared_ptr CMapGeneratorWorker::GetResults() { CScopeLock lock(m_WorkerMutex); return m_MapData; } bool CMapGeneratorWorker::LoadLibrary(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name) { CMapGeneratorWorker* self = static_cast(pCxPrivate->pCBData); return self->LoadScripts(name); } void CMapGeneratorWorker::ExportMap(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue data) { CMapGeneratorWorker* self = static_cast(pCxPrivate->pCBData); // Copy results CScopeLock lock(self->m_WorkerMutex); self->m_MapData = self->m_ScriptInterface->WriteStructuredClone(data); self->m_Progress = 0; } void CMapGeneratorWorker::SetProgress(ScriptInterface::CxPrivate* pCxPrivate, int progress) { CMapGeneratorWorker* self = static_cast(pCxPrivate->pCBData); // Copy data CScopeLock lock(self->m_WorkerMutex); self->m_Progress = progress; } void CMapGeneratorWorker::MaybeGC(ScriptInterface::CxPrivate* pCxPrivate) { CMapGeneratorWorker* self = static_cast(pCxPrivate->pCBData); self->m_ScriptInterface->MaybeGC(); } -bool CMapGeneratorWorker::FileExists(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::wstring& filePath) -{ - return g_VFS->GetFileInfo(filePath, 0) == INFO::OK; -} - -JS::Value CMapGeneratorWorker::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath) -{ - JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue out(cx); - pCxPrivate->pScriptInterface->ReadJSONFile(filePath, &out); - return out; -} - std::vector CMapGeneratorWorker::GetCivData(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) { VfsPath path(L"simulation/data/civs/"); VfsPaths pathnames; std::vector data; // Load all JSON files in civs directory Status ret = vfs::GetPathnames(g_VFS, path, L"*.json", pathnames); if (ret == INFO::OK) { for (const VfsPath& p : pathnames) { // Load JSON file CVFSFile file; PSRETURN ret = file.Load(g_VFS, p); if (ret != PSRETURN_OK) LOGERROR("CMapGeneratorWorker::GetCivData: Failed to load file '%s': %s", p.string8(), GetErrorString(ret)); else data.push_back(file.DecodeUTF8()); // assume it's UTF-8 } } else { // Some error reading directory wchar_t error[200]; LOGERROR("CMapGeneratorWorker::GetCivData: Error reading directory '%s': %s", path.string8(), utf8_from_wstring(StatusDescription(ret, error, ARRAY_SIZE(error)))); } return data; } CParamNode CMapGeneratorWorker::GetTemplate(ScriptInterface::CxPrivate* pCxPrivate, const std::string& templateName) { CMapGeneratorWorker* self = static_cast(pCxPrivate->pCBData); const CParamNode& templateRoot = self->m_TemplateLoader.GetTemplateFileData(templateName).GetChild("Entity"); if (!templateRoot.IsOk()) LOGERROR("Invalid template found for '%s'", templateName.c_str()); return templateRoot; } bool CMapGeneratorWorker::TemplateExists(ScriptInterface::CxPrivate* pCxPrivate, const std::string& templateName) { CMapGeneratorWorker* self = static_cast(pCxPrivate->pCBData); return self->m_TemplateLoader.TemplateExists(templateName); } std::vector CMapGeneratorWorker::FindTemplates(ScriptInterface::CxPrivate* pCxPrivate, const std::string& path, bool includeSubdirectories) { CMapGeneratorWorker* self = static_cast(pCxPrivate->pCBData); return self->m_TemplateLoader.FindTemplates(path, includeSubdirectories, SIMULATION_TEMPLATES); } std::vector CMapGeneratorWorker::FindActorTemplates(ScriptInterface::CxPrivate* pCxPrivate, const std::string& path, bool includeSubdirectories) { CMapGeneratorWorker* self = static_cast(pCxPrivate->pCBData); return self->m_TemplateLoader.FindTemplates(path, includeSubdirectories, ACTOR_TEMPLATES); } int CMapGeneratorWorker::GetTerrainTileSize(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) { return TERRAIN_TILE_SIZE; } bool CMapGeneratorWorker::LoadScripts(const std::wstring& libraryName) { // Ignore libraries that are already loaded if (m_LoadedLibraries.find(libraryName) != m_LoadedLibraries.end()) return true; // Mark this as loaded, to prevent it recursively loading itself m_LoadedLibraries.insert(libraryName); VfsPath path = L"maps/random/" + libraryName + L"/"; VfsPaths pathnames; // Load all scripts in mapgen directory Status ret = vfs::GetPathnames(g_VFS, path, L"*.js", pathnames); if (ret == INFO::OK) { for (const VfsPath& p : pathnames) { LOGMESSAGE("Loading map generator script '%s'", p.string8()); if (!m_ScriptInterface->LoadGlobalScriptFile(p)) { LOGERROR("CMapGeneratorWorker::LoadScripts: Failed to load script '%s'", p.string8()); return false; } } } else { // Some error reading directory wchar_t error[200]; LOGERROR("CMapGeneratorWorker::LoadScripts: Error reading scripts in directory '%s': %s", path.string8(), utf8_from_wstring(StatusDescription(ret, error, ARRAY_SIZE(error)))); return false; } return true; } ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// CMapGenerator::CMapGenerator() : m_Worker(new CMapGeneratorWorker()) { } CMapGenerator::~CMapGenerator() { delete m_Worker; } void CMapGenerator::GenerateMap(const VfsPath& scriptFile, const std::string& settings) { m_Worker->Initialize(scriptFile, settings); } int CMapGenerator::GetProgress() { return m_Worker->GetProgress(); } shared_ptr CMapGenerator::GetResults() { return m_Worker->GetResults(); } Index: ps/trunk/source/gui/scripting/ScriptFunctions.cpp =================================================================== --- ps/trunk/source/gui/scripting/ScriptFunctions.cpp (revision 20506) +++ ps/trunk/source/gui/scripting/ScriptFunctions.cpp (revision 20507) @@ -1,70 +1,71 @@ /* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "scriptinterface/ScriptInterface.h" #include "graphics/scripting/JSInterface_GameView.h" #include "gui/IGUIObject.h" #include "gui/scripting/JSInterface_GUIManager.h" #include "gui/scripting/JSInterface_GUITypes.h" #include "i18n/scripting/JSInterface_L10n.h" #include "lobby/scripting/JSInterface_Lobby.h" #include "network/scripting/JSInterface_Network.h" #include "ps/scripting/JSInterface_ConfigDB.h" #include "ps/scripting/JSInterface_Console.h" #include "ps/scripting/JSInterface_Debug.h" #include "ps/scripting/JSInterface_Game.h" #include "ps/scripting/JSInterface_Main.h" #include "ps/scripting/JSInterface_Mod.h" #include "ps/scripting/JSInterface_SavedGame.h" #include "ps/scripting/JSInterface_VFS.h" #include "ps/scripting/JSInterface_VisualReplay.h" #include "renderer/scripting/JSInterface_Renderer.h" #include "simulation2/scripting/JSInterface_Simulation.h" #include "soundmanager/scripting/JSInterface_Sound.h" /* * This file defines a set of functions that are available to GUI scripts, to allow * interaction with the rest of the engine. * Functions are exposed to scripts within the global object 'Engine', so * scripts should call "Engine.FunctionName(...)" etc. */ void GuiScriptingInit(ScriptInterface& scriptInterface) { JSI_IGUIObject::init(scriptInterface); JSI_GUITypes::init(scriptInterface); JSI_ConfigDB::RegisterScriptFunctions(scriptInterface); JSI_Console::RegisterScriptFunctions(scriptInterface); JSI_Debug::RegisterScriptFunctions(scriptInterface); JSI_GUIManager::RegisterScriptFunctions(scriptInterface); JSI_Game::RegisterScriptFunctions(scriptInterface); JSI_GameView::RegisterScriptFunctions(scriptInterface); JSI_L10n::RegisterScriptFunctions(scriptInterface); JSI_Lobby::RegisterScriptFunctions(scriptInterface); JSI_Main::RegisterScriptFunctions(scriptInterface); JSI_Mod::RegisterScriptFunctions(scriptInterface); JSI_Network::RegisterScriptFunctions(scriptInterface); JSI_Renderer::RegisterScriptFunctions(scriptInterface); JSI_SavedGame::RegisterScriptFunctions(scriptInterface); JSI_Simulation::RegisterScriptFunctions(scriptInterface); JSI_Sound::RegisterScriptFunctions(scriptInterface); - JSI_VFS::RegisterScriptFunctions(scriptInterface); + JSI_VFS::RegisterReadOnlyScriptFunctions(scriptInterface); + JSI_VFS::RegisterWriteScriptFunctions(scriptInterface); JSI_VisualReplay::RegisterScriptFunctions(scriptInterface); } Index: ps/trunk/source/ps/scripting/JSInterface_VFS.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_VFS.cpp (revision 20506) +++ ps/trunk/source/ps/scripting/JSInterface_VFS.cpp (revision 20507) @@ -1,216 +1,220 @@ /* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include #include "ps/CLogger.h" #include "ps/CStr.h" #include "ps/Filesystem.h" #include "scriptinterface/ScriptVal.h" #include "scriptinterface/ScriptInterface.h" #include "ps/scripting/JSInterface_VFS.h" #include "lib/file/vfs/vfs_util.h" // shared error handling code #define JS_CHECK_FILE_ERR(err)\ /* this is liable to happen often, so don't complain */\ if (err == ERR::VFS_FILE_NOT_FOUND)\ {\ return 0; \ }\ /* unknown failure. We output an error message. */\ else if (err < 0)\ LOGERROR("Unknown failure in VFS %i", err ); /* else: success */ // state held across multiple BuildDirEntListCB calls; init by BuildDirEntList. struct BuildDirEntListState { JSContext* cx; JS::PersistentRootedObject filename_array; int cur_idx; BuildDirEntListState(JSContext* cx_) : cx(cx_), filename_array(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())), cur_idx(0) { } }; // called for each matching directory entry; add its full pathname to array. static Status BuildDirEntListCB(const VfsPath& pathname, const CFileInfo& UNUSED(fileINfo), uintptr_t cbData) { BuildDirEntListState* s = (BuildDirEntListState*)cbData; JSAutoRequest rq(s->cx); JS::RootedObject filenameArrayObj(s->cx, s->filename_array); JS::RootedValue val(s->cx); ScriptInterface::ToJSVal( s->cx, &val, CStrW(pathname.string()) ); JS_SetElement(s->cx, filenameArrayObj, s->cur_idx++, val); return INFO::OK; } // Return an array of pathname strings, one for each matching entry in the // specified directory. // // pathnames = buildDirEntList(start_path [, filter_string [, recursive ] ]); // directory: VFS path // filter_string: default "" matches everything; otherwise, see vfs_next_dirent. // recurse: should subdirectories be included in the search? default false. // // note: full pathnames of each file/subdirectory are returned, // ready for use as a "filename" for the other functions. JS::Value JSI_VFS::BuildDirEntList(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& path, const std::wstring& filterStr, bool recurse) { // convert to const wchar_t*; if there's no filter, pass 0 for speed // (interpreted as: "accept all files without comparing"). const wchar_t* filter = 0; if (!filterStr.empty()) filter = filterStr.c_str(); int flags = recurse ? vfs::DIR_RECURSIVE : 0; JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); JSAutoRequest rq(cx); // build array in the callback function BuildDirEntListState state(cx); vfs::ForEachFile(g_VFS, path, BuildDirEntListCB, (uintptr_t)&state, filter, flags); return OBJECT_TO_JSVAL(state.filename_array); } // Return true iff the file exits bool JSI_VFS::FileExists(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const CStrW& filename) { return (g_VFS->GetFileInfo(filename, 0) == INFO::OK); } // Return time [seconds since 1970] of the last modification to the specified file. double JSI_VFS::GetFileMTime(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::wstring& filename) { CFileInfo fileInfo; Status err = g_VFS->GetFileInfo(filename, &fileInfo); JS_CHECK_FILE_ERR(err); return (double)fileInfo.MTime(); } // Return current size of file. unsigned int JSI_VFS::GetFileSize(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::wstring& filename) { CFileInfo fileInfo; Status err = g_VFS->GetFileInfo(filename, &fileInfo); JS_CHECK_FILE_ERR(err); return (unsigned int)fileInfo.Size(); } // Return file contents in a string. Assume file is UTF-8 encoded text. JS::Value JSI_VFS::ReadFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename) { JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); JSAutoRequest rq(cx); CVFSFile file; if (file.Load(g_VFS, filename) != PSRETURN_OK) return JS::NullValue(); CStr contents = file.DecodeUTF8(); // assume it's UTF-8 // Fix CRLF line endings. (This function will only ever be used on text files.) contents.Replace("\r\n", "\n"); // Decode as UTF-8 JS::RootedValue ret(cx); ScriptInterface::ToJSVal(cx, &ret, contents.FromUTF8()); return ret; } // Return file contents as an array of lines. Assume file is UTF-8 encoded text. JS::Value JSI_VFS::ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename) { JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); JSAutoRequest rq(cx); CVFSFile file; if (file.Load(g_VFS, filename) != PSRETURN_OK) return JSVAL_NULL; CStr contents = file.DecodeUTF8(); // assume it's UTF-8 // Fix CRLF line endings. (This function will only ever be used on text files.) contents.Replace("\r\n", "\n"); // split into array of strings (one per line) std::stringstream ss(contents); JS::RootedObject line_array(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); std::string line; int cur_line = 0; while (std::getline(ss, line)) { // Decode each line as UTF-8 JS::RootedValue val(cx); ScriptInterface::ToJSVal(cx, &val, CStr(line).FromUTF8()); JS_SetElement(cx, line_array, cur_line++, val); } return JS::ObjectValue(*line_array); } JS::Value JSI_VFS::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath) { JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); JSAutoRequest rq(cx); JS::RootedValue out(cx); pCxPrivate->pScriptInterface->ReadJSONFile(filePath, &out); return out; } void JSI_VFS::WriteJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath, JS::HandleValue val1) { JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); JSAutoRequest rq(cx); // TODO: This is a workaround because we need to pass a MutableHandle to StringifyJSON. JS::RootedValue val(cx, val1); std::string str(pCxPrivate->pScriptInterface->StringifyJSON(&val, false)); VfsPath path(filePath); WriteBuffer buf; buf.Append(str.c_str(), str.length()); g_VFS->CreateFile(path, buf.Data(), buf.Size()); } -void JSI_VFS::RegisterScriptFunctions(const ScriptInterface& scriptInterface) +void JSI_VFS::RegisterReadOnlyScriptFunctions(const ScriptInterface& scriptInterface) { scriptInterface.RegisterFunction("BuildDirEntList"); scriptInterface.RegisterFunction("FileExists"); scriptInterface.RegisterFunction("GetFileMTime"); scriptInterface.RegisterFunction("GetFileSize"); scriptInterface.RegisterFunction("ReadFile"); scriptInterface.RegisterFunction("ReadFileLines"); scriptInterface.RegisterFunction("ReadJSONFile"); +} + +void JSI_VFS::RegisterWriteScriptFunctions(const ScriptInterface& scriptInterface) +{ scriptInterface.RegisterFunction("WriteJSONFile"); } Index: ps/trunk/source/ps/scripting/JSInterface_VFS.h =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_VFS.h (revision 20506) +++ ps/trunk/source/ps/scripting/JSInterface_VFS.h (revision 20507) @@ -1,67 +1,68 @@ /* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ // JSInterface_VFS.h // // The JavaScript wrapper around useful snippets of the VFS #ifndef INCLUDED_JSI_VFS #define INCLUDED_JSI_VFS #include "scriptinterface/ScriptInterface.h" // these are registered in ScriptFunctions.cpp, hence the need for a header. namespace JSI_VFS { // Return an array of pathname strings, one for each matching entry in the // specified directory. // // pathnames = buildDirEntList(start_path [, filter_string [, recursive ] ]); // directory: VFS path // filter_string: see match_wildcard; "" matches everything. // recurse: should subdirectories be included in the search? default false. // // note: full pathnames of each file/subdirectory are returned, // ready for use as a "filename" for the other functions. JS::Value BuildDirEntList(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& path, const std::wstring& filterStr, bool recurse); // Return true iff the file exists bool FileExists(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& filename); // Return time [seconds since 1970] of the last modification to the specified file. double GetFileMTime(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename); // Return current size of file. unsigned int GetFileSize(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename); // Return file contents in a string. JS::Value ReadFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename); // Return file contents as an array of lines. JS::Value ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename); // Return file contents parsed as a JS Object JS::Value ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath); // Save given JS Object to a JSON file void WriteJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath, JS::HandleValue val1); - void RegisterScriptFunctions(const ScriptInterface& scriptInterface); + void RegisterReadOnlyScriptFunctions(const ScriptInterface& scriptInterface); + void RegisterWriteScriptFunctions(const ScriptInterface& scriptInterface); } #endif