#include #include #include #include #include #include #include #include #include #include #include #include // Console CLear String #define cons_clear std::cout << "\x1B[2J\x1B[H" // Make String Uppercase void ToUpperCase(std::string &str) { std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::toupper(c); }); } // Check if String is Valid Hex String bool isValidHex(const std::string &str) { for (char c : str) { if (!isxdigit(c)) { return false; } } return true; } // Check for tools void CheckTools() { std::vector installed; std::vector not_installed; int res = 0; res = system("makerom"); if (!res) { not_installed.push_back("makerom"); } else { installed.push_back("makerom"); } res = system("bannertool"); if (!res) { not_installed.push_back("bannertool"); } else { installed.push_back("bannertool"); } std::cout << " is set to: " << getenv("DEVKITPRO") << "\n"; std::cout << "Tools-Check:\n"; for (auto const &it : installed) { std::cout << "[+]" << it << " is installed!\n"; } for (auto const &it : not_installed) { std::cout << "[-]" << it << " is not installed!\n"; } } // Print Usage/Help void PrintHelp() { std::cout << "npi-build v0.1\n"; std::cout << "Commands:\n"; std::cout << "help: Display this\n"; std::cout << "generate : Create Project Files!\n"; std::cout << " type: 3dsx | cia3dsx\n"; std::cout << "generate-assist: Create Project Files with assistent!\n"; std::cout << "build: Build the Project!\n"; std::cout << "clean: Delete all files from build.\n"; std::cout << "edit-assist: Edit Project files with assist!\n"; std::cout << "check-tools: Check for Missing Tools!\n"; return; } // Function to generate Directories and Default Files void GenerateProjectDir(const std::string &dst_dir, int type_) { // Create Directories std::filesystem::create_directories(std::filesystem::path(dst_dir + "/app")); std::filesystem::create_directories(std::filesystem::path(dst_dir + "/gfx")); std::filesystem::create_directories( std::filesystem::path(dst_dir + "/romfs/gfx")); std::filesystem::create_directories(dst_dir + "/source"); std::filesystem::create_directories(dst_dir + "/include"); // Create .gitkeep for empty dirs std::ofstream gfx_keep(dst_dir + "/gfx/.gitkeep"); gfx_keep.close(); std::ofstream rgfx_keep(dst_dir + "/romfs/gfx/.gitkeep"); rgfx_keep.close(); std::ofstream sample_source(dst_dir + "/source/main.cpp"); sample_source << sample_code; sample_source.close(); std::ofstream sample_hdr(dst_dir + "/include/common.hpp"); sample_hdr << sample_header; sample_hdr.close(); if (type_ == 1) { helper::ArrayToFile(banner_audio, banner_audio_size, dst_dir + "/app/banner_audio.wav"); helper::ArrayToFile(logo_lz11, logo_lz11_size, dst_dir + "/app/logo.lz11"); helper::ArrayToFile(banner, banner_size, dst_dir + "/app/banner.png"); } // Create icon.png helper::ArrayToFile(icon, icon_size, dst_dir + "/app/icon.png"); } // Process Input Args void ProcessArgs(int argc, char *argv[]) { if (argc < 2) { // No Args PrintHelp(); return; } else if (std::string(argv[1]) == "help") { // Requested Help PrintHelp(); return; } else if (std::string(argv[1]) == "generate") { // Generator if (argc != 4) { // Missing Args / ot too much std::cout << "Wrong Number of Arguments!\n"; return; } // read type std::string type = std::string(argv[2]); int res = 1; int type_ = -1; // TODO: // change this if statement if (type == "3dsx" | type == "cia3dsx") { res = 0; if (type == "3dsx") type_ = 0; else if (type == "cia3dsx") type_ = 1; } // Print Error if re is not 0 if (res) { std::cout << "Unknown type!\n"; return; } // get destination std::string dst_dir = argv[3]; std::cout << "\nDestination: " << dst_dir << "/\n"; // Generate Project GenerateProjectDir(dst_dir, type_); // Create rsf if cia mode if (type_ == 1) { char *ret = new char[10000]; std::string uid = helper::GenerateUniqueId(); sprintf(ret, ciaRSF, default_title, default_code, default_romfs_path, uid.c_str()); std::ofstream test(dst_dir + "/app/build-cia.rsf"); test << ret; test.close(); delete[] ret; } // Generate Default build.json NpiProject npr; Prj_InitDefault(npr, (type_ == 1)); helper::GenerateTemplateFile(dst_dir + "/build.json", npr); } else if (std::string(argv[1]) == "generate-assist") { // Generate with Assistant // define vars std::string prj_name; std::string prodcode; std::string unique_id; int type_; std::string dst_dir; // Request Name std::cout << "Npi-Build Project-Assist:"; std::cout << "\ntype Project Name >"; std::cin >> prj_name; // Request Prod Code std::cout << "\ntype Product Code 4 chars [NPI7] >"; std::cin >> prodcode; if (prodcode.length() != 4) { // Handle Wrong lengh Error std::cout << "\nWrong Length!\n"; return; } // Make Sure its Uppercase ToUpperCase(prodcode); // Output Prod Code and request unique_id std::cout << "Code set to [" << prodcode << "]"; std::cout << "\ntype project's unique id [ff3ff]\n or type random to " "generate a random one>"; std::cin >> unique_id; // Check if random keyword was used bool rnd = false; if (unique_id == "random") { // Generate random one unique_id = helper::GenerateUniqueId(); rnd = true; } if (unique_id.length() != 5 && !rnd) { // Handle wrong lengh std::cout << "\nWrong Length!\n"; return; } if (!isValidHex(unique_id) && !rnd) { // Handle not hex digits std::cout << "\nId is not valid\n"; return; } if (!rnd) { // Add 0x if not random unique_id.insert(0, "0x"); } // Request Project type std::cout << "\nProject type: type 0 for 3dsx\nonly or 1 for cia and 3dsx>"; std::cin >> type_; if (!(type_ == 0 | type_ == 1)) { std::cout << "\nunknown type!\n"; return; } // Request Destination Directory std::cout << "\nProjects Directpry: type . for current>"; std::cin >> dst_dir; std::cout << "\nDestination: " << dst_dir << "/\n"; // Generate default dirs and files GenerateProjectDir(dst_dir, type_); // Generate RSF if cia mode if (type_ == 1) { char *ret = new char[10000]; sprintf(ret, ciaRSF, prj_name.c_str(), prodcode.c_str(), default_romfs_path, unique_id.c_str()); std::ofstream test(dst_dir + "/app/build-cia.rsf"); test << ret; test.close(); delete[] ret; } // Create build.json NpiProject npr; Prj_InitDefault(npr, (type_ == 1)); npr.name = prj_name; if (npr.ctr_type) { npr.prod = prodcode; npr.unique_id = unique_id; } helper::GenerateTemplateFile(dst_dir + "/build.json", npr); } else if (std::string(argv[1]) == "build") { bool as = false; if (argc == 3) { if (std::string(argv[2]) == "async") { as = true; } } // Run over build.json and build project helper::CompileProject(fix_path(std::filesystem::current_path().string()), as); } // Check for makerom and bannertool else if (std::string(argv[1]) == "check-tools") CheckTools(); // Cleanup else if (std::string(argv[1]) == "clean") helper::CleanProject(fix_path(std::filesystem::current_path().string())); } // Main Entrypoint int main(int argc, char *argv[]) { // Process Input ProcessArgs(argc, argv); // Finished std::cout << "Exitting...\n"; return 0; }