1- #include < filesystem>
21#pragma warning(disable : 4251)
32
3+ #include " main/NodeJsHelper.h"
4+
45#include " api/EventAPI.h"
56#include " engine/EngineManager.h"
67#include " engine/EngineOwnData.h"
1516#include " ll/api/thread/ServerThreadExecutor.h"
1617#include " ll/api/utils/StringUtils.h"
1718#include " main/Global.h"
18- #include " main/NodeJsHelper .h"
19+ #include " utils/Utils .h"
1920#include " uv/uv.h"
2021#include " v8/v8.h"
2122
22- #include < functional>
23-
2423using ll::chrono_literals::operator " " _tick;
2524
2625// pre-declare
@@ -41,24 +40,25 @@ std::vector<node::Environment*> uvLoopTask;
4140
4241bool initNodeJs () {
4342 // Init NodeJs
44- WCHAR buf[MAX_PATH];
45- GetCurrentDirectory (MAX_PATH, buf);
46- auto path = ll::string_utils::wstr2str (buf) + " \\ bedrock_server_mod.exe" ;
43+ auto path = ll::string_utils::u8str2str (ll::sys_utils::getModulePath (nullptr ).value ().u8string ());
4744 char * cPath = (char *)path.c_str ();
4845 uv_setup_args (1 , &cPath);
49- args = {path};
50- auto result = node::InitializeOncePerProcess (
51- args ,
46+ auto full_args = std::vector<std::string> {path};
47+ auto result = node::InitializeOncePerProcess (
48+ full_args ,
5249 {node::ProcessInitializationFlags::kNoInitializeV8 ,
53- node::ProcessInitializationFlags::kNoInitializeNodeV8Platform }
50+ node::ProcessInitializationFlags::kNoInitializeNodeV8Platform }
5451 );
55- exec_args = result->exec_args ();
5652 if (result->exit_code () != 0 ) {
5753 lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ().error (
5854 " Failed to initialize node! NodeJs plugins won't be loaded"
5955 );
56+ for (const std::string& error : result->errors ())
57+ lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ().error (error);
6058 return false ;
6159 }
60+ args = result->args ();
61+ exec_args = result->exec_args ();
6262
6363 // Init V8
6464 using namespace v8 ;
@@ -382,8 +382,8 @@ bool isESModulesSystem(const std::string& dirPath) {
382382
383383bool processConsoleNpmCmd (const std::string& cmd) {
384384#ifdef LEGACY_SCRIPT_ENGINE_BACKEND_NODEJS
385- if (cmd.starts_with (" npm " )) {
386- executeNpmCommand (cmd);
385+ if (cmd.starts_with (" npm " ) || cmd. starts_with ( " npx " ) ) {
386+ executeNpmCommand (SplitCmdLine ( cmd) );
387387 return false ;
388388 } else {
389389 return true ;
@@ -393,21 +393,35 @@ bool processConsoleNpmCmd(const std::string& cmd) {
393393#endif
394394}
395395
396- int executeNpmCommand (const std::string& cmd , std::string workingDir) {
396+ int executeNpmCommand (std::vector<std:: string> npmArgs , std::string workingDir) {
397397 if (!nodeJsInited && !initNodeJs ()) {
398398 return -1 ;
399399 }
400400 std::string engineDir =
401401 ll::string_utils::u8str2str (lse::LegacyScriptEngine::getInstance ().getSelf ().getModDir ().u8string ());
402402 if (workingDir.empty ()) workingDir = engineDir;
403- std::vector<std::string> errors;
403+
404+ auto npmPath = std::filesystem::absolute (engineDir) / " node_modules" / " npm" / " bin" / " npm-cli.js" ;
405+ std::vector<std::string>& env_args = npmArgs;
406+ if (!env_args.empty () && (env_args[0 ] == " npm" || env_args[0 ] == " npx" )) {
407+ if (env_args[0 ] == " npx" ) {
408+ npmPath = std::filesystem::absolute (engineDir) / " node_modules" / " npm" / " bin" / " npx-cli.js" ;
409+ }
410+ env_args.erase (env_args.begin ());
411+ }
412+ auto scriptPath = ll::string_utils::replaceAll (ll::string_utils::u8str2str (npmPath.u8string ()), " \\ " , " /" );
413+ env_args.insert (env_args.begin (), {args[0 ], scriptPath});
414+
415+ std::vector<std::string> errors;
416+
404417 std::unique_ptr<node::CommonEnvironmentSetup> setup = node::CommonEnvironmentSetup::Create (
405418 platform.get (),
406419 &errors,
407- args ,
420+ env_args ,
408421 exec_args,
409422 node::EnvironmentFlags::kOwnsProcessState
410423 );
424+
411425 // if kOwnsInspector set, inspector_agent.cc:681
412426 // CHECK_EQ(start_io_thread_async_initialized.exchange(true), false) fail!
413427
@@ -437,26 +451,40 @@ int executeNpmCommand(const std::string& cmd, std::string workingDir) {
437451 R"(
438452 const engineDir = "{0}";
439453 const workingDir = "{1}";
440- const command = "{2}";
441- const oldCwd = process.cwd();
454+ const scriptPath = "{2}";
442455 const publicRequire = require("module").createRequire(
443456 require("path").resolve(engineDir) + require("path").sep
444457 );
458+ // Record states and restore at exit
459+ const oldCwd = process.cwd();
460+ const oldEnv = Object.entries(process.env).filter(([k]) => k.startsWith("npm_"));
461+ const oldTitle = process.title;
462+ process.on("exit", () => {{
463+ Object.keys(process.env)
464+ .filter((k) => k.startsWith("npm_"))
465+ .forEach((k) => delete process.env[k]);
466+ oldEnv.forEach(([k, v]) => (process.env[k] = v));
467+ process.title = oldTitle;
468+ process.chdir(oldCwd);
469+ }});
470+
445471 process.chdir(workingDir);
446- publicRequire("npm-js-interface")(command);
447- process.chdir(oldCwd);
472+ publicRequire(scriptPath);
448473 )" ,
449474 engineDir,
450475 workingDir,
451- cmd
476+ scriptPath
452477 );
453478
454479 try {
455- node::SetProcessExitHandler (env, [&](node::Environment* env_, int exit_code) { node::Stop (env); });
480+ node::SetProcessExitHandler (env, [&](node::Environment*, int exit_code_) {
481+ exit_code = exit_code_;
482+ node::Stop (env);
483+ });
456484 MaybeLocal<v8::Value> loadenv_ret = node::LoadEnvironment (env, executeJs);
457485 if (loadenv_ret.IsEmpty ()) // There has been a JS exception.
458- throw " error " ;
459- exit_code = node::SpinEventLoop (env).FromMaybe (0 );
486+ throw std::runtime_error ( " Failed at LoadEnvironment " ) ;
487+ exit_code = node::SpinEventLoop (env).FromMaybe (exit_code );
460488 } catch (...) {
461489 lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ().error (
462490 " Fail to execute NPM command. Error occurs"
0 commit comments