nmdk
Version:
CLI tool for downloading and setting up Minecraft mod development kits (MDK) for Forge, Fabric, and NeoForge
118 lines (98 loc) • 5.93 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const chalk = require('chalk');
const { retrieveLatestLoaderVersion } = require('./utils/download');
const { collectModConfigurationData, requestProjectCreationConfirmation } = require('./utils/prompts');
const { initializeForgeProject } = require('./loaders/forge');
const { initializeFabricProject } = require('./loaders/fabric');
const { initializeNeoForgeProject } = require('./loaders/neoforge');
async function initializeModProject(modName, mcVersion, loader, loaderVersion) {
try {
displayProjectInitializationHeader(modName, mcVersion, loader, loaderVersion);
validateProjectParameters(modName, mcVersion, loader, loaderVersion);
const projectPath = path.resolve(modName);
if (await fs.pathExists(projectPath)) {
throw new Error(`Directory ${modName} already exists`);
}
let actualLoaderVersion = loaderVersion;
if (loaderVersion === 'latest') {
actualLoaderVersion = await retrieveLatestLoaderVersion(loader, mcVersion);
}
const modConfig = await collectModConfigurationData(modName);
const confirmed = await requestProjectCreationConfirmation(modConfig);
if (!confirmed) {
console.log(chalk.yellow('Project creation cancelled'));
return;
}
await fs.ensureDir(projectPath);
await configureProjectByLoader(loader, modName, mcVersion, actualLoaderVersion, projectPath, modConfig);
displayProjectCompletionSummary(modName, loader, mcVersion, actualLoaderVersion);
} catch (error) {
throw new Error(`Failed to create project: ${error.message}`);
}
}
function validateProjectParameters(modName, mcVersion, loader, loaderVersion) {
if (!modName || modName.trim().length === 0) {
throw new Error('Mod name cannot be empty');
}
if (!mcVersion || !/^\d+\.\d+(\.\d+)?$/.test(mcVersion)) {
throw new Error('Minecraft version must be in format X.Y or X.Y.Z');
}
const validLoaders = ['forge', 'fabric', 'neoforge'];
if (!validLoaders.includes(loader.toLowerCase())) {
throw new Error(`Invalid loader. Must be one of: ${validLoaders.join(', ')}`);
}
if (loader.toLowerCase() === 'neoforge') {
const versionParts = mcVersion.split('.').map(Number);
const major = versionParts[0];
const minor = versionParts[1] || 0;
const patch = versionParts[2] || 0;
if (major < 1 || (major === 1 && minor < 20) || (major === 1 && minor === 20 && patch < 1)) {
throw new Error('NeoForge only supports Minecraft 1.20.1 and above');
}
}
}
async function configureProjectByLoader(loader, modName, mcVersion, loaderVersion, projectPath, modConfig) {
switch (loader.toLowerCase()) {
case 'forge':
await initializeForgeProject(modName, mcVersion, loaderVersion, projectPath, modConfig);
break;
case 'fabric':
await initializeFabricProject(modName, mcVersion, loaderVersion, projectPath, modConfig);
break;
case 'neoforge':
await initializeNeoForgeProject(modName, mcVersion, loaderVersion, projectPath, modConfig);
break;
default:
throw new Error(`Unsupported loader: ${loader}`);
}
}
function displayProjectCompletionSummary(modName, loader, mcVersion, loaderVersion) {
console.log(chalk.blue.bold('='.repeat(75)));
console.log(chalk.green('Project created successfully!'));
console.log(chalk.blue.bold('='.repeat(75)));
console.log(chalk.blue('\nProject Information:'));
console.log(chalk.gray('─'.repeat(40)));
console.log(chalk.white(` Mod Name: ${chalk.cyan(modName)}`));
console.log(chalk.white(` Loader: ${chalk.cyan(loader)} ${chalk.yellow(loaderVersion)}`));
console.log(chalk.white(` Minecraft: ${chalk.cyan(mcVersion)}`));
console.log(chalk.white(` Directory: ${chalk.gray(path.resolve(modName))}`));
console.log(chalk.gray('─'.repeat(40)));
console.log(chalk.blue.bold('='.repeat(75)));
}
function displayProjectInitializationHeader(modName, mcVersion, loader, loaderVersion) {
console.clear();
console.log(chalk.green.bold('███╗ ███╗██████╗ ██╗ ██╗██╗ ██╗███████╗██╗ ██████╗ ███████╗██████╗ '));
console.log(chalk.green.bold('████╗ ████║██╔══██╗██║ ██╔╝██║ ██║██╔════╝██║ ██╔══██╗██╔════╝██╔══██╗'));
console.log(chalk.green.bold('██╔████╔██║██║ ██║█████╔╝ ███████║█████╗ ██║ ██████╔╝█████╗ ██████╔╝'));
console.log(chalk.green.bold('██║╚██╔╝██║██║ ██║██╔═██╗ ██╔══██║██╔══╝ ██║ ██╔═══╝ ██╔══╝ ██╔══██╗'));
console.log(chalk.green.bold('██║ ╚═╝ ██║██████╔╝██║ ██╗██║ ██║███████╗███████╗██║ ███████╗██║ ██║'));
console.log(chalk.green.bold('╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚══════╝╚═╝ ╚═╝'));
console.log(chalk.blue.bold(`Project: ${chalk.cyan(modName)}`));
console.log(chalk.blue.bold(`Loader: ${chalk.cyan(loader)} ${chalk.yellow(loaderVersion)}`));
console.log(chalk.blue.bold(`Version: ${chalk.cyan(mcVersion)}`));
console.log(chalk.blue.bold('='.repeat(75)));
}
module.exports = {
initializeModProject
};