@mcbepack/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/README.md +193 -0
- package/out/commands/build.js +58 -0
- package/out/commands/dev.js +44 -0
- package/out/commands/update.js +98 -0
- package/out/index.js +22 -0
- package/out/utils/archiver.js +84 -0
- package/out/utils/file-sync.js +75 -0
- package/out/utils/paths.js +20 -0
- package/out/utils/webpack.js +77 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# @mcbepack/cli
|
|
2
|
+
|
|
3
|
+
Development and build tooling for MCBEPACK projects
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@mcbepack/cli)
|
|
6
|
+
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
`@mcbepack/cli` provides command-line tools for developing and building Minecraft Bedrock Edition addons. It includes a development server with hot-reload capabilities and multiple build format options.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- **Development Server** - Watch mode with automatic file synchronization
|
|
15
|
+
- **Multiple Build Formats** - Export as `.zip`, `.mcpack`, or `.mcaddon`
|
|
16
|
+
- **Script API Compilation** - Webpack-based bundling for Script API projects
|
|
17
|
+
- **Smart File Sync** - Automatic synchronization to Minecraft development folders
|
|
18
|
+
- **Dependency Updates** - Update Script API packages to latest versions
|
|
19
|
+
- **Environment Configuration** - `.env.local` support for custom paths
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
This package is automatically installed as a peer dependency when creating a project with `create-mcbepack`.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun add -D @mcbepack/cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
### `mcbepack dev`
|
|
32
|
+
|
|
33
|
+
Start the development server with file watching and automatic synchronization.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bun run dev
|
|
37
|
+
# or
|
|
38
|
+
mcbepack dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Features:**
|
|
42
|
+
|
|
43
|
+
- Watches `scripts/` directory for changes
|
|
44
|
+
- Compiles TypeScript/JavaScript with Webpack
|
|
45
|
+
- Syncs compiled files to Minecraft development folder
|
|
46
|
+
- Provides real-time feedback on file changes
|
|
47
|
+
|
|
48
|
+
### `mcbepack build`
|
|
49
|
+
|
|
50
|
+
Build the addon as a .zip, .mcpack, or .mcaddon file.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Build the addon as a .zip archive.
|
|
54
|
+
mcbepack build -o zip
|
|
55
|
+
|
|
56
|
+
# Build the addon as a .mcpack file.
|
|
57
|
+
mcbepack build -o mcpack
|
|
58
|
+
|
|
59
|
+
# Build the addon as a .mcaddon file.
|
|
60
|
+
mcbepack build -o addon
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### `mcbepack update`
|
|
64
|
+
|
|
65
|
+
Update Script API dependencies to the latest release.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Update Script API dependencies to the latest stable release.
|
|
69
|
+
mcbepack update -t stable
|
|
70
|
+
|
|
71
|
+
# Update Script API dependencies to the latest beta release.
|
|
72
|
+
mcbepack update -t beta
|
|
73
|
+
|
|
74
|
+
# Update Script API dependencies to the latest preview release.
|
|
75
|
+
mcbepack update -t preview
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Configuration
|
|
79
|
+
|
|
80
|
+
### Environment Variables
|
|
81
|
+
|
|
82
|
+
Create a `.env.local` file in your project root:
|
|
83
|
+
|
|
84
|
+
```env
|
|
85
|
+
BASE_PATH="C:\Users\YourName\AppData\Roaming\Minecraft Bedrock\Users\Shared\games\com.mojang"
|
|
86
|
+
RESOURCE_PATH="development_resource_packs"
|
|
87
|
+
BEHAVIOR_PATH="development_behavior_packs"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Variables:**
|
|
91
|
+
|
|
92
|
+
- `BASE_PATH` - Path to Minecraft's `com.mojang` directory
|
|
93
|
+
- `RESOURCE_PATH` - Relative path to resource packs folder
|
|
94
|
+
- `BEHAVIOR_PATH` - Relative path to behavior packs folder
|
|
95
|
+
|
|
96
|
+
### Project Structure
|
|
97
|
+
|
|
98
|
+
The CLI expects the following project structure:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
your-project/
|
|
102
|
+
├── scripts/ # Source files (TypeScript/JavaScript)
|
|
103
|
+
│ └── index.ts
|
|
104
|
+
├── behavior/ # Auto-generated behavior pack (if applicable)
|
|
105
|
+
├── resource/ # Auto-generated resource pack (if applicable)
|
|
106
|
+
├── .env.local # Environment configuration
|
|
107
|
+
└── package.json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Development Workflow
|
|
111
|
+
|
|
112
|
+
1. **Start Development Server**
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
bun run dev
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
2. **Edit Source Files**
|
|
119
|
+
- Modify files in `scripts/` directory
|
|
120
|
+
- Changes are automatically detected and compiled
|
|
121
|
+
|
|
122
|
+
3. **Test in Minecraft**
|
|
123
|
+
- Files are synced to Minecraft's development folder
|
|
124
|
+
- Reload the world or restart Minecraft to see changes
|
|
125
|
+
|
|
126
|
+
4. **Build for Distribution**
|
|
127
|
+
```bash
|
|
128
|
+
bun run build:mcaddon
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Technical Details
|
|
132
|
+
|
|
133
|
+
### File Watching
|
|
134
|
+
|
|
135
|
+
The development server uses `chokidar` for efficient file watching:
|
|
136
|
+
|
|
137
|
+
- Monitors `scripts/` directory for changes
|
|
138
|
+
- Triggers recompilation on file add/change/delete
|
|
139
|
+
- Syncs compiled output to Minecraft folders
|
|
140
|
+
|
|
141
|
+
### Webpack Configuration
|
|
142
|
+
|
|
143
|
+
For Script API projects, the CLI uses Webpack with:
|
|
144
|
+
|
|
145
|
+
- TypeScript support via `ts-loader`
|
|
146
|
+
- ESNext target
|
|
147
|
+
- Bundler module resolution
|
|
148
|
+
- Source map generation (development only)
|
|
149
|
+
|
|
150
|
+
### Build Process
|
|
151
|
+
|
|
152
|
+
The build commands:
|
|
153
|
+
|
|
154
|
+
1. Compile source files (if Script API enabled)
|
|
155
|
+
2. Copy pack files to temporary directory
|
|
156
|
+
3. Create archive using `archiver`
|
|
157
|
+
4. Output to project root
|
|
158
|
+
|
|
159
|
+
## Related Packages
|
|
160
|
+
|
|
161
|
+
- [`create-mcbepack`](../create-mcbepack) - Project scaffolding tool
|
|
162
|
+
- [`@mcbepack/api`](../api) - Utility APIs for Script API
|
|
163
|
+
- [`@mcbepack/common`](../common) - Shared utilities
|
|
164
|
+
|
|
165
|
+
## Troubleshooting
|
|
166
|
+
|
|
167
|
+
### Files Not Syncing
|
|
168
|
+
|
|
169
|
+
1. Check `.env.local` paths are correct
|
|
170
|
+
2. Ensure Minecraft development folders exist
|
|
171
|
+
3. Verify file permissions
|
|
172
|
+
|
|
173
|
+
### Compilation Errors
|
|
174
|
+
|
|
175
|
+
1. Check TypeScript configuration in `tsconfig.json`
|
|
176
|
+
2. Ensure all dependencies are installed
|
|
177
|
+
3. Verify source file syntax
|
|
178
|
+
|
|
179
|
+
### Build Failures
|
|
180
|
+
|
|
181
|
+
1. Check for file permission issues
|
|
182
|
+
2. Ensure sufficient disk space
|
|
183
|
+
3. Verify pack manifest files are valid
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
GPL-3.0 - see [LICENSE](./LICENSE) for details
|
|
188
|
+
|
|
189
|
+
## Resources
|
|
190
|
+
|
|
191
|
+
- [GitHub Repository](https://github.com/bugphxne/create-mcbepack)
|
|
192
|
+
- [Documentation](https://docs.mbext.online/mcbepack)
|
|
193
|
+
- [Issue Tracker](https://github.com/bugphxne/create-mcbepack/issues)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import { createCompiler } from "../utils/webpack";
|
|
3
|
+
import { PackArchiver } from "../utils/archiver";
|
|
4
|
+
import { getProjectPaths } from "../utils/paths";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
export const buildCommand = {
|
|
7
|
+
command: "build",
|
|
8
|
+
describe: "Build the project",
|
|
9
|
+
builder: (yargs) => {
|
|
10
|
+
return yargs.option("output", {
|
|
11
|
+
alias: "o",
|
|
12
|
+
type: "string",
|
|
13
|
+
description: "Output format",
|
|
14
|
+
demandOption: true,
|
|
15
|
+
choices: ["mcpack", "mcaddon", "zip"]
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
handler: async (argv) => {
|
|
19
|
+
try {
|
|
20
|
+
const paths = getProjectPaths();
|
|
21
|
+
const { output } = argv;
|
|
22
|
+
console.log(pc.cyan("Building project...\n"));
|
|
23
|
+
if (fs.existsSync(paths.scriptsDir)) {
|
|
24
|
+
const compiler = createCompiler();
|
|
25
|
+
await new Promise((resolve, reject) => {
|
|
26
|
+
compiler.run((err, stats) => {
|
|
27
|
+
if (err) {
|
|
28
|
+
reject(err);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (stats?.hasErrors()) {
|
|
32
|
+
console.error(pc.red("Compilation errors:"));
|
|
33
|
+
console.error(stats.toString({ errors: true }));
|
|
34
|
+
reject(new Error("Compilation failed"));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
console.log(stats?.toString({
|
|
38
|
+
colors: true,
|
|
39
|
+
modules: false,
|
|
40
|
+
children: false,
|
|
41
|
+
chunks: false,
|
|
42
|
+
chunkModules: false,
|
|
43
|
+
}));
|
|
44
|
+
console.log(pc.green("\nWebpack compilation completed\n"));
|
|
45
|
+
resolve();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const archiver = new PackArchiver(paths);
|
|
50
|
+
await archiver.archive(output);
|
|
51
|
+
console.log(pc.green("\nBuild completed successfully!\n"));
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error(pc.red("Build failed:"), error);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import { createCompiler } from "../utils/webpack";
|
|
3
|
+
import { FileSync } from "../utils/file-sync";
|
|
4
|
+
import { getProjectPaths, validateEnv } from "../utils/paths";
|
|
5
|
+
export const devCommand = {
|
|
6
|
+
command: "dev",
|
|
7
|
+
describe: "Run the development server",
|
|
8
|
+
handler: async () => {
|
|
9
|
+
try {
|
|
10
|
+
validateEnv();
|
|
11
|
+
const paths = getProjectPaths();
|
|
12
|
+
console.log(pc.cyan("Starting development server...\n"));
|
|
13
|
+
const compiler = createCompiler();
|
|
14
|
+
compiler.watch({
|
|
15
|
+
aggregateTimeout: 300,
|
|
16
|
+
poll: 1000
|
|
17
|
+
}, (err, stats) => {
|
|
18
|
+
if (stats?.hasWarnings()) {
|
|
19
|
+
console.error(pc.yellow("Compilation warnings:"));
|
|
20
|
+
console.error(stats.toString({ warnings: true }));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (err) {
|
|
24
|
+
console.error(pc.red("Webpack error:"), err);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (stats?.hasErrors()) {
|
|
28
|
+
console.error(pc.red("Compilation errors:"));
|
|
29
|
+
console.error(stats.toString({ errors: true }));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
console.log(pc.green(`Rebuilt at ${new Date().toLocaleTimeString()}`));
|
|
33
|
+
});
|
|
34
|
+
const fileSync = new FileSync(paths);
|
|
35
|
+
fileSync.watchBehaviorPack();
|
|
36
|
+
fileSync.watchResourcePack();
|
|
37
|
+
console.log(pc.dim("Watching for file changes...\n"));
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error(pc.red("Failed to start dev server:"), error);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import { constants, getDependency } from "@mcbepack/common";
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { getProjectPaths } from "../utils/paths";
|
|
6
|
+
export const updateCommand = {
|
|
7
|
+
command: "update",
|
|
8
|
+
describe: "Update the project dependencies",
|
|
9
|
+
builder: (yargs) => {
|
|
10
|
+
return yargs.option("type", {
|
|
11
|
+
alias: "t",
|
|
12
|
+
type: "string",
|
|
13
|
+
description: "Update type",
|
|
14
|
+
choices: ['stable', 'beta', 'preview'],
|
|
15
|
+
default: 'stable'
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
handler: async (argv) => {
|
|
19
|
+
const { type = 'stable' } = argv;
|
|
20
|
+
console.log(pc.cyan(`Updating dependencies to ${pc.bold(type)} version...\n`));
|
|
21
|
+
try {
|
|
22
|
+
const packageJsonPath = join(process.cwd(), "package.json");
|
|
23
|
+
const manifestJsonPath = join(getProjectPaths().behaviorRootPath, "manifest.json");
|
|
24
|
+
if (!existsSync(packageJsonPath)) {
|
|
25
|
+
console.error(pc.red("package.json not found in current directory"));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
if (!existsSync(manifestJsonPath)) {
|
|
29
|
+
console.error(pc.red("manifest.json not found in current directory"));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
33
|
+
const manifestJson = JSON.parse(readFileSync(manifestJsonPath, "utf-8"));
|
|
34
|
+
if (!packageJson.dependencies) {
|
|
35
|
+
console.log(pc.yellow("No dependencies found in package.json"));
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
const minecraftPackages = [
|
|
39
|
+
...constants.packages.modules,
|
|
40
|
+
...constants.packages.plugins,
|
|
41
|
+
];
|
|
42
|
+
let updated = false;
|
|
43
|
+
let updatedCount = 0;
|
|
44
|
+
for (const packageName of minecraftPackages) {
|
|
45
|
+
if (packageJson.dependencies[packageName]) {
|
|
46
|
+
try {
|
|
47
|
+
const dependency = await getDependency(packageName, type);
|
|
48
|
+
const currentVersion = packageJson.dependencies[packageName];
|
|
49
|
+
if (currentVersion !== dependency.fullVersion) {
|
|
50
|
+
packageJson.dependencies[packageName] = dependency.fullVersion;
|
|
51
|
+
console.log(pc.green(` ✓ ${pc.bold(packageName)}`));
|
|
52
|
+
console.log(pc.dim(` ${currentVersion} → ${pc.white(dependency.fullVersion)}`));
|
|
53
|
+
updated = true;
|
|
54
|
+
updatedCount++;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.log(pc.dim(` ${packageName} is already up to date (${currentVersion})`));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.error(pc.red(` Failed to update ${packageName}: ${error instanceof Error ? error.message : String(error)}`));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const manifestDep = manifestJson.dependencies.find((dep) => "module_name" in dep && dep.module_name === packageName);
|
|
65
|
+
if (manifestDep) {
|
|
66
|
+
try {
|
|
67
|
+
const dependency = await getDependency(packageName, type);
|
|
68
|
+
const currentVersion = "version" in manifestDep ? manifestDep.version : undefined;
|
|
69
|
+
if (currentVersion !== dependency.version) {
|
|
70
|
+
manifestJson.dependencies = manifestJson.dependencies.map((dep) => {
|
|
71
|
+
if ("module_name" in dep && dep.module_name === packageName) {
|
|
72
|
+
return { ...dep, version: dependency.version };
|
|
73
|
+
}
|
|
74
|
+
return dep;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(pc.red(` Failed to update manifest for ${packageName}: ${error instanceof Error ? error.message : String(error)}`));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (updated) {
|
|
84
|
+
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
|
|
85
|
+
writeFileSync(manifestJsonPath, JSON.stringify(manifestJson, null, 2) + "\n", "utf-8");
|
|
86
|
+
console.log(pc.green(`\n✓ Updated ${updatedCount} package${updatedCount > 1 ? 's' : ''} successfully!`));
|
|
87
|
+
console.log(pc.dim(`Run ${pc.bold("bun install")} to install the new versions`));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.log(pc.green(`\n✓ All dependencies are up to date!`));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error(pc.red(`\n✗ Error updating dependencies: ${error instanceof Error ? error.message : String(error)}`));
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
package/out/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "@mcbepack/common";
|
|
3
|
+
import yargs from "yargs";
|
|
4
|
+
import { hideBin } from "yargs/helpers";
|
|
5
|
+
import dotenv from "dotenv";
|
|
6
|
+
import { devCommand } from "./commands/dev";
|
|
7
|
+
import { buildCommand } from "./commands/build";
|
|
8
|
+
import { updateCommand } from "./commands/update";
|
|
9
|
+
dotenv.config({
|
|
10
|
+
path: process.cwd() + "/.env.local"
|
|
11
|
+
});
|
|
12
|
+
process.env.NODE_NO_WARNINGS = "1";
|
|
13
|
+
yargs(hideBin(process.argv))
|
|
14
|
+
.command(devCommand)
|
|
15
|
+
.command(buildCommand)
|
|
16
|
+
.command(updateCommand)
|
|
17
|
+
.demandCommand(1, "You need to specify a command")
|
|
18
|
+
.help()
|
|
19
|
+
.alias("h", "help")
|
|
20
|
+
.version()
|
|
21
|
+
.alias("v", "version")
|
|
22
|
+
.parse();
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import archiver from "archiver";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
export class PackArchiver {
|
|
6
|
+
paths;
|
|
7
|
+
constructor(paths) {
|
|
8
|
+
this.paths = paths;
|
|
9
|
+
if (!fs.existsSync(this.paths.binPath)) {
|
|
10
|
+
fs.mkdirSync(this.paths.binPath, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
createArchive(outputPath, callback) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const output = fs.createWriteStream(outputPath);
|
|
16
|
+
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
17
|
+
output.on("close", () => {
|
|
18
|
+
console.log(pc.green(`Created: ${path.basename(outputPath)} (${archive.pointer()} bytes)`));
|
|
19
|
+
resolve();
|
|
20
|
+
});
|
|
21
|
+
archive.on("error", (err) => reject(err));
|
|
22
|
+
archive.pipe(output);
|
|
23
|
+
callback(archive);
|
|
24
|
+
archive.finalize();
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async createMcpack() {
|
|
28
|
+
const promises = [];
|
|
29
|
+
if (fs.existsSync(this.paths.behaviorRootPath)) {
|
|
30
|
+
const outputPath = path.join(this.paths.binPath, `${this.paths.projectName}_behavior.mcpack`);
|
|
31
|
+
promises.push(this.createArchive(outputPath, (archive) => {
|
|
32
|
+
archive.directory(this.paths.behaviorRootPath, this.paths.projectName);
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
if (fs.existsSync(this.paths.resourceRootPath)) {
|
|
36
|
+
const outputPath = path.join(this.paths.binPath, `${this.paths.projectName}_resource.mcpack`);
|
|
37
|
+
promises.push(this.createArchive(outputPath, (archive) => {
|
|
38
|
+
archive.directory(this.paths.resourceRootPath, this.paths.projectName);
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
await Promise.all(promises);
|
|
42
|
+
}
|
|
43
|
+
async createMcaddon() {
|
|
44
|
+
const outputPath = path.join(this.paths.binPath, `${this.paths.projectName}.mcaddon`);
|
|
45
|
+
await this.createArchive(outputPath, (archive) => {
|
|
46
|
+
if (fs.existsSync(this.paths.behaviorRootPath)) {
|
|
47
|
+
archive.directory(this.paths.behaviorRootPath, "behavior_pack");
|
|
48
|
+
}
|
|
49
|
+
if (fs.existsSync(this.paths.resourceRootPath)) {
|
|
50
|
+
archive.directory(this.paths.resourceRootPath, "resource_pack");
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
async createZip() {
|
|
55
|
+
const promises = [];
|
|
56
|
+
if (fs.existsSync(this.paths.behaviorRootPath)) {
|
|
57
|
+
const outputPath = path.join(this.paths.binPath, `${this.paths.projectName}_behavior.zip`);
|
|
58
|
+
promises.push(this.createArchive(outputPath, (archive) => {
|
|
59
|
+
archive.directory(this.paths.behaviorRootPath, this.paths.projectName);
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
if (fs.existsSync(this.paths.resourceRootPath)) {
|
|
63
|
+
const outputPath = path.join(this.paths.binPath, `${this.paths.projectName}_resource.zip`);
|
|
64
|
+
promises.push(this.createArchive(outputPath, (archive) => {
|
|
65
|
+
archive.directory(this.paths.resourceRootPath, this.paths.projectName);
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
await Promise.all(promises);
|
|
69
|
+
}
|
|
70
|
+
async archive(format) {
|
|
71
|
+
console.log(pc.cyan(`\nCreating ${format} archive...`));
|
|
72
|
+
switch (format) {
|
|
73
|
+
case "mcpack":
|
|
74
|
+
await this.createMcpack();
|
|
75
|
+
break;
|
|
76
|
+
case "mcaddon":
|
|
77
|
+
await this.createMcaddon();
|
|
78
|
+
break;
|
|
79
|
+
case "zip":
|
|
80
|
+
await this.createZip();
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import chokidar from "chokidar";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
export class FileSync {
|
|
6
|
+
paths;
|
|
7
|
+
constructor(paths) {
|
|
8
|
+
this.paths = paths;
|
|
9
|
+
}
|
|
10
|
+
syncFile(filePath, action) {
|
|
11
|
+
const destPath = this.getDestPath(filePath);
|
|
12
|
+
if (!destPath)
|
|
13
|
+
return;
|
|
14
|
+
try {
|
|
15
|
+
if (action === "copy") {
|
|
16
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
17
|
+
fs.copyFileSync(filePath, destPath);
|
|
18
|
+
console.log(pc.green(`Synced: ${path.basename(filePath)}`));
|
|
19
|
+
}
|
|
20
|
+
else if (action === "unlink") {
|
|
21
|
+
if (fs.existsSync(destPath)) {
|
|
22
|
+
fs.unlinkSync(destPath);
|
|
23
|
+
console.log(pc.red(`Unlinked: ${path.basename(filePath)}`));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else if (action === "unlinkDir") {
|
|
27
|
+
if (fs.existsSync(destPath)) {
|
|
28
|
+
fs.rmSync(destPath, { recursive: true, force: true });
|
|
29
|
+
console.log(pc.red(`Unlinked Dir: ${path.basename(filePath)}`));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error(pc.red(`Error syncing ${filePath}:`), error);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
setupInitialSync(rootPath, destPath) {
|
|
38
|
+
const targetPath = path.join(destPath, this.paths.projectName);
|
|
39
|
+
if (fs.existsSync(targetPath)) {
|
|
40
|
+
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
41
|
+
}
|
|
42
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
43
|
+
fs.cpSync(rootPath, targetPath, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
getDestPath(filePath) {
|
|
46
|
+
const outputPath = path.relative(this.paths.behaviorRootPath, filePath);
|
|
47
|
+
if (filePath.startsWith(this.paths.behaviorRootPath)) {
|
|
48
|
+
return path.join(this.paths.behaviorPath, path.relative(path.dirname(process.cwd()), outputPath));
|
|
49
|
+
}
|
|
50
|
+
else if (filePath.startsWith(this.paths.resourceRootPath)) {
|
|
51
|
+
return path.join(this.paths.resourcePath, path.relative(path.dirname(process.cwd()), outputPath));
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
watchBehaviorPack() {
|
|
56
|
+
if (!fs.existsSync(this.paths.behaviorRootPath))
|
|
57
|
+
return;
|
|
58
|
+
this.setupInitialSync(this.paths.behaviorRootPath, this.paths.behaviorPath);
|
|
59
|
+
chokidar.watch(this.paths.behaviorRootPath, { ignoreInitial: true })
|
|
60
|
+
.on("add", (filePath) => this.syncFile(filePath, "copy"))
|
|
61
|
+
.on("change", (filePath) => this.syncFile(filePath, "copy"))
|
|
62
|
+
.on("unlink", (filePath) => this.syncFile(filePath, "unlink"))
|
|
63
|
+
.on("unlinkDir", (filePath) => this.syncFile(filePath, "unlinkDir"));
|
|
64
|
+
}
|
|
65
|
+
watchResourcePack() {
|
|
66
|
+
if (!fs.existsSync(this.paths.resourceRootPath))
|
|
67
|
+
return;
|
|
68
|
+
this.setupInitialSync(this.paths.resourceRootPath, this.paths.resourcePath);
|
|
69
|
+
chokidar.watch(this.paths.resourceRootPath, { ignoreInitial: true })
|
|
70
|
+
.on("add", (filePath) => this.syncFile(filePath, "copy"))
|
|
71
|
+
.on("change", (filePath) => this.syncFile(filePath, "copy"))
|
|
72
|
+
.on("unlink", (filePath) => this.syncFile(filePath, "unlink"))
|
|
73
|
+
.on("unlinkDir", (filePath) => this.syncFile(filePath, "unlinkDir"));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
export function validateEnv() {
|
|
3
|
+
const required = ['BASE_PATH', 'BEHAVIOR_PATH', 'RESOURCE_PATH'];
|
|
4
|
+
const missing = required.filter(key => !process.env[key]);
|
|
5
|
+
if (missing.length > 0) {
|
|
6
|
+
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function getProjectPaths() {
|
|
10
|
+
const projectName = path.basename(process.cwd());
|
|
11
|
+
return {
|
|
12
|
+
scriptsDir: path.join(process.cwd(), "scripts"),
|
|
13
|
+
behaviorPath: path.join(process.env.BASE_PATH, process.env.BEHAVIOR_PATH),
|
|
14
|
+
resourcePath: path.join(process.env.BASE_PATH, process.env.RESOURCE_PATH),
|
|
15
|
+
behaviorRootPath: path.join(process.cwd(), "src", "behavior_pack"),
|
|
16
|
+
resourceRootPath: path.join(process.cwd(), "src", "resource_pack"),
|
|
17
|
+
binPath: path.join(process.cwd(), "bin"),
|
|
18
|
+
projectName
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { webpack } from "webpack";
|
|
3
|
+
import { constants } from "@mcbepack/common";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
export function createWebpackConfig() {
|
|
6
|
+
if (fs.existsSync(path.join(process.cwd(), 'scripts', 'index.ts'))) {
|
|
7
|
+
return {
|
|
8
|
+
mode: 'development',
|
|
9
|
+
entry: './scripts/index',
|
|
10
|
+
target: 'node',
|
|
11
|
+
infrastructureLogging: {
|
|
12
|
+
level: 'warn'
|
|
13
|
+
},
|
|
14
|
+
output: {
|
|
15
|
+
path: path.resolve(process.cwd(), 'src', 'behavior_pack', 'scripts'),
|
|
16
|
+
filename: 'index.js',
|
|
17
|
+
module: true,
|
|
18
|
+
library: {
|
|
19
|
+
type: 'module'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
resolve: {
|
|
23
|
+
extensions: ['.js', '.ts'],
|
|
24
|
+
},
|
|
25
|
+
resolveLoader: {
|
|
26
|
+
modules: [
|
|
27
|
+
path.join(__dirname, '..', '..', 'node_modules'),
|
|
28
|
+
'node_modules'
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
externals: constants.packages.modules.map(module => ({
|
|
32
|
+
[module]: module
|
|
33
|
+
})),
|
|
34
|
+
module: {
|
|
35
|
+
rules: [
|
|
36
|
+
{
|
|
37
|
+
test: /\.ts$/,
|
|
38
|
+
use: 'ts-loader',
|
|
39
|
+
exclude: /node_modules/
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
experiments: {
|
|
44
|
+
outputModule: true
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
else if (fs.existsSync(path.join(process.cwd(), 'scripts', 'index.js'))) {
|
|
49
|
+
return {
|
|
50
|
+
mode: 'development',
|
|
51
|
+
entry: './scripts/index',
|
|
52
|
+
target: 'node',
|
|
53
|
+
infrastructureLogging: {
|
|
54
|
+
level: 'warn'
|
|
55
|
+
},
|
|
56
|
+
output: {
|
|
57
|
+
path: path.resolve(process.cwd(), 'src', 'behavior_pack', 'scripts'),
|
|
58
|
+
filename: 'index.js'
|
|
59
|
+
},
|
|
60
|
+
externals: constants.packages.modules.map(module => ({
|
|
61
|
+
[module]: module
|
|
62
|
+
})),
|
|
63
|
+
resolve: {
|
|
64
|
+
extensions: ['.js'],
|
|
65
|
+
},
|
|
66
|
+
experiments: {
|
|
67
|
+
outputModule: true
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw new Error('This project does not use script api.');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function createCompiler() {
|
|
76
|
+
return webpack(createWebpackConfig());
|
|
77
|
+
}
|