sandstone-cli 0.6.0 → 0.6.1

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/README.md CHANGED
@@ -19,7 +19,7 @@ $ npm install -g sandstone-cli
19
19
  $ sand COMMAND
20
20
  running command...
21
21
  $ sand (-v|--version|version)
22
- sandstone-cli/0.6.0 linux-x64 node-v16.19.0
22
+ sandstone-cli/0.6.1 linux-x64 node-v16.19.0
23
23
  $ sand --help [COMMAND]
24
24
  USAGE
25
25
  $ sand COMMAND
@@ -36,7 +36,7 @@ USAGE
36
36
 
37
37
  ## `sand build PATH CONFIG-PATH`
38
38
 
39
- Build the datapack. ⛏
39
+ Build the packs. ⛏
40
40
 
41
41
  ```
42
42
  USAGE
@@ -47,7 +47,7 @@ ARGUMENTS
47
47
  CONFIG-PATH [default: .] Path of the sandstone.config.ts folder.
48
48
 
49
49
  OPTIONS
50
- -d, --dry Do not save the datapack. Mostly useful with `verbose`.
50
+ -d, --dry Do not save the pack. Mostly useful with `verbose`.
51
51
  -h, --help show CLI help
52
52
  -p, --production Runs Sandstone in production mode. This sets process.env.SANDSTONE_ENV to "production".
53
53
  -v, --verbose Log all resulting resources: functions, advancements...
@@ -55,23 +55,23 @@ OPTIONS
55
55
  --autoReload=port Automatically reload your data pack in-game. Requires to open the world to LAN with
56
56
  cheats enabled, and to specify the port.
57
57
 
58
+ --clientPath=clientPath Path of the client folder. Override the value specified in the configuration file.
59
+
58
60
  --description=description Description of the data pack. Override the value specified in the configuration file.
59
61
 
60
62
  --formatVersion=formatVersion Pack format version. Override the value specified in the configuration file.
61
63
 
62
64
  --fullTrace Show the full stack trace on errors.
63
65
 
64
- --minecraftPath=minecraftPath Path of the .minecraft folder. Override the value specified in the configuration file.
65
-
66
66
  --name=name Name of the data pack. Override the value specified in the configuration file.
67
67
 
68
68
  --namespace=namespace The default namespace. Override the value specified in the configuration file.
69
69
 
70
- --path=path The path to save the data pack at. Override the value specified in the configuration
70
+ --root Save the data pack & resource pack in the .minecraft/datapacks &
71
+ .minecraft/resource_packs folders. Override the value specified in the configuration
71
72
  file.
72
73
 
73
- --root Save the data pack in the `.minecraft/datapacks` folder. Override the value specified
74
- in the configuration file.
74
+ --serverPath=serverPath Path of the server folder. Override the value specified in the configuration file.
75
75
 
76
76
  --strictErrors Stop data pack compilation on type errors.
77
77
 
@@ -84,7 +84,7 @@ EXAMPLES
84
84
  $ sand build --verbose --dry
85
85
  ```
86
86
 
