Changeset View
Changeset View
Standalone View
Standalone View
source/graphics/MapGenerator.cpp
Show All 25 Lines | |||||
#include "lib/status.h" | #include "lib/status.h" | ||||
#include "lib/timer.h" | #include "lib/timer.h" | ||||
#include "lib/file/vfs/vfs_path.h" | #include "lib/file/vfs/vfs_path.h" | ||||
#include "maths/MathUtil.h" | #include "maths/MathUtil.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/FileIo.h" | #include "ps/FileIo.h" | ||||
#include "ps/Profile.h" | #include "ps/Profile.h" | ||||
#include "ps/scripting/JSInterface_VFS.h" | #include "ps/scripting/JSInterface_VFS.h" | ||||
#include "scriptinterface/FunctionWrapper.h" | |||||
#include "scriptinterface/ScriptRuntime.h" | #include "scriptinterface/ScriptRuntime.h" | ||||
#include "scriptinterface/ScriptConversions.h" | #include "scriptinterface/ScriptConversions.h" | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include "simulation2/helpers/MapEdgeTiles.h" | #include "simulation2/helpers/MapEdgeTiles.h" | ||||
#include <string> | #include <string> | ||||
#include <vector> | #include <vector> | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | bool CMapGeneratorWorker::Run() | ||||
{ | { | ||||
LOGERROR("CMapGeneratorWorker::Run: Failed to load RMS '%s'", m_ScriptPath.string8()); | LOGERROR("CMapGeneratorWorker::Run: Failed to load RMS '%s'", m_ScriptPath.string8()); | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
#define Register(func, name) \ | |||||
Stan: RegisterFunctionMaybe? Can this be something else than a macro? | |||||
ScriptWrapper::WrapAndRegister<decltype(&CMapGeneratorWorker::func), &CMapGeneratorWorker::func, \ | |||||
CMapGeneratorWorker, CMapGeneratorWorker::GetWorkerFromCxPrivateData>(*m_ScriptInterface, name); | |||||
CMapGeneratorWorker* CMapGeneratorWorker::GetWorkerFromCxPrivateData(JSContext* cx, JS::CallArgs&) | |||||
{ | |||||
return static_cast<CMapGeneratorWorker*>(ScriptInterface::GetScriptInterfaceAndCBData(cx)->pCBData); | |||||
} | |||||
void CMapGeneratorWorker::InitScriptInterface(const u32 seed) | void CMapGeneratorWorker::InitScriptInterface(const u32 seed) | ||||
{ | { | ||||
m_ScriptInterface->SetCallbackData(static_cast<void*>(this)); | m_ScriptInterface->SetCallbackData(static_cast<void*>(this)); | ||||
m_ScriptInterface->ReplaceNondeterministicRNG(m_MapGenRNG); | m_ScriptInterface->ReplaceNondeterministicRNG(m_MapGenRNG); | ||||
m_MapGenRNG.seed(seed); | m_MapGenRNG.seed(seed); | ||||
// VFS | // VFS | ||||
JSI_VFS::RegisterScriptFunctions_Maps(*m_ScriptInterface); | JSI_VFS::RegisterScriptFunctions_Maps(*m_ScriptInterface); | ||||
// Globalscripts may use VFS script functions | // Globalscripts may use VFS script functions | ||||
m_ScriptInterface->LoadGlobalScripts(); | m_ScriptInterface->LoadGlobalScripts(); | ||||
// File loading | // File loading | ||||
m_ScriptInterface->RegisterFunction<bool, VfsPath, CMapGeneratorWorker::LoadLibrary>("LoadLibrary"); | Register(LoadScripts, "LoadLibrary"); | ||||
m_ScriptInterface->RegisterFunction<JS::Value, VfsPath, CMapGeneratorWorker::LoadHeightmap>("LoadHeightmapImage"); | Register(LoadHeightmapImage, "LoadHeightmapImage"); | ||||
m_ScriptInterface->RegisterFunction<JS::Value, VfsPath, CMapGeneratorWorker::LoadMapTerrain>("LoadMapTerrain"); | Register(LoadMapTerrain, "LoadMapTerrain"); | ||||
// Engine constants | // Engine constants | ||||
// Length of one tile of the terrain grid in metres. | // Length of one tile of the terrain grid in metres. | ||||
// Useful to transform footprint sizes to the tilegrid coordinate system. | // Useful to transform footprint sizes to the tilegrid coordinate system. | ||||
m_ScriptInterface->SetGlobal("TERRAIN_TILE_SIZE", static_cast<int>(TERRAIN_TILE_SIZE)); | m_ScriptInterface->SetGlobal("TERRAIN_TILE_SIZE", static_cast<int>(TERRAIN_TILE_SIZE)); | ||||
// Number of impassable tiles at the map border | // Number of impassable tiles at the map border | ||||
m_ScriptInterface->SetGlobal("MAP_BORDER_WIDTH", static_cast<int>(MAP_EDGE_TILES)); | m_ScriptInterface->SetGlobal("MAP_BORDER_WIDTH", static_cast<int>(MAP_EDGE_TILES)); | ||||
} | } | ||||
void CMapGeneratorWorker::RegisterScriptFunctions_MapGenerator() | void CMapGeneratorWorker::RegisterScriptFunctions_MapGenerator() | ||||
{ | { | ||||
// Template functions | // Template functions | ||||
m_ScriptInterface->RegisterFunction<CParamNode, std::string, CMapGeneratorWorker::GetTemplate>("GetTemplate"); | Register(GetTemplate, "GetTemplate"); | ||||
m_ScriptInterface->RegisterFunction<bool, std::string, CMapGeneratorWorker::TemplateExists>("TemplateExists"); | Register(TemplateExists, "TemplateExists"); | ||||
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindTemplates>("FindTemplates"); | Register(FindTemplates, "FindTemplates"); | ||||
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindActorTemplates>("FindActorTemplates"); | Register(FindActorTemplates, "FindActorTemplates"); | ||||
// Progression and profiling | // Progression and profiling | ||||
m_ScriptInterface->RegisterFunction<void, int, CMapGeneratorWorker::SetProgress>("SetProgress"); | Register(SetProgress, "SetProgress"); | ||||
m_ScriptInterface->RegisterFunction<double, CMapGeneratorWorker::GetMicroseconds>("GetMicroseconds"); | Register(GetMicroseconds, "GetMicroseconds"); | ||||
m_ScriptInterface->RegisterFunction<void, JS::HandleValue, CMapGeneratorWorker::ExportMap>("ExportMap"); | Register(ExportMap, "ExportMap"); | ||||
} | } | ||||
#undef Register | |||||
int CMapGeneratorWorker::GetProgress() | int CMapGeneratorWorker::GetProgress() | ||||
{ | { | ||||
std::lock_guard<std::mutex> lock(m_WorkerMutex); | std::lock_guard<std::mutex> lock(m_WorkerMutex); | ||||
return m_Progress; | return m_Progress; | ||||
} | } | ||||
double CMapGeneratorWorker::GetMicroseconds(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) | double CMapGeneratorWorker::GetMicroseconds() | ||||
{ | { | ||||
return JS_Now(); | return JS_Now(); | ||||
} | } | ||||
shared_ptr<ScriptInterface::StructuredClone> CMapGeneratorWorker::GetResults() | shared_ptr<ScriptInterface::StructuredClone> CMapGeneratorWorker::GetResults() | ||||
{ | { | ||||
std::lock_guard<std::mutex> lock(m_WorkerMutex); | std::lock_guard<std::mutex> lock(m_WorkerMutex); | ||||
return m_MapData; | return m_MapData; | ||||
} | } | ||||
bool CMapGeneratorWorker::LoadLibrary(ScriptInterface::CxPrivate* pCxPrivate, const VfsPath& name) | void CMapGeneratorWorker::ExportMap(JS::HandleValue data) | ||||
{ | |||||
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); | |||||
return self->LoadScripts(name); | |||||
} | |||||
void CMapGeneratorWorker::ExportMap(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue data) | |||||
{ | { | ||||
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); | |||||
// Copy results | // Copy results | ||||
std::lock_guard<std::mutex> lock(self->m_WorkerMutex); | std::lock_guard<std::mutex> lock(m_WorkerMutex); | ||||
self->m_MapData = self->m_ScriptInterface->WriteStructuredClone(data); | m_MapData = m_ScriptInterface->WriteStructuredClone(data); | ||||
self->m_Progress = 0; | m_Progress = 0; | ||||
} | } | ||||
void CMapGeneratorWorker::SetProgress(ScriptInterface::CxPrivate* pCxPrivate, int progress) | void CMapGeneratorWorker::SetProgress(int progress) | ||||
{ | { | ||||
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); | |||||
// Copy data | // Copy data | ||||
std::lock_guard<std::mutex> lock(self->m_WorkerMutex); | std::lock_guard<std::mutex> lock(m_WorkerMutex); | ||||
if (progress >= self->m_Progress) | if (progress >= m_Progress) | ||||
self->m_Progress = progress; | m_Progress = progress; | ||||
else | else | ||||
LOGWARNING("The random map script tried to reduce the loading progress from %d to %d", self->m_Progress, progress); | LOGWARNING("The random map script tried to reduce the loading progress from %d to %d", m_Progress, progress); | ||||
} | } | ||||
CParamNode CMapGeneratorWorker::GetTemplate(ScriptInterface::CxPrivate* pCxPrivate, const std::string& templateName) | CParamNode CMapGeneratorWorker::GetTemplate(const std::string& templateName) | ||||
{ | { | ||||
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); | const CParamNode& templateRoot = m_TemplateLoader.GetTemplateFileData(templateName).GetChild("Entity"); | ||||
const CParamNode& templateRoot = self->m_TemplateLoader.GetTemplateFileData(templateName).GetChild("Entity"); | |||||
if (!templateRoot.IsOk()) | if (!templateRoot.IsOk()) | ||||
LOGERROR("Invalid template found for '%s'", templateName.c_str()); | LOGERROR("Invalid template found for '%s'", templateName.c_str()); | ||||
return templateRoot; | return templateRoot; | ||||
} | } | ||||
bool CMapGeneratorWorker::TemplateExists(ScriptInterface::CxPrivate* pCxPrivate, const std::string& templateName) | bool CMapGeneratorWorker::TemplateExists(const std::string& templateName) | ||||
{ | { | ||||
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); | return m_TemplateLoader.TemplateExists(templateName); | ||||
return self->m_TemplateLoader.TemplateExists(templateName); | |||||
} | } | ||||
std::vector<std::string> CMapGeneratorWorker::FindTemplates(ScriptInterface::CxPrivate* pCxPrivate, const std::string& path, bool includeSubdirectories) | std::vector<std::string> CMapGeneratorWorker::FindTemplates(const std::string& path, bool includeSubdirectories) | ||||
{ | { | ||||
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); | return m_TemplateLoader.FindTemplates(path, includeSubdirectories, SIMULATION_TEMPLATES); | ||||
return self->m_TemplateLoader.FindTemplates(path, includeSubdirectories, SIMULATION_TEMPLATES); | |||||
} | } | ||||
std::vector<std::string> CMapGeneratorWorker::FindActorTemplates(ScriptInterface::CxPrivate* pCxPrivate, const std::string& path, bool includeSubdirectories) | std::vector<std::string> CMapGeneratorWorker::FindActorTemplates(const std::string& path, bool includeSubdirectories) | ||||
{ | { | ||||
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); | return m_TemplateLoader.FindTemplates(path, includeSubdirectories, ACTOR_TEMPLATES); | ||||
return self->m_TemplateLoader.FindTemplates(path, includeSubdirectories, ACTOR_TEMPLATES); | |||||
} | } | ||||
bool CMapGeneratorWorker::LoadScripts(const VfsPath& libraryName) | bool CMapGeneratorWorker::LoadScripts(const VfsPath& libraryName) | ||||
{ | { | ||||
// Ignore libraries that are already loaded | // Ignore libraries that are already loaded | ||||
if (m_LoadedLibraries.find(libraryName) != m_LoadedLibraries.end()) | if (m_LoadedLibraries.find(libraryName) != m_LoadedLibraries.end()) | ||||
return true; | return true; | ||||
Show All 24 Lines | else | ||||
wchar_t error[200]; | 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)))); | LOGERROR("CMapGeneratorWorker::LoadScripts: Error reading scripts in directory '%s': %s", path.string8(), utf8_from_wstring(StatusDescription(ret, error, ARRAY_SIZE(error)))); | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
JS::Value CMapGeneratorWorker::LoadHeightmap(ScriptInterface::CxPrivate* pCxPrivate, const VfsPath& filename) | std::vector<u16> CMapGeneratorWorker::LoadHeightmapImage(const VfsPath& filename) | ||||
{ | { | ||||
std::vector<u16> heightmap; | std::vector<u16> heightmap; | ||||
if (LoadHeightmapImageVfs(filename, heightmap) != INFO::OK) | if (LoadHeightmapImageVfs(filename, heightmap) != INFO::OK) | ||||
{ | { | ||||
LOGERROR("Could not load heightmap file '%s'", filename.string8()); | LOGERROR("Could not load heightmap file '%s'", filename.string8()); | ||||
return JS::UndefinedValue(); | m_ScriptInterface->ReportError(("Could not load heightmap file" + filename.string8()).c_str()); | ||||
} | } | ||||
return heightmap; | |||||
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); | |||||
JSContext* cx = self->m_ScriptInterface->GetContext(); | |||||
JSAutoRequest rq(cx); | |||||
JS::RootedValue returnValue(cx); | |||||
ToJSVal_vector(cx, &returnValue, heightmap); | |||||
return returnValue; | |||||
} | } | ||||
// See CMapReader::UnpackTerrain, CMapReader::ParseTerrain for the reordering | // See CMapReader::UnpackTerrain, CMapReader::ParseTerrain for the reordering | ||||
JS::Value CMapGeneratorWorker::LoadMapTerrain(ScriptInterface::CxPrivate* pCxPrivate, const VfsPath& filename) | JS::Value CMapGeneratorWorker::LoadMapTerrain(const VfsPath& filename) | ||||
{ | { | ||||
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); | |||||
JSContext* cx = self->m_ScriptInterface->GetContext(); | |||||
JSAutoRequest rq(cx); | |||||
if (!VfsFileExists(filename)) | if (!VfsFileExists(filename)) | ||||
{ | { | ||||
self->m_ScriptInterface->ReportError( | m_ScriptInterface->ReportError( | ||||
("Terrain file \"" + filename.string8() + "\" does not exist!").c_str()); | ("Terrain file \"" + filename.string8() + "\" does not exist!").c_str()); | ||||
return JS::UndefinedValue(); | return JS::UndefinedValue(); | ||||
} | } | ||||
CFileUnpacker unpacker; | CFileUnpacker unpacker; | ||||
unpacker.Read(filename, "PSMP"); | unpacker.Read(filename, "PSMP"); | ||||
if (unpacker.GetVersion() < CMapIO::FILE_READ_VERSION) | if (unpacker.GetVersion() < CMapIO::FILE_READ_VERSION) | ||||
{ | { | ||||
self->m_ScriptInterface->ReportError( | m_ScriptInterface->ReportError( | ||||
("Could not load terrain file \"" + filename.string8() + "\" too old version!").c_str()); | ("Could not load terrain file \"" + filename.string8() + "\" too old version!").c_str()); | ||||
return JS::UndefinedValue(); | return JS::UndefinedValue(); | ||||
} | } | ||||
// unpack size | // unpack size | ||||
ssize_t patchesPerSide = (ssize_t)unpacker.UnpackSize(); | ssize_t patchesPerSide = (ssize_t)unpacker.UnpackSize(); | ||||
size_t verticesPerSide = patchesPerSide * PATCH_SIZE + 1; | size_t verticesPerSide = patchesPerSide * PATCH_SIZE + 1; | ||||
Show All 30 Lines | for (ssize_t x = 0; x < tilesPerSide; ++x) | ||||
{ | { | ||||
size_t patchY = y / PATCH_SIZE; | size_t patchY = y / PATCH_SIZE; | ||||
size_t offY = y % PATCH_SIZE; | size_t offY = y % PATCH_SIZE; | ||||
// m_Priority and m_Tex2Index unused | // m_Priority and m_Tex2Index unused | ||||
textureIDs.push_back(tiles[(patchY * patchesPerSide + patchX) * SQR(PATCH_SIZE) + (offY * PATCH_SIZE + offX)].m_Tex1Index); | textureIDs.push_back(tiles[(patchY * patchesPerSide + patchX) * SQR(PATCH_SIZE) + (offY * PATCH_SIZE + offX)].m_Tex1Index); | ||||
} | } | ||||
} | } | ||||
JS::RootedValue returnValue(cx); | JS::RootedValue returnValue(m_ScriptInterface->GetContext()); | ||||
ScriptInterface::CreateObject( | ScriptInterface::CreateObject( | ||||
cx, | m_ScriptInterface->GetContext(), | ||||
&returnValue, | &returnValue, | ||||
"height", heightmap, | "height", heightmap, | ||||
"textureNames", textureNames, | "textureNames", textureNames, | ||||
"textureIDs", textureIDs); | "textureIDs", textureIDs); | ||||
return returnValue; | return returnValue; | ||||
} | } | ||||
Show All 26 Lines |
Wildfire Games · Phabricator
RegisterFunctionMaybe? Can this be something else than a macro?