diff --git a/Caprica/main.cpp b/Caprica/main.cpp index 61e7f4d..477e126 100644 --- a/Caprica/main.cpp +++ b/Caprica/main.cpp @@ -88,7 +88,7 @@ static const std::unordered_set FAKE_SKYRIM_SCRIPTS_SET = { "fake://skyrim/__ScriptObject.psc", "fake://skyrim/DLC1SCWispWallScript.psc", }; - +static caseless_unordered_identifier_set abs_import_dirs {}; bool handleImports(const std::vector &f, caprica::CapricaJobManager *jobManager); PapyrusCompilationNode *getNode(const PapyrusCompilationNode::NodeType &nodeType, @@ -308,12 +308,14 @@ bool handleImports(const std::vector &f, caprica::CapricaJobManager } std::cout << "Importing files..." << std::endl; int i = 0; + abs_import_dirs.reserve(f.size()); for (auto& dir : f) { std::string ns = ""; if (conf::Papyrus::game > GameID::Skyrim) ns = "!!temp" + std::to_string(i++); if (!addFilesFromDirectory(dir, true, "", jobManager, PapyrusCompilationNode::NodeType::PapyrusImport, ns)) return false; + abs_import_dirs.emplace(std::filesystem::absolute(dir).string()); } CapricaStats::outputImportedCount(); caprica::papyrus::PapyrusCompilationContext::RenameImports(jobManager); @@ -349,7 +351,27 @@ bool addSingleFile(const std::string &f, auto ppath = caprica::FSUtils::parentPathAsRef(f); if (ppath.compare(filename.c_str()) != 0) { namespaceDir += ppath; - absBaseDir = absBaseDir.find(namespaceDir) != std::string::npos ? absBaseDir.substr(0, absBaseDir.find(namespaceDir)) : absBaseDir; + absBaseDir = absBaseDir.rfind(namespaceDir) != std::string::npos + ? absBaseDir.substr(0, absBaseDir.rfind(namespaceDir)) + : absBaseDir; + } + } else { + // PCompiler-like namespace resolution by scanning imports + bool found = false; + for (auto& dir : abs_import_dirs) { + auto relPath = std::filesystem::relative(f, dir); + // check if relpath begins with ".." + if (relPath != path && !relPath.string().starts_with("..")) { + namespaceDir += relPath.parent_path().string(); + absBaseDir = dir; + found = true; + break; + } + } + if (!found) { + std::cout << "ERROR: Absolute file path '" << f << "' is not in an import directory, cannot resolve namespace!" + << std::endl; + return false; } } auto namespaceName = namespaceDir; diff --git a/Caprica/main_options.cpp b/Caprica/main_options.cpp index a15e439..62d01d3 100644 --- a/Caprica/main_options.cpp +++ b/Caprica/main_options.cpp @@ -538,7 +538,7 @@ bool parseCommandLineArguments(int argc, char* argv[], caprica::CapricaJobManage parseUserFlags(std::move(flagsPath)); } else { - if (conf::Papyrus::game == GameID::Starfield){ + if (conf::Papyrus::game == GameID::Starfield) { std::cout << "No flags specified, Using default Starfield flags file." << std::endl; parseUserFlags("fake://Starfield/Starfield_Papyrus_Flags.flg"); } diff --git a/Caprica/papyrus/PapyrusCompilationContext.cpp b/Caprica/papyrus/PapyrusCompilationContext.cpp index 2ad7db7..818f743 100644 --- a/Caprica/papyrus/PapyrusCompilationContext.cpp +++ b/Caprica/papyrus/PapyrusCompilationContext.cpp @@ -545,7 +545,6 @@ static void renameMap(const PapyrusNamespace* child, TempRenameMap& tempRenameMa } void PapyrusCompilationContext::RenameImports(CapricaJobManager* jobManager) { - // TODO: Make sure that this is actually idempotent; we call it again in main() if (conf::General::compileInParallel) jobManager->startup((uint32_t)std::thread::hardware_concurrency());