87
- _See code: [src/commands/build.ts](https://github.com/TheMrZZ/sandstone-cli/blob/v0.6.0/src/commands/build.ts)_
87
+ _See code: [src/commands/build.ts](https://github.com/TheMrZZ/sandstone-cli/blob/v0.6.1/src/commands/build.ts)_
88
88
 
89
89
  ## `sand create PROJECT-NAME`
90
90
 
@@ -98,26 +98,27 @@ ARGUMENTS
98
98
  PROJECT-NAME Name of the project folder. This is not the name of the data pack.
99
99
 
100
100
  OPTIONS
101
- -d, --datapack-name=datapack-name The name of the data pack.
102
- -h, --help show CLI help
103
- -n, --namespace=namespace The default namespace that will be used.
104
- -p, --custom-path=custom-path The path to save the data pack at. Not compatible with --save-root and --world.
101
+ -c, --client-path=client-path The client path to write packs at.
102
+ -d, --pack-name=pack-name The name of the data pack.
103
+ -h, --help show CLI help
104
+ -n, --namespace=namespace The default namespace that will be used.
105
105
 
106
- -r, --save-root Save the data pack in the .minecraft/datapacks folder. Not compatible with --world
107
- and --custom-path.
106
+ -r, --save-root Save the data pack & resource pack in the .minecraft/datapacks &
107
+ .minecraft/resource_packs folders. Not compatible with --world.
108
108
 
109
- -w, --world=world The world to save the data pack in. Not compatible with --save-root and
110
- --custom-path.
109
+ -s, --server-path=server-path The server path to write the server-side packs at. Not compatible with --world.
111
110
 
112
- --npm Use npm.
111
+ -w, --world=world The world to save the packs in. Not compatible with --save-root or --server
113
112
 
114
- --yarn Use yarn instead of npm.
113
+ --npm Use npm.
114
+
115
+ --yarn Use yarn instead of npm.
115
116
 
116
117
  EXAMPLE
117
- $ sand create my-datapack
118
+ $ sand create my-pack
118
119
  ```
119
120
 
120
- _See code: [src/commands/create.ts](https://github.com/TheMrZZ/sandstone-cli/blob/v0.6.0/src/commands/create.ts)_
121
+ _See code: [src/commands/create.ts](https://github.com/TheMrZZ/sandstone-cli/blob/v0.6.1/src/commands/create.ts)_
121
122
 
122
123
  ## `sand help [COMMAND]`
123
124
 
@@ -159,11 +160,11 @@ EXAMPLES
159
160
  $ sand update --cli --sandstone --skip
160
161
  ```
161
162
 
162
- _See code: [src/commands/update.ts](https://github.com/TheMrZZ/sandstone-cli/blob/v0.6.0/src/commands/update.ts)_
163
+ _See code: [src/commands/update.ts](https://github.com/TheMrZZ/sandstone-cli/blob/v0.6.1/src/commands/update.ts)_
163
164
 
164
165
  ## `sand watch PATH CONFIG-PATH`
165
166
 
166
- Build the datapack, and rebuild it on file change. ⛏
167
+ Build the packs, and rebuild them on file change. ⛏
167
168
 
168
169
  ```
169
170
  USAGE
@@ -174,7 +175,7 @@ ARGUMENTS
174
175
  CONFIG-PATH [default: .] Path of the sandstone.config.ts folder.
175
176
 
176
177
  OPTIONS
177
- -d, --dry Do not save the datapack. Mostly useful with `verbose`.
178
+ -d, --dry Do not save the pack. Mostly useful with `verbose`.
178
179
  -h, --help show CLI help
179
180
  -p, --production Runs Sandstone in production mode. This sets process.env.SANDSTONE_ENV to "production".
180
181
  -v, --verbose Log all resulting resources: functions, advancements...
@@ -182,23 +183,23 @@ OPTIONS
182
183
  --autoReload=port Automatically reload your data pack in-game. Requires to open the world to LAN with
183
184
  cheats enabled, and to specify the port.
184
185
 
186
+ --clientPath=clientPath Path of the client folder. Override the value specified in the configuration file.
187
+
185
188
  --description=description Description of the data pack. Override the value specified in the configuration file.
186
189
 
187
190
  --formatVersion=formatVersion Pack format version. Override the value specified in the configuration file.
188
191
 
189
192
  --fullTrace Show the full stack trace on errors.
190
193
 
191
- --minecraftPath=minecraftPath Path of the .minecraft folder. Override the value specified in the configuration file.
192
-
193
194
  --name=name Name of the data pack. Override the value specified in the configuration file.
194
195
 
195
196
  --namespace=namespace The default namespace. Override the value specified in the configuration file.
196
197
 
197
- --path=path The path to save the data pack at. Override the value specified in the configuration
198
+ --root Save the data pack & resource pack in the .minecraft/datapacks &
199
+ .minecraft/resource_packs folders. Override the value specified in the configuration
198
200
  file.
199
201
 
200
- --root Save the data pack in the `.minecraft/datapacks` folder. Override the value specified
201
- in the configuration file.
202
+ --serverPath=serverPath Path of the server folder. Override the value specified in the configuration file.
202
203
 
203
204
  --strictErrors Stop data pack compilation on type errors.
204
205
 
@@ -211,5 +212,5 @@ EXAMPLES
211
212
  $ sand watch --verbose --dry
212
213
  ```
213
214
 
214
- _See code: [src/commands/watch.ts](https://github.com/TheMrZZ/sandstone-cli/blob/v0.6.0/src/commands/watch.ts)_
215
+ _See code: [src/commands/watch.ts](https://github.com/TheMrZZ/sandstone-cli/blob/v0.6.1/src/commands/watch.ts)_
215
216
  <!-- commandsstop -->
@@ -2,8 +2,9 @@ import { ProjectFolders } from '../utils';
2
2
  export declare type BuildOptions = {
3
3
  world?: string;
4
4
  root?: boolean;
5
- path?: string;
6
- minecraftPath?: string;
5
+ clientPath?: string;
6
+ serverPath?: string;
7
+ ssh?: string;
7
8
  namespace?: string;
8
9
  name?: string;
9
10
  description?: string;
@@ -22,4 +23,4 @@ export declare type BuildOptions = {
22
23
  *
23
24
  * @param changedFiles The files that changed since the last build.
24
25
  */
25
- export declare function buildProject(options: BuildOptions, folders: ProjectFolders, changedFiles?: string[]): Promise<void>;
26
+ export declare function buildProject(options: BuildOptions, folders: ProjectFolders, resourceTypes: string[], changedFiles?: string[]): Promise<void>;
@@ -1,10 +1,30 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
2
21
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
23
  };
5
24
  Object.defineProperty(exports, "__esModule", { value: true });
6
25
  exports.buildProject = void 0;
7
26
  const path_1 = __importDefault(require("path"));
27
+ const os = __importStar(require("os"));
8
28
  const crypto_1 = __importDefault(require("crypto"));
9
29
  const util_1 = require("util");
10
30
  const fs_extra_1 = __importDefault(require("fs-extra"));
@@ -13,6 +33,7 @@ const klaw_1 = __importDefault(require("klaw"));
13
33
  const madge_1 = __importDefault(require("madge"));
14
34
  const graph_1 = require("./graph");
15
35
  const chalk_1 = __importDefault(require("chalk"));
36
+ const adm_zip_1 = __importDefault(require("adm-zip"));
16
37
  const pe = new pretty_error_1.default();
17
38
  // Return the hash of a string
18
39
  function hash(stringToHash) {
@@ -33,36 +54,9 @@ async function mkDir(dirPath) {
33
54
  // Directory already exists
34
55
  }
35
56
  }
36
- const cache = {};
57
+ let cache = {};
37
58
  const dependenciesCache = new graph_1.DependencyGraph({});
38
59
  const fileResources = new Map();
39
- /**
40
- * Recursively removes empty directories from the given directory.
41
- *
42
- * If the directory itself is empty, it is also removed.
43
- *
44
- * Code taken from: https://gist.github.com/jakub-g/5903dc7e4028133704a4
45
- *
46
- * @param {string} directory Path to the directory to clean up
47
- */
48
- async function removeEmptyDirectories(directory) {
49
- // lstat does not follow symlinks (in contrast to stat)
50
- const fileStats = await fs_extra_1.default.lstat(directory);
51
- if (!fileStats.isDirectory()) {
52
- return;
53
- }
54
- let fileNames = await fs_extra_1.default.readdir(directory);
55
- if (fileNames.length > 0) {
56
- const recursiveRemovalPromises = fileNames.map((fileName) => removeEmptyDirectories(path_1.default.join(directory, fileName)));
57
- await Promise.all(recursiveRemovalPromises);
58
- // re-evaluate fileNames; after deleting subdirectory
59
- // we may have parent directory empty now
60
- fileNames = await fs_extra_1.default.readdir(directory);
61
- }
62
- if (fileNames.length === 0) {
63
- await fs_extra_1.default.rmdir(directory);
64
- }
65
- }
66
60
  function getNewModules(dependenciesGraph, rawFiles, projectFolder) {
67
61
  const rawFilesPath = rawFiles.map(({ path }) => path);
68
62
  // Get only the new modules
@@ -87,34 +81,103 @@ function diffMap(map1, map2) {
87
81
  function diffResources(tree1, tree2) {
88
82
  return tree1.diff(tree2);
89
83
  }
84
+ /**
85
+ *
86
+ * @param worldName The name of the world
87
+ * @param minecraftPath The optional location of the .minecraft folder.
88
+ * If left unspecified, the .minecraft will be found automatically.
89
+ */
90
+ async function getClientWorldPath(worldName, minecraftPath = undefined) {
91
+ let mcPath;
92
+ if (minecraftPath) {
93
+ mcPath = minecraftPath;
94
+ }
95
+ else {
96
+ mcPath = await getClientPath();
97
+ }
98
+ const savesPath = path_1.default.join(mcPath, 'saves');
99
+ const worldPath = path_1.default.join(savesPath, worldName);
100
+ if (!fs_extra_1.default.existsSync(worldPath)) {
101
+ const existingWorlds = (await fs_extra_1.default.readdir(savesPath, { withFileTypes: true })).filter((f) => f.isDirectory).map((f) => f.name);
102
+ throw new Error(`Unable to locate the "${worldPath}" folder. Word ${worldName} does not exists. List of existing worlds: ${JSON.stringify(existingWorlds, null, 2)}`);
103
+ }
104
+ return worldPath;
105
+ }
106
+ /**
107
+ * Get the .minecraft path
108
+ */
109
+ async function getClientPath() {
110
+ function getMCPath() {
111
+ switch (os.platform()) {
112
+ case 'win32':
113
+ return path_1.default.join(os.homedir(), 'AppData/Roaming/.minecraft');
114
+ case 'darwin':
115
+ return path_1.default.join(os.homedir(), 'Library/Application Support/minecraft');
116
+ case 'linux':
117
+ default:
118
+ return path_1.default.join(os.homedir(), '.minecraft');
119
+ }
120
+ }
121
+ const mcPath = getMCPath();
122
+ if (!await fs_extra_1.default.stat(mcPath)) {
123
+ throw new Error('Unable to locate the .minecraft folder. Please specify it manually.');
124
+ }
125
+ return mcPath;
126
+ }
90
127
  /**
91
128
  * Build the project, but might throw errors.
92
129
  *
93
- * @param options The options to build the project with.
130
+ * @param cliOptions The options to build the project with.
94
131
  *
95
132
  * @param projectFolder The folder of the project. It needs a sandstone.config.ts, and it or one of its parent needs a package.json.
96
133
  */
97
- async function _buildProject(options, { absProjectFolder, rootFolder, sandstoneConfigFolder }, changedFiles) {
98
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
134
+ async function _buildProject(cliOptions, { absProjectFolder, rootFolder, sandstoneConfigFolder }, resourceTypes, changedFiles) {
135
+ var _a, _b, _c, _d, _e;
99
136
  const sandstoneLocation = path_1.default.join(rootFolder, 'node_modules/sandstone/');
100
137
  // First, read sandstone.config.ts to get all properties
101
138
  const sandstoneConfig = require(path_1.default.join(sandstoneConfigFolder, 'sandstone.config.ts')).default;
102
139
  const { saveOptions, scripts } = sandstoneConfig;
140
+ const outputFolder = path_1.default.join(rootFolder, '.sandstone', 'output');
103
141
  /// OPTIONS ///
104
- // Check if the player overidded the save options
105
- const overrideSaveOptions = options.world || options.root || options.path;
106
- const world = overrideSaveOptions ? options.world : saveOptions.world;
107
- const root = overrideSaveOptions ? options.root : saveOptions.root;
108
- const customPath = overrideSaveOptions ? options.path : saveOptions.path;
109
- const minecraftPath = (_a = options.minecraftPath) !== null && _a !== void 0 ? _a : sandstoneConfig.minecraftPath;
110
- const dataPackName = (_b = options.name) !== null && _b !== void 0 ? _b : sandstoneConfig.name;
111
- if ([world, root, customPath].filter(x => x !== undefined).length > 1) {
112
- throw new Error(`Expected only 'world', 'root' or 'path'. Got at least two of them: world=${world}, root=${root}, path=${customPath}`);
142
+ const clientPath = !cliOptions.production ? (cliOptions.clientPath || saveOptions.clientPath || await getClientPath()) : undefined;
143
+ const server = !cliOptions.production && (cliOptions.serverPath || saveOptions.serverPath || cliOptions.ssh || saveOptions.ssh) ? await (async () => {
144
+ if (cliOptions.ssh || saveOptions.ssh) {
145
+ const sshOptions = JSON.stringify(await fs_extra_1.default.readFile(cliOptions.ssh || saveOptions.ssh, 'utf8'));
146
+ // TODO: implement SFTP
147
+ return {
148
+ readFile: async (relativePath, encoding = 'utf8') => { },
149
+ writeFile: async (relativePath, contents) => { },
150
+ remove: async (relativePath) => { },
151
+ };
152
+ }
153
+ const serverPath = cliOptions.serverPath || saveOptions.serverPath;
154
+ return {
155
+ readFile: async (relativePath, encoding = 'utf8') => await fs_extra_1.default.readFile(path_1.default.join(serverPath, relativePath), encoding),
156
+ writeFile: async (relativePath, contents) => {
157
+ if (contents === undefined) {
158
+ await fs_extra_1.default.unlink(path_1.default.join(serverPath, relativePath));
159
+ }
160
+ else {
161
+ await fs_extra_1.default.writeFile(path_1.default.join(serverPath, relativePath), contents);
162
+ }
163
+ },
164
+ remove: async (relativePath) => await fs_extra_1.default.remove(path_1.default.join(serverPath, relativePath))
165
+ };
166
+ })() : undefined;
167
+ let worldName = cliOptions.world || saveOptions.world;
168
+ // Make sure the world exists
169
+ if (worldName && !cliOptions.production) {
170
+ await getClientWorldPath(worldName, clientPath);
171
+ }
172
+ const root = cliOptions.root !== undefined ? cliOptions.root : saveOptions.root;
173
+ const packName = (_a = cliOptions.name) !== null && _a !== void 0 ? _a : sandstoneConfig.name;
174
+ if (worldName && root) {
175
+ throw new Error(`Expected only 'world' or 'root'. Got both.`);
113
176
  }
114
177
  // Important /!\: The below if statements, which set environment variables, must run before importing any Sandstone file.
115
178
  // Set the pack ID environment variable
116
179
  // Set production/development mode
117
- if (options.production) {
180
+ if (cliOptions.production) {
118
181
  process.env.SANDSTONE_ENV = 'production';
119
182
  }
120
183
  else {
@@ -124,37 +187,33 @@ async function _buildProject(options, { absProjectFolder, rootFolder, sandstoneC
124
187
  process.env.PACK_UID = sandstoneConfig.packUid;
125
188
  }
126
189
  // Set the namespace
127
- const namespace = sandstoneConfig.namespace || options.namespace;
190
+ const namespace = cliOptions.namespace || sandstoneConfig.namespace;
128
191
  if (namespace) {
129
192
  process.env.NAMESPACE = namespace;
130
193
  }
131
- // Set conflict strategies
132
- function setStrategy(strategyName, value) {
133
- if (value) {
134
- process.env[`${strategyName.toUpperCase()}_CONFLICT_STRATEGY`] = value;
194
+ const { onConflict } = sandstoneConfig;
195
+ if (onConflict) {
196
+ if (onConflict.default) {
197
+ process.env[`GENERAL_CONFLICT_STRATEGY`] = onConflict.default;
198
+ }
199
+ for (const resource of resourceTypes) {
200
+ if (onConflict[resource]) {
201
+ process.env[`${resource.toUpperCase()}_CONFLICT_STRATEGY`] = onConflict[resource];
202
+ }
135
203
  }
136
204
  }
137
- const { onConflict } = sandstoneConfig;
138
- setStrategy('general', onConflict === null || onConflict === void 0 ? void 0 : onConflict.default);
139
- setStrategy('advancement', onConflict === null || onConflict === void 0 ? void 0 : onConflict.advancement);
140
- setStrategy('loot_table', onConflict === null || onConflict === void 0 ? void 0 : onConflict.lootTable);
141
- setStrategy('mcfunction', onConflict === null || onConflict === void 0 ? void 0 : onConflict.mcFunction);
142
- setStrategy('predicate', onConflict === null || onConflict === void 0 ? void 0 : onConflict.predicate);
143
- setStrategy('recipe', onConflict === null || onConflict === void 0 ? void 0 : onConflict.recipe);
144
- setStrategy('tag', onConflict === null || onConflict === void 0 ? void 0 : onConflict.tag);
205
+ // JSON indentation
206
+ process.env.INDENTATION = saveOptions.indentation;
207
+ // Pack mcmeta
208
+ process.env.PACK_OPTIONS = JSON.stringify(sandstoneConfig.packs);
145
209
  // Configure error display
146
- if (!options.fullTrace) {
210
+ if (!cliOptions.fullTrace) {
147
211
  pe.skipNodeFiles();
148
212
  }
149
213
  /// IMPORTING USER CODE ///
150
214
  // The configuration is ready.
151
215
  // Now, let's run the beforeAll script
152
- const { getDestinationPath } = require(path_1.default.join(sandstoneLocation, 'datapack', 'saveDatapack'));
153
- const destinationPath = getDestinationPath(dataPackName, { world, asRootDatapack: root, customPath, minecraftPath });
154
- await ((_c = scripts === null || scripts === void 0 ? void 0 : scripts.beforeAll) === null || _c === void 0 ? void 0 : _c.call(scripts, {
155
- dataPackName,
156
- destination: destinationPath,
157
- }));
216
+ await ((_b = scripts === null || scripts === void 0 ? void 0 : scripts.beforeAll) === null || _b === void 0 ? void 0 : _b.call(scripts));
158
217
  // Finally, let's import all .ts & .js files under ./src.
159
218
  let error = false;
160
219
  // Get the list of all files
@@ -188,28 +247,17 @@ async function _buildProject(options, { absProjectFolder, rootFolder, sandstoneC
188
247
  dependenciesCache.merge(dependenciesGraph);
189
248
  // Transform resolved dependents into a flat list of files, and sort them by their number of dependencies
190
249
  const newModules = getNewModules(dependenciesCache, changedFilesPaths !== null && changedFilesPaths !== void 0 ? changedFilesPaths : rawFiles, absProjectFolder);
191
- const { savePack } = require(sandstoneLocation);
192
- const { dataPack } = require(sandstoneLocation + '/init');
250
+ const { sandstonePack } = require(sandstoneLocation);
193
251
  // If files changed, we need to clean the cache & delete the related resources
194
252
  if (changedFiles) {
195
253
  for (const node of newModules) {
196
- // For eached changed file, we need to reset the require cache
254
+ // For each changed file, we need to reset the require cache
197
255
  delete require.cache[path_1.default.join(absProjectFolder, node.name)];
198
256
  // Then we need to delete all resources the file created
199
257
  const oldResources = fileResources.get(node.name);
200
258
  if (oldResources) {
201
- const { resources, customResources, objectives, rootFunctions } = oldResources;
202
- for (const resource of resources) {
203
- dataPack.resources.deleteResource(resource.path, resource.resourceType);
204
- }
205
- for (const resource of customResources) {
206
- dataPack.customResources.delete(resource);
207
- }
208
- for (const objective of objectives.keys()) {
209
- dataPack.objectives.delete(objective);
210
- }
211
- for (const rootFunction of rootFunctions) {
212
- dataPack.rootFunctions.delete(rootFunction);
259
+ for (const resource of oldResources.resources) {
260
+ sandstonePack.core.deleteResource(resource.path, resource.resourceType);
213
261
  }
214
262
  }
215
263
  }
@@ -218,10 +266,8 @@ async function _buildProject(options, { absProjectFolder, rootFolder, sandstoneC
218
266
  for (const node of newModules) {
219
267
  const modulePath = path_1.default.join(absProjectFolder, node.name);
220
268
  const currentResources = {
221
- resources: dataPack.resources.clone(),
222
- objectives: new Map([...dataPack.objectives.entries()]),
223
- rootFunctions: new Set([...dataPack.rootFunctions]),
224
- customResources: new Set([...dataPack.customResources]),
269
+ resources: new Set([...sandstonePack.core.resourceNodes]),
270
+ objectives: new Set([...sandstonePack.objectives.entries()])
225
271
  };
226
272
  // We have a module, let's require it!
227
273
  const filePath = path_1.default.resolve(modulePath);
@@ -230,10 +276,6 @@ async function _buildProject(options, { absProjectFolder, rootFolder, sandstoneC
230
276
  if (await fs_extra_1.default.pathExists(filePath)) {
231
277
  require(filePath);
232
278
  }
233
- // Generate the mcfunctions
234
- for (const mcfunction of dataPack.rootFunctions) {
235
- await mcfunction.generate();
236
- }
237
279
  }
238
280
  catch (e) {
239
281
  logError(e, node.name);
@@ -242,10 +284,8 @@ async function _buildProject(options, { absProjectFolder, rootFolder, sandstoneC
242
284
  // Now, find the resources that were added by this file & store them.
243
285
  // This will be used if those files are changed later.
244
286
  const newResources = {
245
- resources: diffResources(dataPack.resources, currentResources.resources),
246
- customResources: diffSet(dataPack.customResources, currentResources.customResources),
247
- rootFunctions: diffSet(dataPack.rootFunctions, currentResources.rootFunctions),
248
- objectives: diffMap(dataPack.objectives, currentResources.objectives),
287
+ resources: diffResources(sandstonePack.core.resourceNodes, currentResources.resources),
288
+ objectives: diffSet(sandstonePack.objectives, currentResources.objectives),
249
289
  };
250
290
  fileResources.set(node.name, newResources);
251
291
  }
@@ -255,72 +295,141 @@ async function _buildProject(options, { absProjectFolder, rootFolder, sandstoneC
255
295
  /// SAVING RESULTS ///
256
296
  // Setup the cache if it doesn't exist.
257
297
  // This cache is here to avoid writing files on disk when they did not change.
258
- const newCache = {
259
- files: {}
260
- };
261
- if (cache[absProjectFolder] === undefined) {
262
- cache[absProjectFolder] = {
263
- files: {},
264
- };
298
+ const newCache = {};
299
+ if (cache === undefined) {
300
+ cache = {};
265
301
  }
266
302
  // Save the pack
267
- // Run the beforeSave script
268
- await ((_d = scripts === null || scripts === void 0 ? void 0 : scripts.beforeSave) === null || _d === void 0 ? void 0 : _d.call(scripts, {
269
- dataPackName,
270
- destination: destinationPath,
271
- }));
272
- await savePack(dataPackName, {
273
- // Save location
274
- world: world,
275
- asRootDatapack: root,
276
- customPath: customPath,
277
- minecraftPath: minecraftPath,
278
- indentation: saveOptions.indentation,
279
- // Data pack mcmeta
280
- description: (_e = options.description) !== null && _e !== void 0 ? _e : sandstoneConfig.description,
281
- formatVersion: (_f = options.formatVersion) !== null && _f !== void 0 ? _f : sandstoneConfig.formatVersion,
303
+ // Run the beforeSave script (TODO: This is where sandstone-server will remove restart env vars)
304
+ await ((_c = scripts === null || scripts === void 0 ? void 0 : scripts.beforeSave) === null || _c === void 0 ? void 0 : _c.call(scripts));
305
+ const packTypes = await sandstonePack.save({
282
306
  // Additional parameters
283
- dryRun: options.dry,
284
- verbose: options.verbose,
285
- customFileHandler: (_g = saveOptions.customFileHandler) !== null && _g !== void 0 ? _g : (async ({ relativePath, content }) => {
286
- var _a;
287
- const realPath = path_1.default.join(destinationPath, relativePath);
288
- // We hash the real path alongside the content.
289
- // Therefore, if the real path change (for example, the user changed the resulting directory), the file will be recreated.
290
- const hashValue = hash(content + realPath);
291
- // Add to new cache. We use the relative path as key to make the cache lighter.
292
- newCache.files[relativePath] = hashValue;
293
- newCache.resultFolder = destinationPath;
294
- if (((_a = cache[absProjectFolder].files) === null || _a === void 0 ? void 0 : _a[realPath]) === hashValue) {
307
+ dryRun: cliOptions.dry,
308
+ verbose: cliOptions.verbose,
309
+ fileHandler: (_d = saveOptions.customFileHandler) !== null && _d !== void 0 ? _d : (async ({ relativePath, content, contentSummary }) => {
310
+ // We hash the relative path alongside the content to ensure unique hash.
311
+ const hashValue = hash(contentSummary + relativePath);
312
+ // Add to new cache.
313
+ newCache[relativePath] = hashValue;
314
+ if (cache[relativePath] === hashValue) {
295
315
  // Already in cache - skip
296
316
  return;
297
317
  }
298
318
  // Not in cache: write to disk
319
+ const realPath = path_1.default.join(rootFolder, relativePath);
299
320
  await mkDir(path_1.default.dirname(realPath));
300
321
  return await fs_extra_1.default.writeFile(realPath, content);
301
322
  })
302
323
  });
303
- // Delete old files that aren't cached anymore
304
- const oldFilesNames = new Set(Object.keys(cache[absProjectFolder].files));
305
- Object.keys(newCache.files).forEach(name => oldFilesNames.delete(name));
306
- const previousResultFolder = (_h = cache === null || cache === void 0 ? void 0 : cache[absProjectFolder]) === null || _h === void 0 ? void 0 : _h.resultFolder;
307
- await Promise.allSettled([...oldFilesNames.values()].map(name => (0, util_1.promisify)(fs_extra_1.default.rm)(path_1.default.join(previousResultFolder !== null && previousResultFolder !== void 0 ? previousResultFolder : '', name))));
308
- // Delete all empty folders of previous directory
309
- if (previousResultFolder !== undefined) {
310
- try {
311
- await removeEmptyDirectories(previousResultFolder);
324
+ async function archiveOutput(packType, outputPath) {
325
+ const archive = new adm_zip_1.default();
326
+ await archive.addLocalFolderPromise(outputPath, {});
327
+ await archive.writeZipPromise(`${outputPath}.zip`, { overwrite: true });
328
+ }
329
+ // TODO: implement linking to make the cache more useful when not archiving.
330
+ if (!cliOptions.production) {
331
+ for (const packType of packTypes) {
332
+ const outputPath = path_1.default.join(rootFolder, '.sandstone/output/archives', `${packName}_${packType.type}`);
333
+ if (packType.handleOutput) {
334
+ await packType.handleOutput('output', async (relativePath, encoding = 'utf8') => await fs_extra_1.default.readFile(path_1.default.join(outputPath, relativePath), encoding), async (relativePath, contents) => {
335
+ if (contents === undefined) {
336
+ await fs_extra_1.default.unlink(path_1.default.join(outputPath, relativePath));
337
+ }
338
+ else {
339
+ await fs_extra_1.default.writeFile(path_1.default.join(outputPath, relativePath), contents);
340
+ }
341
+ });
342
+ }
343
+ if (packType.archiveOutput) {
344
+ archiveOutput(packType, outputPath);
345
+ }
346
+ // Handle client
347
+ if (!(server && packType.networkSides === 'server')) {
348
+ let fullClientPath;
349
+ if (worldName) {
350
+ fullClientPath = path_1.default.join(clientPath, packType.clientPath);
351
+ try {
352
+ fullClientPath = fullClientPath.replace('$packName$', packName);
353
+ }
354
+ catch { }
355
+ try {
356
+ fullClientPath = fullClientPath.replace('$worldName$', worldName);
357
+ }
358
+ catch { }
359
+ }
360
+ else {
361
+ fullClientPath = path_1.default.join(clientPath, packType.rootPath);
362
+ try {
363
+ fullClientPath = fullClientPath.replace('$packName$', packName);
364
+ }
365
+ catch { }
366
+ }
367
+ if (packType.archiveOutput) {
368
+ await fs_extra_1.default.copyFile(`${outputPath}.zip`, `${fullClientPath}.zip`);
369
+ }
370
+ else {
371
+ await fs_extra_1.default.remove(fullClientPath);
372
+ await fs_extra_1.default.copy(outputPath, fullClientPath);
373
+ }
374
+ if (packType.handleOutput) {
375
+ await packType.handleOutput('client', async (relativePath, encoding = 'utf8') => await fs_extra_1.default.readFile(path_1.default.join(clientPath, relativePath), encoding), async (relativePath, contents) => {
376
+ if (contents === undefined) {
377
+ fs_extra_1.default.unlink(path_1.default.join(clientPath, relativePath));
378
+ }
379
+ else {
380
+ await fs_extra_1.default.writeFile(path_1.default.join(clientPath, relativePath), contents);
381
+ }
382
+ });
383
+ }
384
+ }
385
+ // Handle server
386
+ if (server && (packType.networkSides === 'server' || packType.networkSides === 'both')) {
387
+ let serverPath = packType.serverPath;
388
+ try {
389
+ serverPath = serverPath.replace('$packName$', packName);
390
+ }
391
+ catch { }
392
+ if (packType.archiveOutput) {
393
+ await server.writeFile(await fs_extra_1.default.readFile(`${outputPath}.zip`, 'utf8'), `${serverPath}.zip`);
394
+ }
395
+ else {
396
+ server.remove(serverPath);
397
+ for await (const file of (0, klaw_1.default)(outputPath)) {
398
+ await server.writeFile(path_1.default.join(serverPath, file.path.split(outputPath)[1]), await fs_extra_1.default.readFile(file.path));
399
+ }
400
+ }
401
+ if (packType.handleOutput) {
402
+ await packType.handleOutput('server', server.readFile, server.writeFile);
403
+ }
404
+ }
312
405
  }
313
- catch (e) {
314
- // Previous directory was deleted by the user himself
406
+ }
407
+ else {
408
+ for (const packType of packTypes) {
409
+ const outputPath = path_1.default.join(rootFolder, '.sandstone/output/archives', `${packName}_${packType.type}`);
410
+ if (packType.handleOutput) {
411
+ await packType.handleOutput('output', async (relativePath, encoding = 'utf8') => await fs_extra_1.default.readFile(path_1.default.join(outputPath, relativePath), encoding), async (relativePath, contents) => {
412
+ if (contents === undefined) {
413
+ await fs_extra_1.default.unlink(path_1.default.join(outputPath, relativePath));
414
+ }
415
+ else {
416
+ await fs_extra_1.default.writeFile(path_1.default.join(outputPath, relativePath), contents);
417
+ }
418
+ });
419
+ }
420
+ if (packType.archiveOutput) {
421
+ archiveOutput(packType, outputPath);
422
+ }
315
423
  }
316
424
  }
425
+ // Delete old files that aren't cached anymore
426
+ const oldFilesNames = new Set(Object.keys(cache));
427
+ Object.keys(newCache).forEach(name => oldFilesNames.delete(name));
428
+ await Promise.allSettled([...oldFilesNames.values()].map(name => (0, util_1.promisify)(fs_extra_1.default.rm)(path_1.default.join(outputFolder, name))));
317
429
  // Override old cache
318
- cache[absProjectFolder] = newCache;
430
+ cache = newCache;
319
431
  // Run the afterAll script
320
- await ((_j = scripts === null || scripts === void 0 ? void 0 : scripts.afterAll) === null || _j === void 0 ? void 0 : _j.call(scripts, {
321
- dataPackName,
322
- destination: destinationPath,
323
- }));
432
+ await ((_e = scripts === null || scripts === void 0 ? void 0 : scripts.afterAll) === null || _e === void 0 ? void 0 : _e.call(scripts));
324
433
  }
325
434
  /**
326
435
  * Build the project. Will log errors and never throw any.
@@ -331,9 +440,9 @@ async function _buildProject(options, { absProjectFolder, rootFolder, sandstoneC
331
440
  *
332
441
  * @param changedFiles The files that changed since the last build.
333
442
  */
334
- async function buildProject(options, folders, changedFiles) {
443
+ async function buildProject(options, folders, resourceTypes, changedFiles) {
335
444
  try {
336
- await _buildProject(options, folders, changedFiles);
445
+ await _buildProject(options, folders, resourceTypes, changedFiles);
337
446
  }
338
447
  catch (err) {
339
448
  logError(err);
@@ -9,8 +9,8 @@ export default class Build extends Command {
9
9
  namespace: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
10
10
  world: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
11
11
  root: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
12
- path: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
13
- minecraftPath: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
12
+ clientPath: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
13
+ serverPath: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
14
14
  name: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
15
15
  description: import("@oclif/command/lib/flags").IOptionFlag<string | undefined>;
16
16
  formatVersion: import("@oclif/parser/lib/flags").IOptionFlag<number | undefined>;
@@ -18,11 +18,11 @@ class Build extends command_1.Command {
18
18
  transpileOnly: !flags.strictErrors,
19
19
  project: tsConfigPath,
20
20
  });
21
- (0, buildProject_1.buildProject)(flags, folders);
21
+ (0, buildProject_1.buildProject)(flags, folders, utils_1.datapackResources);
22
22
  }
23
23
  }
24
24
  exports.default = Build;
25
- Build.description = 'Build the datapack. ⛏';
25
+ Build.description = 'Build the packs. ⛏';
26
26
  Build.examples = [
27
27
  '$ sand build',
28
28
  '$ sand build --verbose',
@@ -6,11 +6,12 @@ export default class Create extends Command {
6
6
  help: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
7
7
  yarn: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
8
8
  npm: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
9
- 'datapack-name': flags.IOptionFlag<string | undefined>;
9
+ 'pack-name': flags.IOptionFlag<string | undefined>;
10
10
  namespace: flags.IOptionFlag<string | undefined>;
11
11
  'save-root': import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
12
12
  world: flags.IOptionFlag<string | undefined>;
13
- 'custom-path': flags.IOptionFlag<string | undefined>;
13
+ 'server-path': flags.IOptionFlag<string | undefined>;
14
+ 'client-path': flags.IOptionFlag<string | undefined>;
14
15
  };
15
16
  static args: {
16
17
  name: string;
@@ -28,7 +28,7 @@ class Create extends command_1.Command {
28
28
  const { args, flags } = this.parse(Create);
29
29
  const projectPath = path_1.default.resolve(args['project-name']);
30
30
  const projectName = path_1.default.basename(projectPath);
31
- const datapackName = await (0, utils_1.getFlagOrPrompt)(flags, 'datapack-name', {
31
+ const packName = await (0, utils_1.getFlagOrPrompt)(flags, 'pack-name', {
32
32
  message: 'Name of your data pack (can be changed later) >',
33
33
  type: 'input',
34
34
  default: projectName,
@@ -41,27 +41,27 @@ class Create extends command_1.Command {
41
41
  else if (flags.world) {
42
42
  saveOptions.world = flags.world;
43
43
  }
44
- else if (flags['custom-path']) {
45
- saveOptions.path = flags['custom-path'];
44
+ else if (flags['server-path']) {
45
+ saveOptions.serverPath = flags['server-path'];
46
46
  }
47
- else {
48
- // User didn't specify a way to save the file. Ask him.
47
+ else { // TODO: Add support for ssh
48
+ // User didn't specify a way to save the file. Ask them.
49
49
  const { saveChoice } = await inquirer_1.default.prompt({
50
50
  name: 'saveChoice',
51
51
  type: 'list',
52
- message: 'Where do you want your datapack to be saved (can be changed later)?',
52
+ message: 'Where do you want your packs to be saved (can be changed later)?',
53
53
  choices: [{
54
- name: 'In the root .minecraft/datapacks folder',
54
+ name: 'In the root client (.minecraft) folder',
55
55
  value: 'root',
56
- short: '.minecraft/datapacks folder',
56
+ short: 'Client folder',
57
57
  }, {
58
- name: 'In the datapacks folder of a world',
58
+ name: 'In a world',
59
59
  value: 'world',
60
- short: 'World datapacks folder',
60
+ short: 'World',
61
61
  }, {
62
- name: 'At a custom path',
63
- value: 'path',
64
- short: 'Custom path',
62
+ name: 'In a server',
63
+ value: 'server-path',
64
+ short: 'Server path',
65
65
  }],
66
66
  });
67
67
  if (saveChoice === 'root') {
@@ -69,22 +69,25 @@ class Create extends command_1.Command {
69
69
  }
70
70
  else if (saveChoice === 'world') {
71
71
  const { world } = await inquirer_1.default.prompt({
72
- name: 'world',
73
- message: 'What world do you want to save the Datapack in? >',
72
+ name: 'World',
73
+ message: 'What world do you want to save the packs in? >',
74
74
  type: 'list',
75
75
  choices: utils_1.getWorldsList,
76
76
  });
77
77
  saveOptions.world = world;
78
78
  }
79
- else {
80
- const { path } = await inquirer_1.default.prompt({
81
- name: 'path',
82
- message: 'Where do you want to save the data pack? Relative paths are accepted. >',
79
+ else { // TODO: Add native folder selector
80
+ const { serverPath } = await inquirer_1.default.prompt({
81
+ name: 'Server path',
82
+ message: 'Where is the server to save the packs in? Relative paths are accepted. >',
83
83
  type: 'input',
84
84
  });
85
- saveOptions.path = path;
85
+ saveOptions.serverPath = serverPath;
86
86
  }
87
87
  }
88
+ if (flags['client-path']) {
89
+ saveOptions.clientPath = flags['client-path'];
90
+ }
88
91
  const namespace = await (0, utils_1.getFlagOrPrompt)(flags, 'namespace', {
89
92
  message: 'Default namespace (can be changed later) >',
90
93
  default: 'default',
@@ -115,6 +118,7 @@ class Create extends command_1.Command {
115
118
  (0, child_process_1.execSync)('npm install sandstone', { cwd: projectPath });
116
119
  (0, child_process_1.execSync)('npm install --save-dev typescript @types/node sandstone-cli', { cwd: projectPath });
117
120
  }
121
+ // TODO: Make profiles for either packs or libraries
118
122
  // Merge with the package.json template
119
123
  const generatedPackage = JSON.parse(fs_1.default.readFileSync(path_1.default.join(projectPath, 'package.json')).toString());
120
124
  /** Remove the `main` property */
@@ -128,9 +132,13 @@ class Create extends command_1.Command {
128
132
  fs_1.default.writeFileSync(path_1.default.join(projectPath, 'sandstone.config.ts'), `import type { SandstoneConfig } from 'sandstone'
129
133
 
130
134
  export default {
131
- name: ${toJson(datapackName)},
132
- description: ${toJson(['A ', { text: 'Sandstone', color: 'gold' }, ' data pack.'])},
133
- formatVersion: ${7},
135
+ name: ${toJson(packName)},
136
+ packs: {
137
+ datapack: {
138
+ description: ${toJson(['A ', { text: 'Sandstone', color: 'gold' }, ' data pack.'])},
139
+ packFormat: ${11},
140
+ }
141
+ },
134
142
  namespace: ${toJson(namespace)},
135
143
  packUid: ${toJson((0, nanoid_1.nanoid)(8))},
136
144
  saveOptions: ${toJson(Object.fromEntries(Object.entries(saveOptions).filter(([_, value]) => value !== undefined)))},
@@ -151,17 +159,18 @@ export default {
151
159
  exports.default = Create;
152
160
  Create.description = 'Create a new Sandstone project.';
153
161
  Create.examples = [
154
- '$ sand create my-datapack',
162
+ '$ sand create my-pack',
155
163
  ];
156
164
  Create.flags = {
157
165
  help: command_1.flags.help({ char: 'h' }),
158
166
  yarn: command_1.flags.boolean({ description: 'Use yarn instead of npm.', env: 'USE_YARN', exclusive: ['npm'] }),
159
167
  npm: command_1.flags.boolean({ description: 'Use npm.', env: 'USE_NPM', exclusive: ['yarn'] }),
160
- 'datapack-name': command_1.flags.string({ char: 'd', env: 'DATAPACK_NAME', description: 'The name of the data pack.' }),
168
+ 'pack-name': command_1.flags.string({ char: 'd', env: 'PACK_NAME', description: 'The name of the data pack.' }),
161
169
  namespace: command_1.flags.string({ char: 'n', env: 'NAMESPACE', description: 'The default namespace that will be used.' }),
162
- 'save-root': command_1.flags.boolean({ char: 'r', env: 'SAVE_ROOT', description: 'Save the data pack in the .minecraft/datapacks folder. Not compatible with --world and --custom-path.', exclusive: ['world', 'custom-path'] }),
163
- world: command_1.flags.string({ char: 'w', env: 'WORLD', description: 'The world to save the data pack in. Not compatible with --save-root and --custom-path.', exclusive: ['save-root', 'custom-path'] }),
164
- 'custom-path': command_1.flags.string({ char: 'p', env: 'CUSTOM_PATH', description: 'The path to save the data pack at. Not compatible with --save-root and --world.', exclusive: ['save-root', 'world'] }),
170
+ 'save-root': command_1.flags.boolean({ char: 'r', env: 'SAVE_ROOT', description: 'Save the data pack & resource pack in the .minecraft/datapacks & .minecraft/resource_packs folders. Not compatible with --world.', exclusive: ['world'] }),
171
+ world: command_1.flags.string({ char: 'w', env: 'WORLD', description: 'The world to save the packs in. Not compatible with --save-root or --server', exclusive: ['save-root', 'server'] }),
172
+ 'server-path': command_1.flags.string({ char: 's', env: 'SERVER_PATH', description: 'The server path to write the server-side packs at. Not compatible with --world.', exclusive: ['world'] }),
173
+ 'client-path': command_1.flags.string({ char: 'c', env: 'CLIENT_PATH', description: 'The client path to write packs at.' }),
165
174
  };
166
175
  Create.args = [{
167
176
  name: 'project-name',
@@ -9,8 +9,8 @@ export default class Watch extends Command {
9
9
  namespace: flags.IOptionFlag<string | undefined>;
10
10
  world: flags.IOptionFlag<string | undefined>;
11
11
  root: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
12
- path: flags.IOptionFlag<string | undefined>;
13
- minecraftPath: flags.IOptionFlag<string | undefined>;
12
+ clientPath: flags.IOptionFlag<string | undefined>;
13
+ serverPath: flags.IOptionFlag<string | undefined>;
14
14
  name: flags.IOptionFlag<string | undefined>;
15
15
  description: flags.IOptionFlag<string | undefined>;
16
16
  formatVersion: import("@oclif/parser/lib/flags").IOptionFlag<number | undefined>;
@@ -15,6 +15,7 @@ class Watch extends command_1.Command {
15
15
  let alreadyBuilding = false;
16
16
  let needRebuild = false;
17
17
  let client = null;
18
+ // TODO: add support for clients & resources that require restarts & world resets, sandstone-server should override the involved environment variables if mods are present that fix it
18
19
  if (flags.autoReload !== undefined) {
19
20
  try {
20
21
  client = (await require('minecraft-protocol')).createClient({
@@ -36,7 +37,7 @@ class Watch extends command_1.Command {
36
37
  return;
37
38
  }
38
39
  alreadyBuilding = true;
39
- await (0, buildProject_1.buildProject)(flags, folders, paths);
40
+ await (0, buildProject_1.buildProject)(flags, folders, utils_1.datapackResources, paths);
40
41
  client === null || client === void 0 ? void 0 : client.write('chat', { message: '/reload' });
41
42
  alreadyBuilding = false;
42
43
  if (needRebuild) {
@@ -72,7 +73,7 @@ class Watch extends command_1.Command {
72
73
  }
73
74
  }
74
75
  exports.default = Watch;
75
- Watch.description = 'Build the datapack, and rebuild it on file change. ⛏';
76
+ Watch.description = 'Build the packs, and rebuild them on file change. ⛏';
76
77
  Watch.examples = [
77
78
  '$ sand watch',
78
79
  '$ sand watch --verbose',
@@ -80,13 +81,14 @@ Watch.examples = [
80
81
  ];
81
82
  Watch.flags = {
82
83
  help: command_1.flags.help({ char: 'h' }),
83
- dry: command_1.flags.boolean({ char: 'd', description: 'Do not save the datapack. Mostly useful with `verbose`.' }),
84
+ dry: command_1.flags.boolean({ char: 'd', description: 'Do not save the pack. Mostly useful with `verbose`.' }),
84
85
  verbose: command_1.flags.boolean({ char: 'v', description: 'Log all resulting resources: functions, advancements...' }),
85
86
  namespace: command_1.flags.string({ description: 'The default namespace. Override the value specified in the configuration file.' }),
86
87
  world: command_1.flags.string({ description: 'The world to save the data pack in. Override the value specified in the configuration file.' }),
87
- root: command_1.flags.boolean({ description: 'Save the data pack in the `.minecraft/datapacks` folder. Override the value specified in the configuration file.' }),
88
- path: command_1.flags.string({ description: 'The path to save the data pack at. Override the value specified in the configuration file.' }),
89
- minecraftPath: command_1.flags.string({ name: 'minecraft-path', description: 'Path of the .minecraft folder. Override the value specified in the configuration file.' }),
88
+ root: command_1.flags.boolean({ description: 'Save the data pack & resource pack in the .minecraft/datapacks & .minecraft/resource_packs folders. Override the value specified in the configuration file.' }),
89
+ clientPath: command_1.flags.string({ name: 'client-path', description: 'Path of the client folder. Override the value specified in the configuration file.' }),
90
+ serverPath: command_1.flags.string({ name: 'server-path', description: 'Path of the server folder. Override the value specified in the configuration file.' }),
91
+ // TODO: ssh
90
92
  name: command_1.flags.string({ description: 'Name of the data pack. Override the value specified in the configuration file.' }),
91
93
  description: command_1.flags.string({ description: 'Description of the data pack. Override the value specified in the configuration file.' }),
92
94
  formatVersion: command_1.flags.integer({ name: 'format', description: 'Pack format version. Override the value specified in the configuration file.' }),
@@ -1,6 +1,6 @@
1
1
  # Sandstone project
2
2
 
3
- To build the datapack, run:
3
+ To build the packs, run:
4
4
  ```ts
5
5
  npm run build
6
6
  // or
@@ -9,7 +9,7 @@ yarn build
9
9
  sand build
10
10
  ```
11
11
 
12
- To automatically rebuild the datapack on each change, run:
12
+ To automatically rebuild the packs on each change, run:
13
13
  ```ts
14
14
  npm run watch
15
15
  // or
package/lib/utils.d.ts CHANGED
@@ -28,3 +28,4 @@ export declare type ProjectFolders = {
28
28
  sandstoneConfigFolder: string;
29
29
  };
30
30
  export declare function getProjectFolders(projectFolder: string): ProjectFolders;
31
+ export declare const datapackResources: string[];
package/lib/utils.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getProjectFolders = exports.getFileFolder = exports.getWorldPath = exports.getWorldsList = exports.getMinecraftPath = exports.hasYarn = exports.getFlagOrPrompt = void 0;
6
+ exports.datapackResources = exports.getProjectFolders = exports.getFileFolder = exports.getWorldPath = exports.getWorldsList = exports.getMinecraftPath = exports.hasYarn = exports.getFlagOrPrompt = void 0;
7
7
  const inquirer_1 = __importDefault(require("inquirer"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const os_1 = __importDefault(require("os"));
@@ -119,3 +119,4 @@ function getProjectFolders(projectFolder) {
119
119
  };
120
120
  }
121
121
  exports.getProjectFolders = getProjectFolders;
122
+ exports.datapackResources = ['mcfunction', 'advancement', 'item_modifier', 'loot_table', 'predicate', 'recipe', 'tag', 'trim_material', 'trim_pattern'];
@@ -1 +1 @@
1
- {"version":"0.6.0","commands":{"build":{"id":"build","description":"Build the datapack. ⛏","pluginName":"sandstone-cli","pluginType":"core","aliases":[],"examples":["$ sand build","$ sand build --verbose","$ sand build --verbose --dry"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"dry":{"name":"dry","type":"boolean","char":"d","description":"Do not save the datapack. Mostly useful with `verbose`.","allowNo":false},"verbose":{"name":"verbose","type":"boolean","char":"v","description":"Log all resulting resources: functions, advancements...","allowNo":false},"namespace":{"name":"namespace","type":"option","description":"The default namespace. Override the value specified in the configuration file."},"world":{"name":"world","type":"option","description":"The world to save the data pack in. Override the value specified in the configuration file."},"root":{"name":"root","type":"boolean","description":"Save the data pack in the `.minecraft/datapacks` folder. Override the value specified in the configuration file.","allowNo":false},"path":{"name":"path","type":"option","description":"The path to save the data pack at. Override the value specified in the configuration file."},"minecraftPath":{"name":"minecraftPath","type":"option","description":"Path of the .minecraft folder. Override the value specified in the configuration file."},"name":{"name":"name","type":"option","description":"Name of the data pack. Override the value specified in the configuration file."},"description":{"name":"description","type":"option","description":"Description of the data pack. Override the value specified in the configuration file."},"formatVersion":{"name":"formatVersion","type":"option","description":"Pack format version. Override the value specified in the configuration file."},"fullTrace":{"name":"fullTrace","type":"boolean","description":"Show the full stack trace on errors.","allowNo":false},"strictErrors":{"name":"strictErrors","type":"boolean","description":"Stop data pack compilation on type errors.","allowNo":false},"production":{"name":"production","type":"boolean","char":"p","description":"Runs Sandstone in production mode. This sets process.env.SANDSTONE_ENV to \"production\".","allowNo":false},"autoReload":{"name":"autoReload","type":"option","description":"Automatically reload your data pack in-game. Requires to open the world to LAN with cheats enabled, and to specify the port.","helpValue":"port"}},"args":[{"name":"path","description":"Path of the folder containing source files.","required":true,"default":"./src"},{"name":"config-path","description":"Path of the sandstone.config.ts folder.","required":true,"default":"."}]},"create":{"id":"create","description":"Create a new Sandstone project.","pluginName":"sandstone-cli","pluginType":"core","aliases":[],"examples":["$ sand create my-datapack"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"yarn":{"name":"yarn","type":"boolean","description":"Use yarn instead of npm.","allowNo":false},"npm":{"name":"npm","type":"boolean","description":"Use npm.","allowNo":false},"datapack-name":{"name":"datapack-name","type":"option","char":"d","description":"The name of the data pack."},"namespace":{"name":"namespace","type":"option","char":"n","description":"The default namespace that will be used."},"save-root":{"name":"save-root","type":"boolean","char":"r","description":"Save the data pack in the .minecraft/datapacks folder. Not compatible with --world and --custom-path.","allowNo":false},"world":{"name":"world","type":"option","char":"w","description":"The world to save the data pack in. Not compatible with --save-root and --custom-path."},"custom-path":{"name":"custom-path","type":"option","char":"p","description":"The path to save the data pack at. Not compatible with --save-root and --world."}},"args":[{"name":"project-name","description":"Name of the project folder. This is not the name of the data pack.","required":true}]},"update":{"id":"update","description":"Update Sandstone & Sandstone-CLI.","pluginName":"sandstone-cli","pluginType":"core","aliases":[],"examples":["$ sand update","$ sand update --cli","$ sand update --sandstone","$ sand update --cli --sandstone --skip"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"cli":{"name":"cli","type":"boolean","description":"Update the Sandstone CLI without asking.","allowNo":false},"sandstone":{"name":"sandstone","type":"boolean","description":"Update the current Sandstone version without asking.","allowNo":false},"skip":{"name":"skip","type":"boolean","description":"Skip all interactive prompts and refuse them.","allowNo":false},"yarn":{"name":"yarn","type":"boolean","description":"Use yarn to install the updates.","allowNo":false},"npm":{"name":"npm","type":"boolean","description":"Use npm to install the updates.","allowNo":false}},"args":[]},"watch":{"id":"watch","description":"Build the datapack, and rebuild it on file change. ⛏","pluginName":"sandstone-cli","pluginType":"core","aliases":[],"examples":["$ sand watch","$ sand watch --verbose","$ sand watch --verbose --dry"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"dry":{"name":"dry","type":"boolean","char":"d","description":"Do not save the datapack. Mostly useful with `verbose`.","allowNo":false},"verbose":{"name":"verbose","type":"boolean","char":"v","description":"Log all resulting resources: functions, advancements...","allowNo":false},"namespace":{"name":"namespace","type":"option","description":"The default namespace. Override the value specified in the configuration file."},"world":{"name":"world","type":"option","description":"The world to save the data pack in. Override the value specified in the configuration file."},"root":{"name":"root","type":"boolean","description":"Save the data pack in the `.minecraft/datapacks` folder. Override the value specified in the configuration file.","allowNo":false},"path":{"name":"path","type":"option","description":"The path to save the data pack at. Override the value specified in the configuration file."},"minecraftPath":{"name":"minecraftPath","type":"option","description":"Path of the .minecraft folder. Override the value specified in the configuration file."},"name":{"name":"name","type":"option","description":"Name of the data pack. Override the value specified in the configuration file."},"description":{"name":"description","type":"option","description":"Description of the data pack. Override the value specified in the configuration file."},"formatVersion":{"name":"formatVersion","type":"option","description":"Pack format version. Override the value specified in the configuration file."},"fullTrace":{"name":"fullTrace","type":"boolean","description":"Show the full stack trace on errors.","allowNo":false},"strictErrors":{"name":"strictErrors","type":"boolean","description":"Stop data pack compilation on type errors.","allowNo":false},"production":{"name":"production","type":"boolean","char":"p","description":"Runs Sandstone in production mode. This sets process.env.SANDSTONE_ENV to \"production\".","allowNo":false},"autoReload":{"name":"autoReload","type":"option","description":"Automatically reload your data pack in-game. Requires to open the world to LAN with cheats enabled, and to specify the port.","helpValue":"port"}},"args":[{"name":"path","description":"Path of the folder containing source files.","required":true,"default":"./src"},{"name":"config-path","description":"Path of the sandstone.config.ts folder.","required":true,"default":"."}]}}}
1
+ {"version":"0.6.1","commands":{"build":{"id":"build","description":"Build the packs. ⛏","pluginName":"sandstone-cli","pluginType":"core","aliases":[],"examples":["$ sand build","$ sand build --verbose","$ sand build --verbose --dry"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"dry":{"name":"dry","type":"boolean","char":"d","description":"Do not save the pack. Mostly useful with `verbose`.","allowNo":false},"verbose":{"name":"verbose","type":"boolean","char":"v","description":"Log all resulting resources: functions, advancements...","allowNo":false},"namespace":{"name":"namespace","type":"option","description":"The default namespace. Override the value specified in the configuration file."},"world":{"name":"world","type":"option","description":"The world to save the data pack in. Override the value specified in the configuration file."},"root":{"name":"root","type":"boolean","description":"Save the data pack & resource pack in the .minecraft/datapacks & .minecraft/resource_packs folders. Override the value specified in the configuration file.","allowNo":false},"clientPath":{"name":"clientPath","type":"option","description":"Path of the client folder. Override the value specified in the configuration file."},"serverPath":{"name":"serverPath","type":"option","description":"Path of the server folder. Override the value specified in the configuration file."},"name":{"name":"name","type":"option","description":"Name of the data pack. Override the value specified in the configuration file."},"description":{"name":"description","type":"option","description":"Description of the data pack. Override the value specified in the configuration file."},"formatVersion":{"name":"formatVersion","type":"option","description":"Pack format version. Override the value specified in the configuration file."},"fullTrace":{"name":"fullTrace","type":"boolean","description":"Show the full stack trace on errors.","allowNo":false},"strictErrors":{"name":"strictErrors","type":"boolean","description":"Stop data pack compilation on type errors.","allowNo":false},"production":{"name":"production","type":"boolean","char":"p","description":"Runs Sandstone in production mode. This sets process.env.SANDSTONE_ENV to \"production\".","allowNo":false},"autoReload":{"name":"autoReload","type":"option","description":"Automatically reload your data pack in-game. Requires to open the world to LAN with cheats enabled, and to specify the port.","helpValue":"port"}},"args":[{"name":"path","description":"Path of the folder containing source files.","required":true,"default":"./src"},{"name":"config-path","description":"Path of the sandstone.config.ts folder.","required":true,"default":"."}]},"create":{"id":"create","description":"Create a new Sandstone project.","pluginName":"sandstone-cli","pluginType":"core","aliases":[],"examples":["$ sand create my-pack"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"yarn":{"name":"yarn","type":"boolean","description":"Use yarn instead of npm.","allowNo":false},"npm":{"name":"npm","type":"boolean","description":"Use npm.","allowNo":false},"pack-name":{"name":"pack-name","type":"option","char":"d","description":"The name of the data pack."},"namespace":{"name":"namespace","type":"option","char":"n","description":"The default namespace that will be used."},"save-root":{"name":"save-root","type":"boolean","char":"r","description":"Save the data pack & resource pack in the .minecraft/datapacks & .minecraft/resource_packs folders. Not compatible with --world.","allowNo":false},"world":{"name":"world","type":"option","char":"w","description":"The world to save the packs in. Not compatible with --save-root or --server"},"server-path":{"name":"server-path","type":"option","char":"s","description":"The server path to write the server-side packs at. Not compatible with --world."},"client-path":{"name":"client-path","type":"option","char":"c","description":"The client path to write packs at."}},"args":[{"name":"project-name","description":"Name of the project folder. This is not the name of the data pack.","required":true}]},"update":{"id":"update","description":"Update Sandstone & Sandstone-CLI.","pluginName":"sandstone-cli","pluginType":"core","aliases":[],"examples":["$ sand update","$ sand update --cli","$ sand update --sandstone","$ sand update --cli --sandstone --skip"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"cli":{"name":"cli","type":"boolean","description":"Update the Sandstone CLI without asking.","allowNo":false},"sandstone":{"name":"sandstone","type":"boolean","description":"Update the current Sandstone version without asking.","allowNo":false},"skip":{"name":"skip","type":"boolean","description":"Skip all interactive prompts and refuse them.","allowNo":false},"yarn":{"name":"yarn","type":"boolean","description":"Use yarn to install the updates.","allowNo":false},"npm":{"name":"npm","type":"boolean","description":"Use npm to install the updates.","allowNo":false}},"args":[]},"watch":{"id":"watch","description":"Build the packs, and rebuild them on file change. ⛏","pluginName":"sandstone-cli","pluginType":"core","aliases":[],"examples":["$ sand watch","$ sand watch --verbose","$ sand watch --verbose --dry"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"dry":{"name":"dry","type":"boolean","char":"d","description":"Do not save the pack. Mostly useful with `verbose`.","allowNo":false},"verbose":{"name":"verbose","type":"boolean","char":"v","description":"Log all resulting resources: functions, advancements...","allowNo":false},"namespace":{"name":"namespace","type":"option","description":"The default namespace. Override the value specified in the configuration file."},"world":{"name":"world","type":"option","description":"The world to save the data pack in. Override the value specified in the configuration file."},"root":{"name":"root","type":"boolean","description":"Save the data pack & resource pack in the .minecraft/datapacks & .minecraft/resource_packs folders. Override the value specified in the configuration file.","allowNo":false},"clientPath":{"name":"clientPath","type":"option","description":"Path of the client folder. Override the value specified in the configuration file."},"serverPath":{"name":"serverPath","type":"option","description":"Path of the server folder. Override the value specified in the configuration file."},"name":{"name":"name","type":"option","description":"Name of the data pack. Override the value specified in the configuration file."},"description":{"name":"description","type":"option","description":"Description of the data pack. Override the value specified in the configuration file."},"formatVersion":{"name":"formatVersion","type":"option","description":"Pack format version. Override the value specified in the configuration file."},"fullTrace":{"name":"fullTrace","type":"boolean","description":"Show the full stack trace on errors.","allowNo":false},"strictErrors":{"name":"strictErrors","type":"boolean","description":"Stop data pack compilation on type errors.","allowNo":false},"production":{"name":"production","type":"boolean","char":"p","description":"Runs Sandstone in production mode. This sets process.env.SANDSTONE_ENV to \"production\".","allowNo":false},"autoReload":{"name":"autoReload","type":"option","description":"Automatically reload your data pack in-game. Requires to open the world to LAN with cheats enabled, and to specify the port.","helpValue":"port"}},"args":[{"name":"path","description":"Path of the folder containing source files.","required":true,"default":"./src"},{"name":"config-path","description":"Path of the sandstone.config.ts folder.","required":true,"default":"."}]}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sandstone-cli",
3
3
  "description": "The CLI for Sandstone - the data pack creation library.",
4
- "version": "0.6.0",
4
+ "version": "0.6.1",
5
5
  "contributors": [
6
6
  {
7
7
  "name": "TheMrZZ - Florian ERNST",
@@ -22,8 +22,10 @@
22
22
  "@oclif/config": "^1",
23
23
  "@oclif/plugin-help": "^3",
24
24
  "@oclif/plugin-warn-if-update-available": "^1.7.0",
25
+ "@types/adm-zip": "^0.5.0",
25
26
  "@types/node": "^18.11.18",
26
27
  "@types/semver": "^7.3.4",
28
+ "adm-zip": "^0.5.10",
27
29
  "chalk": "^4.1.0",
28
30
  "chokidar": "^3.4.3",
29
31
  "fs-extra": "^9.0.1",
@@ -42,7 +44,7 @@
42
44
  "@oclif/dev-cli": "^1",
43
45
  "@types/fs-extra": "^9.0.4",
44
46
  "@types/inquirer": "^7.3.1",
45
- "@types/klaw": "^3.0.1",
47
+ "@types/klaw": "^3.0.3",
46
48
  "@types/lodash.debounce": "^4.0.6",
47
49
  "@types/madge": "^5.0.0",
48
50
  "@types/nodemon": "^1.19.0",