diff --git a/src/engine/cmdline/Build.cpp b/src/engine/cmdline/Build.cpp index f10d688e..09719e11 100644 --- a/src/engine/cmdline/Build.cpp +++ b/src/engine/cmdline/Build.cpp @@ -1,7 +1,44 @@ -#include "cmdline.h" - -namespace eve +#include "cmdline/cmdline.h" +#include +#include +#include +using namespace std; +namespace eve::cmd { + +struct BuildArgs : Handler { + string log_path, platform, output_path; + bool release = false, debug = false; + + void setup(CLI::App& app, std::shared_ptr formatter) override { + auto build = app.add_subcommand("build", "Build the game under current path"); + build->allow_extras()->formatter(formatter); + build->add_option("-p,--platform", platform, "Build platform (linux, macosx, win32, win32_uwp, ios, android)"); + build->add_flag("-r,--release", release, "release build (default)"); + build->add_flag("-d,--debug", debug, "debug build"); + build->add_option("-l,--log", log_path, "log messages into a file"); + build->add_option("-o,--output", output_path, "output folder path"); + } + + int parse(CLI::App& app, Cmdline& cmd) override { + auto build = app.get_subcommand("build"); + if (build->parsed()) { + if (debug && release) { + cerr << rang::fg::red << "Build type can not be both debug and release" << rang::fg::reset << endl; + exit(1); + } + if (!debug && !release) { release = true; } + + string current_path = cmd.get_remaining(build); + return cmd.Build(current_path, output_path, platform); + } + return -1; // not handle + } +}; + +CMD_REG(BuildArgs); + + int Cmdline::Build(std::string path, std::string output, std::string platform) { return 0; diff --git a/src/engine/cmdline/Create.cpp b/src/engine/cmdline/Create.cpp index 2bb3dd40..a054d09a 100644 --- a/src/engine/cmdline/Create.cpp +++ b/src/engine/cmdline/Create.cpp @@ -1,11 +1,33 @@ #include "cmdline.h" #include +#include +#include using namespace std::filesystem; +using namespace std; -namespace eve +namespace eve::cmd { +struct CreateArgs : Handler { + void setup(CLI::App& app, std::shared_ptr formatter) override { + auto create = app.add_subcommand("create", "Create a new game from template"); + create->allow_extras(); + } + + int parse(CLI::App& app, Cmdline& cmd) override { + auto create = app.get_subcommand("create"); + if (create->parsed()) { + string name = cmd.get_remaining(create, "mygame"); + int res = cmd.Create(".", name); + if (res == 0) cout << rang::fg::green << "Created " << name << " in current path" << rang::fg::reset << endl; + return res; + } + return -1; // not handle + } +}; + +CMD_REG(CreateArgs); // create a new project diff --git a/src/engine/cmdline/Readme.md b/src/engine/cmdline/Readme.md index 8832a7ea..cd2c4174 100644 --- a/src/engine/cmdline/Readme.md +++ b/src/engine/cmdline/Readme.md @@ -12,13 +12,22 @@ Cmdline 其中核心是执行、测试、创建、打包 -执行逻辑: +执行逻辑(目录): 1. 创建脚本VM 2. 查看当前文件夹下是否有启动脚本 boot.nut 有: 加载 没有: 加载默认boot脚本 3. 运行脚本 +执行逻辑(压缩包): +1. 加载压缩包内文件系统 +2. 创建脚本VM +3. 查看当前文件夹下是否有启动脚本 boot.nut + 有: 加载 + 没有: 加载默认boot脚本 +4. 运行脚本 + + 开发服务器逻辑: 1. 创建脚本VM 2. 查看当前文件夹下是否有启动脚本 diff --git a/src/engine/cmdline/Run.cpp b/src/engine/cmdline/Run.cpp index 1a9a14dd..4ab66c24 100644 --- a/src/engine/cmdline/Run.cpp +++ b/src/engine/cmdline/Run.cpp @@ -3,10 +3,39 @@ #include "common/Module.h" #include +#include +#include -namespace eve +using namespace std; + +namespace eve::cmd { +struct RunArgs : Handler { + string log_path; + bool no_window = false, debug = false; + + void setup(CLI::App& app, std::shared_ptr formatter) override { + auto run = app.add_subcommand("run", "Run game under current path"); + run->allow_extras()->formatter(formatter); + run->add_flag("--no-window", no_window, "Run script only, no window mode"); + run->add_flag("--debug", debug, "debug mode"); + run->add_option("-l,--log", log_path, "log messages into a file"); + } + + int parse(CLI::App& app, Cmdline& cmd) override { + auto run = app.get_subcommand("run"); + if (run->parsed() || cmd.getArgc() == 1) { + string current_path = cmd.get_remaining(run); + return cmd.Run(current_path); + } + return -1; // not handle + } +}; + +CMD_REG(RunArgs); + + // create a new project int Cmdline::Run(std::string path) { ssq::VM vm(2048, ssq::Libs::ALL); diff --git a/src/engine/cmdline/cmdline.cpp b/src/engine/cmdline/cmdline.cpp index 9265d85a..dd9d0171 100644 --- a/src/engine/cmdline/cmdline.cpp +++ b/src/engine/cmdline/cmdline.cpp @@ -1,13 +1,36 @@ -#include "cmdline.h" +#include "cmdline/cmdline.h" +#include "common/config.h" #include - -namespace eve +#include +#include +#include +using namespace std; +namespace eve::cmd { Module_IMPL(Cmdline, new Cmdline()); -Cmdline::Cmdline() {} +std::vector>& Cmdline::handers() { + static std::vector> cmds = {}; + return cmds; +} +void Cmdline::registerCmd(std::function handler) { + handers().push_back(handler); +} + +class MyFormatter : public CLI::Formatter { +public: + std::string make_usage(const CLI::App *app, std::string name) const override { + std::string usage = "Usage: "; + usage += name; + usage += " [Options] [Root Folder]"; + return usage; + } +}; + + +Cmdline::Cmdline() {} void Cmdline::expose(ssq::Table& table) { auto cls = table.addClass(name, Cmdline::create, false); @@ -18,6 +41,56 @@ void Cmdline::expose(ssq::Class& cls) { cls.addFunc("getName", &Cmdline::getName); } +int Cmdline::runArgs(unsigned argc, char** argv) { + CLI::App app{"EVEngine - A Modern Game Engine"}; + bool version; + app.add_flag("-v,--version", version, "Print version string"); + auto formatter = std::make_shared(); + + std::vector handles; + for (auto cmd : handers()) { + auto* p = cmd(); + handles.push_back(p); + p->setup(app, formatter); + } + + try { + this->argc = argc; + this->argv = argv; + app.parse(argc, argv); + } catch (const CLI::ParseError &e) { + for (auto* h : handles) delete h; + int res = app.exit(e); + return res; + } + + int res = 0; + for (auto* h : handles) { + if (int r = h->parse(app, *this); r != -1) { + res = r; break; + } + } + if (version) cout << EVENGINE_VERSION << endl; + + for (auto* h : handles) delete h; + return res; +} + + + +std::string Cmdline::get_remaining(CLI::App* sub, std::string default_path) { + auto paths = sub->remaining(); + if (paths.size() > 1) { + cerr << rang::fg::red << "Unknown remaining arguments: " << rang::fg::reset << paths[1] << endl; + exit(1); + } + if (paths.size() == 0) { + return default_path; + } + return paths[0]; +} + + } // namespace eve diff --git a/src/engine/cmdline/cmdline.h b/src/engine/cmdline/cmdline.h index de44f00e..7ba6083e 100644 --- a/src/engine/cmdline/cmdline.h +++ b/src/engine/cmdline/cmdline.h @@ -1,12 +1,29 @@ #pragma once #include +#include +#include #include "common/Module.h" +namespace CLI +{ + class App; + class Formatter; +} // namespace CLI -namespace eve { + +namespace eve::cmd { + +class Cmdline; +class Register; +struct Handler { + virtual ~Handler() {} + virtual void setup(CLI::App&, std::shared_ptr) = 0; + virtual int parse(CLI::App&, Cmdline&) = 0; +}; class Cmdline : public Module { + public: Module_REG(Cmdline); @@ -39,13 +56,35 @@ public: // create a new project int Create(std::string path, std::string name); - // this will be used in physfs filesystem - void setArg0(std::string arg0) { this->arg0 = arg0; } - std::string getArg0() { return arg0; } + // this will run passed argv by parsing it + int runArgs(unsigned argc, char** argv); + // this will be used in physfs filesystem + std::string getArgv(unsigned i) { return argv[i]; } + unsigned getArgc() { return argc; } + + static std::string get_remaining(CLI::App* sub, std::string default_path = "."); + + friend Register; protected: Cmdline(); - std::string arg0; + + unsigned argc; + char** argv; + + static std::vector>& handers(); + static void registerCmd(std::function handler); }; +#define CMD_REG(name) \ + static eve::cmd::Handler* name##_create() { return new name(); } \ + Register name##_cmd_reg(name##_create) + +struct Register { + Register(std::function handler) { + Cmdline::registerCmd(handler); + } +}; + + } // namespace eve diff --git a/src/engine/main.cpp b/src/engine/main.cpp index 46495733..1286f3da 100644 --- a/src/engine/main.cpp +++ b/src/engine/main.cpp @@ -31,65 +31,5 @@ public: int main(int argc, char **argv) { - string log_path, output_path, current_path, platform; - bool version = false, no_window = false, debug = false, release = false; - int res = 0; - - CLI::App app{"EVEngine - A Modern Game Engine"}; - app.add_flag("-v,--version", version, "Print version string"); - auto formatter = std::make_shared(); - - auto run = app.add_subcommand("run", "Run game under current path"); - run->allow_extras()->formatter(formatter); - run->add_flag("--no-window", no_window, "Run script only, no window mode"); - run->add_flag("--debug", debug, "debug mode"); - run->add_option("-l,--log", log_path, "log messages into a file"); - - auto build = app.add_subcommand("build", "Build the game under current path"); - build->allow_extras()->formatter(formatter); - build->add_option("-p,--platform", platform, "Build platform (linux, macosx, win32, win32_uwp, ios, android)"); - build->add_flag("-r,--release", release, "release build (default)"); - build->add_flag("-d,--debug", debug, "debug build"); - build->add_option("-l,--log", log_path, "log messages into a file"); - - auto create = app.add_subcommand("create", "Create a new game from template"); - create->allow_extras(); - - - try { - app.parse(argc, argv); - } catch (const CLI::ParseError &e) { - return app.exit(e); - } - - Cmdline* cmd = Cmdline::create(); - cmd->setArg0(argv[0]); - - if (build->parsed()) { - if (debug && release) { - cerr << rang::fg::red << "Build type can not be both debug and release" << rang::fg::reset << endl; - exit(1); - } - if (!debug && !release) { release = true; } - - current_path = get_remaining(run); - res = cmd->Build(current_path, output_path, platform); - } - - if (create->parsed()) { - string name = get_remaining(create, "mygame"); - res = cmd->Create(".", name); - cout << rang::fg::green << "Created " << name << " in current path" << rang::fg::reset << endl; - } - - if (run->parsed() || argc == 1) { - current_path = get_remaining(run); - res = cmd->Run(current_path); - } - - if (version) { - cout << EVENGINE_VERSION << endl; - } - - return res; + return requireModInst(eve::cmd,Cmdline)->runArgs(argc, argv); } \ No newline at end of file diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index 68f6c10d..c474e021 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -89,7 +89,7 @@ namespace physfs { Filesystem::Filesystem() : fused(false), fusedSet(false) { requirePath = {"?.lua", "?/init.lua"}; cRequirePath = {"??"}; - if (auto* c = getModInst(eve,Cmdline)) init(c->getArg0().c_str()); + if (auto* c = getModInst(eve::cmd,Cmdline)) init(c->getArgv(0).c_str()); else init(NULL); } diff --git a/test/filesystem.nut b/test/filesystem.nut index 5d161cc5..4b185b18 100644 --- a/test/filesystem.nut +++ b/test/filesystem.nut @@ -35,5 +35,8 @@ function readDir() { print(p.getName()); return false; } + p.setIdentity("mygame", true); + p.setupWriteDirectory(); + p.setSource("."); return true; } \ No newline at end of file