sapdon 3.5.1 → 3.5.2
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 +6 -4
- package/doc/guidebook.md +1 -1
- package/doc/user/faq.md +3 -15
- package/doc/user/quick-start.md +6 -2
- package/package.json +1 -1
- package/prod/cli/start.js +1 -1
- package/prod/core/index.d.ts +1 -1
- package/prod/templates/js_sapdon/build.config +24 -0
- package/prod/templates/js_sapdon/main.mjs +4 -0
- package/prod/templates/js_sapdon/mod.info +7 -0
- package/prod/templates/js_sapdon/pack_icon.png +0 -0
- package/prod/templates/js_sapdon/package.json +21 -0
- package/prod/templates/js_sapdon/res/animations/animation_item.animation.json +34 -0
- package/prod/templates/js_sapdon/res/animations/large_item.animation.json +27 -0
- package/prod/templates/js_sapdon/res/models/blocks/crop.geo.json +48 -0
- package/prod/templates/js_sapdon/res/models/blocks/flipbook_item.geo.json +3160 -0
- package/prod/templates/js_sapdon/res/models/entity/animation/animation_item.geo.json +26 -0
- package/prod/templates/js_sapdon/res/models/entity/animation/large_item.geo.json +28 -0
- package/prod/templates/js_sapdon/res/textures/blocks/none.png +0 -0
- package/prod/templates/js_sapdon/res/textures/blocks/test_log_oak.png +0 -0
- package/prod/templates/js_sapdon/res/textures/blocks/test_log_top.png +0 -0
- package/prod/templates/js_sapdon/res/textures/items/masterball.png +0 -0
- package/prod/templates/js_sapdon/scripts/custom_components/cropComponent.js +50 -0
- package/prod/templates/js_sapdon/scripts/custom_components/items/gui_book.js +37 -0
- package/prod/templates/js_sapdon/scripts/custom_components/registry.js +25 -0
- package/prod/templates/js_sapdon/scripts/index.js +1 -0
- package/prod/templates/ts_sapdon/build.config +24 -0
- package/prod/templates/ts_sapdon/main.ts +15 -0
- package/prod/templates/ts_sapdon/mod.info +7 -0
- package/prod/templates/ts_sapdon/pack_icon.png +0 -0
- package/prod/templates/ts_sapdon/package.json +21 -0
- package/prod/templates/ts_sapdon/res/animations/animation_item.animation.json +34 -0
- package/prod/templates/ts_sapdon/res/animations/large_item.animation.json +27 -0
- package/prod/templates/ts_sapdon/res/models/blocks/crop.geo.json +48 -0
- package/prod/templates/ts_sapdon/res/models/blocks/flipbook_item.geo.json +3160 -0
- package/prod/templates/ts_sapdon/res/models/entity/animation/animation_item.geo.json +26 -0
- package/prod/templates/ts_sapdon/res/models/entity/animation/large_item.geo.json +28 -0
- package/prod/templates/ts_sapdon/res/models/entity/dummy.geo.json +24 -0
- package/prod/templates/ts_sapdon/res/models/entity/falling_block.geo.json +35 -0
- package/prod/templates/ts_sapdon/res/textures/blocks/none.png +0 -0
- package/prod/templates/ts_sapdon/res/textures/blocks/test_log_oak.png +0 -0
- package/prod/templates/ts_sapdon/res/textures/blocks/test_log_top.png +0 -0
- package/prod/templates/ts_sapdon/res/textures/items/masterball.png +0 -0
- package/prod/templates/ts_sapdon/scripts/index.ts +14 -0
- package/prod/templates/ts_sapdon/tsconfig.json +117 -0
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Sapdon
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-
|
|
5
3
|
Minecraft Bedrock 版 Addon 开发框架,将 JSON 配置抽象为 TypeScript 类,提供类型安全的 API 和自动化构建工具。
|
|
6
4
|
|
|
7
5
|
[](https://nodejs.org/)
|
|
@@ -31,14 +29,18 @@ Minecraft Bedrock 版 Addon 开发框架,将 JSON 配置抽象为 TypeScript
|
|
|
31
29
|
|
|
32
30
|
### 安装
|
|
33
31
|
|
|
32
|
+
把 `sapdon` 作为当前项目的本地开发依赖安装(不写入全局 PATH):
|
|
33
|
+
|
|
34
34
|
```bash
|
|
35
|
-
npm install -
|
|
35
|
+
npm install -D sapdon
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
### 创建项目
|
|
39
39
|
|
|
40
|
+
通过 `npx` 调用本地安装的 `sapdon`:
|
|
41
|
+
|
|
40
42
|
```bash
|
|
41
|
-
sapdon create my_addon
|
|
43
|
+
npx sapdon create my_addon
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
根据提示输入项目信息,选择 TypeScript 或 JavaScript 模板。
|
package/doc/guidebook.md
CHANGED
package/doc/user/faq.md
CHANGED
|
@@ -2,13 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 1. 如何更新框架版本?
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm update -g sapdon
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
如果使用的是本地项目依赖,请在项目目录中执行:
|
|
5
|
+
sapdon 作为本地 devDependency 安装,请在项目目录中更新:
|
|
12
6
|
|
|
13
7
|
```bash
|
|
14
8
|
npm update sapdon
|
|
@@ -95,19 +89,13 @@ $env:MC_PATH = "C:\Users\<用户名>\AppData\Local\Packages\Microsoft.MinecraftU
|
|
|
95
89
|
|
|
96
90
|
## 7. 构建报错 "tsc-alias not found"?
|
|
97
91
|
|
|
98
|
-
|
|
92
|
+
确保已在项目目录安装依赖(sapdon 作为本地 devDependency,`npm install` 会一并安装,无需全局安装):
|
|
99
93
|
|
|
100
94
|
```bash
|
|
101
95
|
npm install
|
|
102
96
|
```
|
|
103
97
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
```bash
|
|
107
|
-
npm install -g sapdon
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
此错误通常是因为依赖未正确安装或 node_modules 目录不完整导致的。
|
|
98
|
+
此错误通常是因为依赖未正确安装或 `node_modules` 目录不完整导致的。
|
|
111
99
|
|
|
112
100
|
---
|
|
113
101
|
|
package/doc/user/quick-start.md
CHANGED
|
@@ -8,14 +8,18 @@
|
|
|
8
8
|
|
|
9
9
|
## 安装 CLI
|
|
10
10
|
|
|
11
|
+
把 `sapdon` 作为当前项目的本地开发依赖安装(不写入全局 PATH):
|
|
12
|
+
|
|
11
13
|
```bash
|
|
12
|
-
npm install -
|
|
14
|
+
npm install -D sapdon
|
|
13
15
|
```
|
|
14
16
|
|
|
15
17
|
## 创建项目
|
|
16
18
|
|
|
19
|
+
通过 `npx` 调用本地安装的 `sapdon`:
|
|
20
|
+
|
|
17
21
|
```bash
|
|
18
|
-
sapdon create hello_sapdon
|
|
22
|
+
npx sapdon create hello_sapdon
|
|
19
23
|
```
|
|
20
24
|
|
|
21
25
|
按提示填写项目信息:
|
package/package.json
CHANGED
package/prod/cli/start.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{program as e}from"commander";import n from"inquirer";import o from"path";import{fileURLToPath as t}from"url";import i from"fs";import{randomUUID as r}from"crypto";import{fileURLToPath as s}from"node:url";import c from"child_process";import a from"fs/promises";import l from"http";import{rollup as u}from"rollup";import p from"@rollup/plugin-commonjs";import{nodeResolve as d}from"@rollup/plugin-node-resolve";import m from"@rollup/plugin-typescript";import{typescriptPaths as f}from"rollup-plugin-typescript-paths";import g from"@rollup/plugin-json";import"rollup-plugin-visualizer";import y from"@rollup/plugin-terser";import h from"os";import j from"lodash";import b from"archiver";const S=()=>r();function v(e,n){try{i.copyFileSync(e,n)}catch(e){console.error("文件复制失败:",e)}}const w=e=>!i.existsSync(e),_=e=>{try{return i.readFileSync(e,"utf8")}catch(e){console.log(e)}return null},O=(e,n)=>{i.mkdirSync(o.dirname(e),{recursive:!0}),i.writeFileSync(e,n)},k=(e,n)=>{if(i.mkdirSync(o.dirname(n),{recursive:!0}),!i.existsSync(e))return void console.log(`Source path ${e} does not exist.`);i.existsSync(n)||i.mkdirSync(n);i.readdirSync(e).forEach(t=>{const r=o.join(e,t),s=o.join(n,t);i.lstatSync(r).isDirectory()?k(r,s):i.copyFileSync(r,s)})};function x(e){const n=s(e.url);return o.dirname(n)}const N=new Map;function $(e,n){let o=N.get(e);return o||(o=n(e),N.set(e,o),o)}function J(){const e=E(),n=o.join(e,"build.config");if(!i.existsSync(n))throw new Error("未找到项目配置文件,请先初始化项目");return $(n,e=>function(e){const n=(o=i.readFileSync(e),JSON.parse(String(o).replace(/\/\/.*|\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/g,"$1")));var o;if(2===n.formatVersion)return n;const t=function({defaultConfig:e,resources:n,scripts:o}){const t={formatVersion:2,buildOptions:{useHMR:!0,buildMode:"dev",buildEntry:e.buildEntry,scriptEntry:e.scriptEntry,scriptOutput:e.scriptEntry.replace(".ts",".js"),useJs:"ts"!==o[0].type,buildDir:e.buildDir,dependencies:e.dependencies,resource:{path:n[0].path,resourceHints:!0}},versionType:"release"};return t}(n);return i.writeFileSync(e,JSON.stringify(t,null,2)),t}(e))}const F=t(import.meta.url),R=o.dirname(F),P={js:"js_sapdon",ts:"ts_sapdon"},D=e=>{const n=o.join(e,"package.json");if(!i.existsSync(n))return null;try{const t=JSON.parse(i.readFileSync(n,"utf-8"));return{name:o.basename(e),description:t.description||"A new sapdon project",author:t.author||"Sapdon",version:t.version||"1.0.0"}}catch(e){return console.error("读取package.json文件时出错:",e),null}},M={};function E(){const e=M.projectPath??process.cwd();if(!i.existsSync(o.join(e,"build.config")))throw new Error("无效的项目路径");return e}function B(){const{buildDir:e}=J().buildOptions,n=$("projectName",()=>o.basename(E()));return o.join(E(),e,n+"_bp")}const H=async(e,n,t="")=>{const i={};try{await a.access(e)}catch{return i}const r=await a.readdir(e);for(const s of r){const r=o.join(e,s);if((await a.stat(r)).isDirectory()){const e=await H(r,n,t);Object.assign(i,e)}else if(s.endsWith(".png")){const e=o.basename(s,".png"),c=`${t}${o.relative(n,r).replace(/\.png$/,"").replace(/\\/g,"/")}`;i[e]={textures:c}}}return i},L=async(e,n,o)=>{try{const t=JSON.stringify(n,null,2);await a.writeFile(e,t),console.log(o)}catch(e){console.error("Error writing JSON file:",e)}};Symbol.metadata||(Symbol.metadata=Symbol("[[metadata]]"));const A=Symbol("isRawJSON");const I=["boolean","number"],C=["string","undefined"];function W(e,n){const o=typeof n;if(null===o)return null;if(C.includes(o))return n;if(I.includes(o))return JSON.rawJSON(n);if("object"===o)return JSON.isRawJSON(n)?n:function(e){return!0===e?.[A]}(n)?JSON.rawJSON(n.rawJSON):n;if("bigint"===o)return JSON.rawJSON(n.toString());throw new Error("Unexpected value")}const T={encode:e=>JSON.stringify(e,W),decode:JSON.parse};const{port:U}={port:49037};const z=new class{cliServerHandlers=new Map;listening=!1;isListening(){return this.listening}bootstrap(){this.listening=!0;const e=l.createServer(async(e,n)=>{const o=this.cliServerHandlers.get((e.url??"/").slice(1));if(o){try{const{promise:n,resolve:t,reject:i}=Promise.withResolvers();let r=Buffer.alloc(0);e.on("data",e=>r=Buffer.concat([r,e])),e.on("end",()=>{try{t(function(e,n=T){return n.decode(e)}(r))}catch(e){i(e)}}),await o(...await n)}catch(e){return console.error(e),n.writeHead(500),void n.end()}n.writeHead(200),n.end()}else n.writeHead(404),n.end()}).listen(U,()=>console.log(`Dev Server listening on port ${U}`));return e.on("error",e=>{throw this.listening=!1,function(e){return"object"==typeof e&&null!==e&&"EADDRINUSE"===e.code}(e)&&(console.error(`[sapdon] Dev Server 端口 ${U} 已被其他 sapdon 进程占用。`),console.error("[sapdon] 请先结束残留的 sapdon 进程,再重新构建,否则本次构建的数据可能被写入错误的包目录。"),process.exit(1)),e}),e}handle(e,n){this.cliServerHandlers.set(e,n)}getHandler(e){return this.cliServerHandlers.get(e)}interceptHandler(e,n){const o=n(this.getHandler(e)??Function.prototype);return this.cliServerHandlers.set(e,o),o}};async function V({level:e,message:n,timeStamp:o,stack:t}){console[e](n,t,`\nat ${new Date(o).toLocaleString()}`)}class G{static dataList=[];static getDataList(){return[...this.dataList]}static startServer(){z.handle("submitGregistry",e=>{this.dataList=e}),z.handle("remote-logger",V)}}const q=async(e,n,t)=>{try{o.join(n,`${t}_BP`);const r=o.join(n,`${t}_RP`),s=(...e)=>o.join(r,...e),c=G.getDataList(),a={item:null,block:null,flipbook:[]},l=[];for(const{name:r,root:s,path:u,data:p}of c){switch(console.log("处理数据:",r,s,u),r){case"item_texture":a.item=p,console.log("用户物品贴图数据:",a.item);continue;case"terrain_texture":a.block=p,console.log("用户方块贴图数据:",a.block);continue;case"flipbook_textures":a.flipbook=p,console.log("用户翻书贴图数据:",a.flipbook);continue}if(p._scriptSource){const n=o.dirname(e),t=o.join(n,u,`${r}.js`);i.existsSync(t)?console.log(`自定义组件脚本已存在,跳过: ${t}`):(O(t,p.source),console.log(`已生成自定义组件脚本: ${t}`)),l.push({safeName:r,componentId:p.componentId});continue}const c="behavior"===s?`${t}_BP`:`${t}_RP`,d=o.join(n,c),m=o.join(d,u,`${r}.json`);O(m,JSON.stringify(p,null,2))}if(l.length>0){const n=o.dirname(e),t=o.join(n,"scripts","custom_components"),r=o.join(t,"index.js");if(i.existsSync(r))console.log(`自定义组件注册索引已存在,跳过: ${r}`);else{const e=l.map(({safeName:e})=>`import { ${e} } from './${e}.js';`),n=l.map(({safeName:e,componentId:n})=>` init.blockComponentRegistry.registerCustomComponent('${n}', ${e});`),o=["// Auto-generated by sapdon.","import { system } from '@minecraft/server';","",...e,"","system.beforeEvents.startup.subscribe((init) => {",...n,"});",""].join("\n");O(r,o),console.log(`已生成自定义组件注册索引: ${r}`)}}await async function(e,n,o){const t=e("textures/items"),i=e("textures/item_texture.json");await async function(e,n,o,t){try{const i=await H(e,e,"textures/items/");t&&Object.assign(i,t);const r={resource_pack_name:o,texture_name:"atlas.items",texture_data:i};await L(n,r,"Item texture JSON file generated successfully.")}catch(e){console.error("Error generating item texture JSON:",e)}}(t,i,n,o.item);const r=e("textures/blocks"),s=e("textures/terrain_texture.json");await async function(e,n,o,t){try{const i=await H(e,e,"textures/blocks/");t&&Object.assign(i,t);const r={texture_name:"atlas.terrain",resource_pack_name:o,padding:8,num_mip_levels:4,texture_data:i};await L(n,r,"Block texture JSON file generated successfully.")}catch(e){console.error("Error generating block texture JSON:",e)}}(r,s,n,o.block);const c=e("textures/flipbook_textures.json");O(c,JSON.stringify(o.flipbook,null,2))}(s,t,a),console.log(`已加载并执行 ${e} 文件!`)}catch(n){console.error(`加载或执行 ${e} 失败:${n.message}`),console.error(n.stack)}};class K{name;description;version;uuid;allow_random_seed;lock_template_options;pack_scope;base_game_version;min_engine_version;constructor(e,n,o,t,i={}){this.name=e,this.description=n,this.version=o,this.uuid=t,this.allow_random_seed=i.allow_random_seed,this.lock_template_options=i.lock_template_options,this.pack_scope=i.pack_scope,this.base_game_version=i.base_game_version,this.min_engine_version=i.min_engine_version}}class Q{description;type;uuid;version;constructor(e,n,o,t){this.description=e,this.type=n,this.uuid=o,this.version=t}}class X{authors;license;generated_with;product_type;url;constructor(e,n,o,t,i){this.authors=e,this.license=n,this.generated_with=o,this.product_type=t,this.url=i}}class Y{format_version;header;modules;dependencies;capabilities;metadata;constructor(e,n,o,t,i=null,r=null){this.format_version=e,this.header=n,this.modules=o,this.dependencies=t,null!=i&&(this.capabilities=i),null!=r&&(this.metadata=r)}}const Z=process.env.MC_PATH,ee=process.env.MC_BETA_PATH,ne="AppData/Roaming/Minecraft Bedrock/Users/Shared/games/com.mojang",oe="AppData/Local/Packages/Microsoft.MinecraftWindowsBeta_8wekyb3d8bbwe/LocalState/games/com.mojang/";function te(){return"beta"===J().versionType?$("McInstallPath.Beta",()=>ee||o.join(h.homedir(),oe)):$("McInstallPath.Main",()=>Z||o.join(h.homedir(),ne))}var ie={name:"sapdon",version:"3.5.0",scripts:{build:"node scripts/build.cjs",test:'tsc && tsc-alias && node --test "tests/*.test.mjs"',"build:demo":"cd examples/block_demo && npm run build",pub:"npm run build && npm publish"},keywords:["bedrock","tools","addon"],author:"Meteage",license:"ISC",type:"module",bin:{sapdon:"prod/cli/start.js"},description:"Sapdon is a Node.js toolkit designed for building Bedrock Edition Minecraft addon packs.",devDependencies:{"@minecraft/server":"^2.0.0-beta.1.21.80-preview.20","@minecraft/server-ui":"^1.3.0","@types/archiver":"^6.0.0","@types/d3-array":"^3.2.1","@types/lodash":"^4.17.16","@types/node":"^22.14.0","tsc-alias":"^1.8.13"},dependencies:{"@rollup/plugin-commonjs":"^28.0.2","@rollup/plugin-json":"^6.1.0","@rollup/plugin-node-resolve":"^16.0.0","@rollup/plugin-terser":"^0.4.4","@rollup/plugin-typescript":"^12.1.2",chalk:"^5.4.1",commander:"^13.0.0","d3-array":"^3.2.4",archiver:"^7.0.0","download-git-repo":"^3.0.2",inquirer:"^12.3.1",lodash:"^4.17.21",ora:"^8.1.1",rollup:"^4.39.0","rollup-plugin-dts":"^6.2.1","rollup-plugin-typescript-paths":"^1.5.0","rollup-plugin-visualizer":"^5.14.0","tsconfig-paths":"^4.2.0",tslib:"^2.8.1",typescript:"^5.8.2"},files:["prod/**/*","doc/**/*"]};function re(){return $(o.join(x(import.meta),"../../../package.json"),()=>ie)}async function se(e,n){const t=J(),r=o.join(e,t.buildOptions.buildDir),s=o.join(r,`${n}_BP`),c=o.join(r,`${n}_RP`);i.cpSync(s,o.join(te(),"development_behavior_packs/",`${n}_BP/`),{recursive:!0,force:!0}),i.cpSync(c,o.join(te(),"development_resource_packs/",`${n}_RP/`),{recursive:!0,force:!0})}async function ce(e){const n=o.join(e,"node_modules"),t=o.join(x(import.meta),"../"),r=o.join(t,"core"),s=o.join(t,"cli"),c=o.join(t,"oc"),a=o.join(n,"@sapdon/core"),l=o.join(n,"@sapdon/cli"),u=o.join(n,"@sapdon/runtime"),p=re();i.cpSync(r,a,{recursive:!0,force:!0}),i.cpSync(s,l,{recursive:!0,force:!0}),i.cpSync(c,u,{recursive:!0,force:!0}),i.writeFileSync(o.join(a,"package.json"),JSON.stringify({name:"@sapdon/core",type:"module",main:"index.js",types:"index.d.ts",version:p.version})),i.writeFileSync(o.join(l,"package.json"),JSON.stringify({name:"@sapdon/cli",type:"module",main:"index.js",types:"index.d.ts",version:p.version})),i.writeFileSync(o.join(u,"package.json"),JSON.stringify({name:"@sapdon/runtime",type:"module",main:"index.js",types:"index.d.ts",version:p.version}))}const ae=t(import.meta.url);o.dirname(ae);const le=["rollup","typescript","@sapdon/core","@sapdon/cli","@minecraft"];function ue(e){const n=(e=>o.join(e,".sapdon_uuid.json"))(e);if(i.existsSync(n))return JSON.parse(i.readFileSync(n,"utf-8"));const t={bp:S(),rp:S()};return i.mkdirSync(o.dirname(n),{recursive:!0}),i.writeFileSync(n,JSON.stringify(t,null,2)),console.log("已生成持久化 UUID 用于 BP/RP 交叉绑定"),t}const pe={js:async(e,n,o)=>{const t=J();try{const i=await u({input:e,plugins:[d({preferBuiltins:!0}),p(),g(),..."prod"===t.buildOptions.buildMode?[y()]:[]],external(e){for(const n of le)if(e.includes(n))return!0;return!1}});await i.write({file:n,format:"esm",sourcemap:o}),i.close()}catch(e){console.error(e)}},ts:async(e,n,t)=>{const i=E(),r=J(),s={file:n,format:"esm",sourcemap:t};try{const n=await u({input:e,plugins:[f(),d({preferBuiltins:!0}),m({tsconfig:o.join(i,"tsconfig.json"),compilerOptions:{outDir:o.dirname(s.file)}}),p(),g(),..."prod"===r.buildOptions.buildMode?[y()]:[]],external(e){for(const n of le)if(e.includes(n))return!0;return!1}});await n.write(s),n.close()}catch(e){console.error(e)}},any:async(e,n)=>{J().buildOptions.useJs?await pe.js(e,n):await pe.ts(e,n)}};async function de(e){const n="."+crypto.randomUUID()+".js",t=o.join(o.dirname(e),".tmp",n);await pe.any(e,t);try{await async function(e){const{promise:n,resolve:o}=Promise.withResolvers();return c.fork(e,{stdio:"inherit"}).on("exit",o),n}(t)}catch(e){console.error(e)}finally{i.rmSync(t,{force:!0})}}function me(e){return console.log("开始构建项目"),console.log("项目路径:"+e),w(e)?(console.log("项目不存在"),!1):!w(o.join(e,"build.config"))||(console.log("项目没有build.config文件"),!1)}const fe=async(e,n)=>{const t=J(),r=o.join(e,"mod.info"),s=JSON.parse(_(r)),c=ge(s.min_engine_version),a=o.join(e,t.buildOptions.buildDir),l=o.join(a,`${n}_BP/`),u=o.join(a,`${n}_RP/`),p=o.join(e,t.buildOptions.buildEntry);if(!z.isListening()){const i=o.join(l,"manifest.json");if(w(i)){const e=ue(a),n=ge(s.version),i=ye(s.name,s.description,s.version,{min_engine_version:c},t.buildOptions.dependencies,t.buildOptions.scriptOutput,e.bp,e.rp,n),r=he(s.name,s.description,s.version,{min_engine_version:c},[],e.bp,e.rp,n);O(o.join(l,"manifest.json"),i),O(o.join(u,"manifest.json"),r)}const r=o.join(e,"pack_icon.png");v(r,o.join(l,"pack_icon.png")),v(r,o.join(u,"pack_icon.png"));const d=t.buildOptions.resource,m=o.join(e,d.path);k(m,u),z.isListening()||z.bootstrap(),G.startServer(),z.handle("submit",async e=>{"debug"!==t.buildOptions.buildMode&&(G.dataList=e,await q(p,a,n))})}await de(p),await async function(e=!1){const n=e?"js":"ts",t=E(),r=J(),{scriptEntry:s,scriptOutput:c,buildMode:a}=r.buildOptions,l=o.join(B(),c);i.mkdirSync(o.dirname(l),{recursive:!0}),await pe[n](o.join(t,s),l,"dev"===a)}(t.buildOptions.useJs),await se(e,n),J().buildOptions.keepServer||(console.log("[sapdon] 构建完成,开发服务器已自动退出。"),console.log('[sapdon] 如需保持服务器常开(HMR / 热更新),请在 build.config 中设置 "buildOptions.keepServer": true'),process.exit(0))};function ge(e){return e.split(".").map(e=>Number(e))}const ye=(e,n,o,t={},i=[],r,s,c,a)=>{console.log("开始生成behavior_packs/manifest.json"),console.log("Entry:",r);const l=new K(e+"_BP",n,a,s,t),u=new Q("行为模块","data",S(),a),p=new Q("脚本模块","script",S(),a);r&&(p.entry=r);const d=new X(["@sapdon"],"MIT",{sapdon:["1.0.0"]},"addon","https://github.com/junjun260/sapdon"),m=new Y(2,l,[u,p],[...i,{uuid:c,version:a}],null,d);return JSON.stringify(m,null,2)},he=(e,n,o,t={},i=[],r,s,c)=>{const a=new K(e+"_RP",n,c,s,t),l=new Q("资源模块","resources",S(),c),u=new X(["@sapdon"],"MIT",{sapdon:["1.0.0"]},"addon","https://github.com/junjun260/sapdon"),p=new Y(2,a,[l],[...i,{uuid:r,version:c}],null,u);return JSON.stringify(p,null,2)},je="import fs from 'fs'\nexport class FileResource {\n static cache: Record<string, FileResource> = {}\n static fileSystemLoader = (uri: string) => fs.readFileSync(uri)\n\n private _res: any\n\n /**\n * 不要调用构造器!\n * 使用 FileResource.get(uri) 方法获取实例\n * @param origin \n */\n constructor(public origin: string) {\n this.origin = origin\n FileResource.cache[origin] = this\n }\n\n /**\n * @param uri \n * @returns {FileResource}\n */\n static get(uri: string) {\n if (uri in FileResource.cache) {\n return FileResource.cache[uri]\n }\n return new FileResource(uri)\n }\n\n load(loader=FileResource.fileSystemLoader) {\n if (this._res) {\n return this._res\n }\n const content = loader(this.origin)\n this._res = content\n return content\n }\n\n clear() {\n delete FileResource.cache[this.origin]\n }\n\n loadWithoutCache(loader=FileResource.fileSystemLoader) {\n return loader(this.origin)\n }\n\n ptr() {\n const func = () => this.load()\n return Object.assign(func, this)\n }\n}",be=j.debounce;function Se(e,n,t){i.readdirSync(e).forEach(r=>{const s=o.join(e,r);i.statSync(s).isDirectory()?(t(r,e),Se(s,n,t)):n(r,e)})}var ve;function we(e){return e.replaceAll(".","_").replaceAll("-","_").replaceAll("@","$")}function _e(e){const n={type:ve.Dir,name:e,children:{}},t={[e]:n};let i=n;return Se(e,(e,n)=>{const t=o.basename(e),r=we(t.slice(0,t.lastIndexOf("."))),s={type:ve.File,name:r,origin:o.join(n,e)};i.children[r]=s},(e,n)=>{const r=we(e),s=t[n],c={type:ve.Dir,name:r,children:{}};s.children[r]=c,t[o.join(n,e)]=c,i=c}),n}function Oe(e){return!!i.existsSync(o.join(e,"build.config"))||(console.log("无法生成资源目录,请 cd 到项目根目录下执行 sapdon res"),!1)}function ke(){const{buildOptions:e}=J();if(e.buildEntry.endsWith("js"))return;const n=process.cwd(),t=o.join(n,"res");if(!Oe(n))return;i.existsSync(t)||i.mkdirSync(t);!function(e,n){const o={};!function e(n,o){for(const t in n.children){const i=n.children[t];if(i.type===ve.File)o[i.name]=`<fn>${i.origin}</fn>`;else{const n={};o[i.name]=n,e(i,n)}}}(e,o);const t=[je].join(";\n"),r=`\n;export default ${JSON.stringify(o,null,2)}`.replace(/"\<fn\>(.*)\<\/fn\>"/g,"FileResource.get('$1').ptr()");i.writeFileSync(n,t+r)}(_e(t),o.join(n,"res.hint.ts"))}!function(e){e[e.File=0]="File",e[e.Dir=1]="Dir"}(ve||(ve={}));const xe=j.debounce;function Ne(e,n){const{buildDir:t,useHMR:r}=J().buildOptions;!function(){const e=process.cwd();Oe(e)&&i.watch(o.join(e,"res"),{recursive:!0},be((e,n)=>{c.execSync("sapdon res")},3e3))}(),r&&i.watch(e,{recursive:!0},xe(async(i,r)=>{i&&r&&(r.startsWith(".")||r.startsWith("node_modules")||r.startsWith(o.join(t,"./"))||r.includes(".tmp")||(r.endsWith(".js")||r.endsWith(".ts")||"build.config"===r||"mod.info"===r)&&(process.stdout.write(`File ${r} changed, reloading...\r`),await fe(e,n),await se(e,n),console.log(`Reloaded ${r}`)))}),1e3)}const $e=t(import.meta.url),Je=o.dirname($e);process.removeAllListeners("warning"),e.command("init").description("初始化一个基于NodeJS的项目").action(()=>{const e=process.cwd(),t=o.join(e,"package.json");let r;if(i.existsSync(t)){try{r=JSON.parse(i.readFileSync(t,"utf-8"))}catch(e){return console.error("读取package.json文件时出错:",e),void console.log("请使改用create命令进行创建。")}r.scripts={...r.scripts,init:"sapdon init",compile:"sapdon compile",config:"sapdon config"};try{i.writeFileSync(t,JSON.stringify(r,null,2),"utf-8")}catch(e){return void console.error("写入package.json文件时出错:",e)}n.prompt([{type:"input",name:"min_engine_version",message:"最低引擎版本:",default:"1.19.50"}]).then(n=>{((e,n)=>{if(!(w(o.join(e,"mod.info"))&&w(o.join(e,"main.mjs"))&&w(o.join(e,"scripts"))&&w(o.join(e,"build.config"))))return void console.log("项目已存在...");const t=o.join(R,"../templates/js_sapdon");k(t,e),O(o.join(e,"mod.info"),JSON.stringify(n,null,2))})(e,{...D(e),...n}),console.log("请使用命令sapdon config配置框架的build.config文件。")})}else console.error("没有找到package.json文件,请使改用create命令进行创建。")}),e.command("create <project-name>").description("Create a new project").action(e=>{n.prompt([{type:"input",name:"name",message:"Project Name:",default:o.basename(e)},{type:"input",name:"description",message:"Project Description:",default:"A new sapdon project"},{type:"input",name:"author",message:"Author Name:",default:"Sapdon"},{type:"input",name:"version",message:"Project Version:",default:"1.0.0"},{type:"input",name:"min_engine_version",message:"Minimum Engine Version:",default:"1.19.50"},{type:"input",name:"language",message:"Language:(js/ts)",default:"ts"}]).then(n=>{const t=o.join(process.cwd(),e);console.log("项目路径:",t),((e,n)=>{if(console.log(1,n),!w(e))return void console.log("项目名称已存在,创建项目目录失败");const t=o.join(R,`../../src/templates/${P[n.language||"js"]}`);k(t,e),O(o.join(e,"mod.info"),JSON.stringify(n,null,2)),c.execSync("npm i",{cwd:e,stdio:"inherit"})})(t,n),ce(t)})}),e.command("build <project-name>").description("Build the project").action(e=>{console.log("Building the project...");const n=o.join(process.cwd(),e),t=o.basename(n);M.projectPath=n,ke(),me(n)&&(fe(n,t),Ne(n,t))}),e.command("compile").description("Compile the current project (build without HMR)").action(()=>{console.log("Compiling the current project...");const e=process.cwd();me(e)&&fe(e,o.basename(e))}),e.command("pack").description("Package build output into .mcaddon file").action(async()=>{const e=process.cwd(),n=o.basename(e);M.projectPath=e,await(async e=>{const n=E(),t=J(),r=o.join(n,t.buildOptions.buildDir),s=o.join(r,`${e}_BP`),c=o.join(r,`${e}_RP`);if(!i.existsSync(s)||!i.existsSync(c))return void console.error("构建输出目录不存在,请先运行 sapdon compile");const a=o.join(r,`${e}.mcaddon`),l=i.createWriteStream(a),u=b("zip",{zlib:{level:9}});l.on("close",()=>{console.log(`打包完成: ${a} (${u.pointer()} bytes)`)}),u.on("error",e=>{throw e}),u.pipe(l),u.directory(s,`${e}_BP`),u.directory(c,`${e}_RP`),await u.finalize()})(n)}),e.command("lib").description("Generate lib files for development server.").action(()=>{ce(process.cwd())}),e.command("res").description("Generate resource hints.").action(()=>{ke()}),e.command("config").description("Configure build.config file").action(()=>{const e=o.join(Je,"./build.config");let n;try{n=JSON.parse(_(e))}catch(e){return void console.error("读取build.config文件时出错:",e)}}),e.parse(e.argv);
|
|
2
|
+
import{program as e}from"commander";import n from"inquirer";import o from"path";import{fileURLToPath as t}from"url";import i from"fs";import{randomUUID as r}from"crypto";import{fileURLToPath as s}from"node:url";import c from"child_process";import a from"fs/promises";import l from"http";import{rollup as u}from"rollup";import p from"@rollup/plugin-commonjs";import{nodeResolve as d}from"@rollup/plugin-node-resolve";import m from"@rollup/plugin-typescript";import{typescriptPaths as f}from"rollup-plugin-typescript-paths";import g from"@rollup/plugin-json";import"rollup-plugin-visualizer";import y from"@rollup/plugin-terser";import h from"os";import j from"lodash";import b from"archiver";const S=()=>r();function v(e,n){try{i.copyFileSync(e,n)}catch(e){console.error("文件复制失败:",e)}}const w=e=>!i.existsSync(e),_=e=>{try{return i.readFileSync(e,"utf8")}catch(e){console.log(e)}return null},O=(e,n)=>{i.mkdirSync(o.dirname(e),{recursive:!0}),i.writeFileSync(e,n)},k=(e,n)=>{if(i.mkdirSync(o.dirname(n),{recursive:!0}),!i.existsSync(e))return void console.log(`Source path ${e} does not exist.`);i.existsSync(n)||i.mkdirSync(n);i.readdirSync(e).forEach(t=>{const r=o.join(e,t),s=o.join(n,t);i.lstatSync(r).isDirectory()?k(r,s):i.copyFileSync(r,s)})};function x(e){const n=s(e.url);return o.dirname(n)}const N=new Map;function $(e,n){let o=N.get(e);return o||(o=n(e),N.set(e,o),o)}function J(){const e=E(),n=o.join(e,"build.config");if(!i.existsSync(n))throw new Error("未找到项目配置文件,请先初始化项目");return $(n,e=>function(e){const n=(o=i.readFileSync(e),JSON.parse(String(o).replace(/\/\/.*|\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/g,"$1")));var o;if(2===n.formatVersion)return n;const t=function({defaultConfig:e,resources:n,scripts:o}){const t={formatVersion:2,buildOptions:{useHMR:!0,buildMode:"dev",buildEntry:e.buildEntry,scriptEntry:e.scriptEntry,scriptOutput:e.scriptEntry.replace(".ts",".js"),useJs:"ts"!==o[0].type,buildDir:e.buildDir,dependencies:e.dependencies,resource:{path:n[0].path,resourceHints:!0}},versionType:"release"};return t}(n);return i.writeFileSync(e,JSON.stringify(t,null,2)),t}(e))}const F=t(import.meta.url),R=o.dirname(F),P={js:"js_sapdon",ts:"ts_sapdon"},D=e=>{const n=o.join(e,"package.json");if(!i.existsSync(n))return null;try{const t=JSON.parse(i.readFileSync(n,"utf-8"));return{name:o.basename(e),description:t.description||"A new sapdon project",author:t.author||"Sapdon",version:t.version||"1.0.0"}}catch(e){return console.error("读取package.json文件时出错:",e),null}},M={};function E(){const e=M.projectPath??process.cwd();if(!i.existsSync(o.join(e,"build.config")))throw new Error("无效的项目路径");return e}function B(){const{buildDir:e}=J().buildOptions,n=$("projectName",()=>o.basename(E()));return o.join(E(),e,n+"_bp")}const H=async(e,n,t="")=>{const i={};try{await a.access(e)}catch{return i}const r=await a.readdir(e);for(const s of r){const r=o.join(e,s);if((await a.stat(r)).isDirectory()){const e=await H(r,n,t);Object.assign(i,e)}else if(s.endsWith(".png")){const e=o.basename(s,".png"),c=`${t}${o.relative(n,r).replace(/\.png$/,"").replace(/\\/g,"/")}`;i[e]={textures:c}}}return i},L=async(e,n,o)=>{try{const t=JSON.stringify(n,null,2);await a.writeFile(e,t),console.log(o)}catch(e){console.error("Error writing JSON file:",e)}};Symbol.metadata||(Symbol.metadata=Symbol("[[metadata]]"));const A=Symbol("isRawJSON");const I=["boolean","number"],C=["string","undefined"];function W(e,n){const o=typeof n;if(null===o)return null;if(C.includes(o))return n;if(I.includes(o))return JSON.rawJSON(n);if("object"===o)return JSON.isRawJSON(n)?n:function(e){return!0===e?.[A]}(n)?JSON.rawJSON(n.rawJSON):n;if("bigint"===o)return JSON.rawJSON(n.toString());throw new Error("Unexpected value")}const T={encode:e=>JSON.stringify(e,W),decode:JSON.parse};const{port:U}={port:49037};const z=new class{cliServerHandlers=new Map;listening=!1;isListening(){return this.listening}bootstrap(){this.listening=!0;const e=l.createServer(async(e,n)=>{const o=this.cliServerHandlers.get((e.url??"/").slice(1));if(o){try{const{promise:n,resolve:t,reject:i}=Promise.withResolvers();let r=Buffer.alloc(0);e.on("data",e=>r=Buffer.concat([r,e])),e.on("end",()=>{try{t(function(e,n=T){return n.decode(e)}(r))}catch(e){i(e)}}),await o(...await n)}catch(e){return console.error(e),n.writeHead(500),void n.end()}n.writeHead(200),n.end()}else n.writeHead(404),n.end()}).listen(U,()=>console.log(`Dev Server listening on port ${U}`));return e.on("error",e=>{throw this.listening=!1,function(e){return"object"==typeof e&&null!==e&&"EADDRINUSE"===e.code}(e)&&(console.error(`[sapdon] Dev Server 端口 ${U} 已被其他 sapdon 进程占用。`),console.error("[sapdon] 请先结束残留的 sapdon 进程,再重新构建,否则本次构建的数据可能被写入错误的包目录。"),process.exit(1)),e}),e}handle(e,n){this.cliServerHandlers.set(e,n)}getHandler(e){return this.cliServerHandlers.get(e)}interceptHandler(e,n){const o=n(this.getHandler(e)??Function.prototype);return this.cliServerHandlers.set(e,o),o}};async function V({level:e,message:n,timeStamp:o,stack:t}){console[e](n,t,`\nat ${new Date(o).toLocaleString()}`)}class G{static dataList=[];static getDataList(){return[...this.dataList]}static startServer(){z.handle("submitGregistry",e=>{this.dataList=e}),z.handle("remote-logger",V)}}const q=async(e,n,t)=>{try{o.join(n,`${t}_BP`);const r=o.join(n,`${t}_RP`),s=(...e)=>o.join(r,...e),c=G.getDataList(),a={item:null,block:null,flipbook:[]},l=[];for(const{name:r,root:s,path:u,data:p}of c){switch(console.log("处理数据:",r,s,u),r){case"item_texture":a.item=p,console.log("用户物品贴图数据:",a.item);continue;case"terrain_texture":a.block=p,console.log("用户方块贴图数据:",a.block);continue;case"flipbook_textures":a.flipbook=p,console.log("用户翻书贴图数据:",a.flipbook);continue}if(p._scriptSource){const n=o.dirname(e),t=o.join(n,u,`${r}.js`);i.existsSync(t)?console.log(`自定义组件脚本已存在,跳过: ${t}`):(O(t,p.source),console.log(`已生成自定义组件脚本: ${t}`)),l.push({safeName:r,componentId:p.componentId});continue}const c="behavior"===s?`${t}_BP`:`${t}_RP`,d=o.join(n,c),m=o.join(d,u,`${r}.json`);O(m,JSON.stringify(p,null,2))}if(l.length>0){const n=o.dirname(e),t=o.join(n,"scripts","custom_components"),r=o.join(t,"index.js");if(i.existsSync(r))console.log(`自定义组件注册索引已存在,跳过: ${r}`);else{const e=l.map(({safeName:e})=>`import { ${e} } from './${e}.js';`),n=l.map(({safeName:e,componentId:n})=>` init.blockComponentRegistry.registerCustomComponent('${n}', ${e});`),o=["// Auto-generated by sapdon.","import { system } from '@minecraft/server';","",...e,"","system.beforeEvents.startup.subscribe((init) => {",...n,"});",""].join("\n");O(r,o),console.log(`已生成自定义组件注册索引: ${r}`)}}await async function(e,n,o){const t=e("textures/items"),i=e("textures/item_texture.json");await async function(e,n,o,t){try{const i=await H(e,e,"textures/items/");t&&Object.assign(i,t);const r={resource_pack_name:o,texture_name:"atlas.items",texture_data:i};await L(n,r,"Item texture JSON file generated successfully.")}catch(e){console.error("Error generating item texture JSON:",e)}}(t,i,n,o.item);const r=e("textures/blocks"),s=e("textures/terrain_texture.json");await async function(e,n,o,t){try{const i=await H(e,e,"textures/blocks/");t&&Object.assign(i,t);const r={texture_name:"atlas.terrain",resource_pack_name:o,padding:8,num_mip_levels:4,texture_data:i};await L(n,r,"Block texture JSON file generated successfully.")}catch(e){console.error("Error generating block texture JSON:",e)}}(r,s,n,o.block);const c=e("textures/flipbook_textures.json");O(c,JSON.stringify(o.flipbook,null,2))}(s,t,a),console.log(`已加载并执行 ${e} 文件!`)}catch(n){console.error(`加载或执行 ${e} 失败:${n.message}`),console.error(n.stack)}};class K{name;description;version;uuid;allow_random_seed;lock_template_options;pack_scope;base_game_version;min_engine_version;constructor(e,n,o,t,i={}){this.name=e,this.description=n,this.version=o,this.uuid=t,this.allow_random_seed=i.allow_random_seed,this.lock_template_options=i.lock_template_options,this.pack_scope=i.pack_scope,this.base_game_version=i.base_game_version,this.min_engine_version=i.min_engine_version}}class Q{description;type;uuid;version;constructor(e,n,o,t){this.description=e,this.type=n,this.uuid=o,this.version=t}}class X{authors;license;generated_with;product_type;url;constructor(e,n,o,t,i){this.authors=e,this.license=n,this.generated_with=o,this.product_type=t,this.url=i}}class Y{format_version;header;modules;dependencies;capabilities;metadata;constructor(e,n,o,t,i=null,r=null){this.format_version=e,this.header=n,this.modules=o,this.dependencies=t,null!=i&&(this.capabilities=i),null!=r&&(this.metadata=r)}}const Z=process.env.MC_PATH,ee=process.env.MC_BETA_PATH,ne="AppData/Roaming/Minecraft Bedrock/Users/Shared/games/com.mojang",oe="AppData/Local/Packages/Microsoft.MinecraftWindowsBeta_8wekyb3d8bbwe/LocalState/games/com.mojang/";function te(){return"beta"===J().versionType?$("McInstallPath.Beta",()=>ee||o.join(h.homedir(),oe)):$("McInstallPath.Main",()=>Z||o.join(h.homedir(),ne))}var ie={name:"sapdon",version:"3.5.2",scripts:{build:"node scripts/build.cjs",test:'tsc && tsc-alias && node --test "tests/*.test.mjs"',"build:demo":"cd examples/block_demo && npm run build",pub:"npm run build && npm publish"},keywords:["bedrock","tools","addon"],author:"Meteage",license:"ISC",type:"module",bin:{sapdon:"prod/cli/start.js"},description:"Sapdon is a Node.js toolkit designed for building Bedrock Edition Minecraft addon packs.",devDependencies:{"@minecraft/server":"^2.0.0-beta.1.21.80-preview.20","@minecraft/server-ui":"^1.3.0","@types/archiver":"^6.0.0","@types/d3-array":"^3.2.1","@types/lodash":"^4.17.16","@types/node":"^22.14.0","tsc-alias":"^1.8.13"},dependencies:{"@rollup/plugin-commonjs":"^28.0.2","@rollup/plugin-json":"^6.1.0","@rollup/plugin-node-resolve":"^16.0.0","@rollup/plugin-terser":"^0.4.4","@rollup/plugin-typescript":"^12.1.2",chalk:"^5.4.1",commander:"^13.0.0","d3-array":"^3.2.4",archiver:"^7.0.0","download-git-repo":"^3.0.2",inquirer:"^12.3.1",lodash:"^4.17.21",ora:"^8.1.1",rollup:"^4.39.0","rollup-plugin-dts":"^6.2.1","rollup-plugin-typescript-paths":"^1.5.0","rollup-plugin-visualizer":"^5.14.0","tsconfig-paths":"^4.2.0",tslib:"^2.8.1",typescript:"^5.8.2"},files:["prod/**/*","doc/**/*"]};function re(){return $(o.join(x(import.meta),"../../../package.json"),()=>ie)}async function se(e,n){const t=J(),r=o.join(e,t.buildOptions.buildDir),s=o.join(r,`${n}_BP`),c=o.join(r,`${n}_RP`);i.cpSync(s,o.join(te(),"development_behavior_packs/",`${n}_BP/`),{recursive:!0,force:!0}),i.cpSync(c,o.join(te(),"development_resource_packs/",`${n}_RP/`),{recursive:!0,force:!0})}async function ce(e){const n=o.join(e,"node_modules"),t=o.join(x(import.meta),"../"),r=o.join(t,"core"),s=o.join(t,"cli"),c=o.join(t,"oc"),a=o.join(n,"@sapdon/core"),l=o.join(n,"@sapdon/cli"),u=o.join(n,"@sapdon/runtime"),p=re();i.cpSync(r,a,{recursive:!0,force:!0}),i.cpSync(s,l,{recursive:!0,force:!0}),i.cpSync(c,u,{recursive:!0,force:!0}),i.writeFileSync(o.join(a,"package.json"),JSON.stringify({name:"@sapdon/core",type:"module",main:"index.js",types:"index.d.ts",version:p.version})),i.writeFileSync(o.join(l,"package.json"),JSON.stringify({name:"@sapdon/cli",type:"module",main:"index.js",types:"index.d.ts",version:p.version})),i.writeFileSync(o.join(u,"package.json"),JSON.stringify({name:"@sapdon/runtime",type:"module",main:"index.js",types:"index.d.ts",version:p.version}))}const ae=t(import.meta.url);o.dirname(ae);const le=["rollup","typescript","@sapdon/core","@sapdon/cli","@minecraft"];function ue(e){const n=(e=>o.join(e,".sapdon_uuid.json"))(e);if(i.existsSync(n))return JSON.parse(i.readFileSync(n,"utf-8"));const t={bp:S(),rp:S()};return i.mkdirSync(o.dirname(n),{recursive:!0}),i.writeFileSync(n,JSON.stringify(t,null,2)),console.log("已生成持久化 UUID 用于 BP/RP 交叉绑定"),t}const pe={js:async(e,n,o)=>{const t=J();try{const i=await u({input:e,plugins:[d({preferBuiltins:!0}),p(),g(),..."prod"===t.buildOptions.buildMode?[y()]:[]],external(e){for(const n of le)if(e.includes(n))return!0;return!1}});await i.write({file:n,format:"esm",sourcemap:o}),i.close()}catch(e){console.error(e)}},ts:async(e,n,t)=>{const i=E(),r=J(),s={file:n,format:"esm",sourcemap:t};try{const n=await u({input:e,plugins:[f(),d({preferBuiltins:!0}),m({tsconfig:o.join(i,"tsconfig.json"),compilerOptions:{outDir:o.dirname(s.file)}}),p(),g(),..."prod"===r.buildOptions.buildMode?[y()]:[]],external(e){for(const n of le)if(e.includes(n))return!0;return!1}});await n.write(s),n.close()}catch(e){console.error(e)}},any:async(e,n)=>{J().buildOptions.useJs?await pe.js(e,n):await pe.ts(e,n)}};async function de(e){const n="."+crypto.randomUUID()+".js",t=o.join(o.dirname(e),".tmp",n);await pe.any(e,t);try{await async function(e){const{promise:n,resolve:o}=Promise.withResolvers();return c.fork(e,{stdio:"inherit"}).on("exit",o),n}(t)}catch(e){console.error(e)}finally{i.rmSync(t,{force:!0})}}function me(e){return console.log("开始构建项目"),console.log("项目路径:"+e),w(e)?(console.log("项目不存在"),!1):!w(o.join(e,"build.config"))||(console.log("项目没有build.config文件"),!1)}const fe=async(e,n)=>{const t=J(),r=o.join(e,"mod.info"),s=JSON.parse(_(r)),c=ge(s.min_engine_version),a=o.join(e,t.buildOptions.buildDir),l=o.join(a,`${n}_BP/`),u=o.join(a,`${n}_RP/`),p=o.join(e,t.buildOptions.buildEntry);if(!z.isListening()){const i=o.join(l,"manifest.json");if(w(i)){const e=ue(a),n=ge(s.version),i=ye(s.name,s.description,s.version,{min_engine_version:c},t.buildOptions.dependencies,t.buildOptions.scriptOutput,e.bp,e.rp,n),r=he(s.name,s.description,s.version,{min_engine_version:c},[],e.bp,e.rp,n);O(o.join(l,"manifest.json"),i),O(o.join(u,"manifest.json"),r)}const r=o.join(e,"pack_icon.png");v(r,o.join(l,"pack_icon.png")),v(r,o.join(u,"pack_icon.png"));const d=t.buildOptions.resource,m=o.join(e,d.path);k(m,u),z.isListening()||z.bootstrap(),G.startServer(),z.handle("submit",async e=>{"debug"!==t.buildOptions.buildMode&&(G.dataList=e,await q(p,a,n))})}await de(p),await async function(e=!1){const n=e?"js":"ts",t=E(),r=J(),{scriptEntry:s,scriptOutput:c,buildMode:a}=r.buildOptions,l=o.join(B(),c);i.mkdirSync(o.dirname(l),{recursive:!0}),await pe[n](o.join(t,s),l,"dev"===a)}(t.buildOptions.useJs),await se(e,n),J().buildOptions.keepServer||(console.log("[sapdon] 构建完成,开发服务器已自动退出。"),console.log('[sapdon] 如需保持服务器常开(HMR / 热更新),请在 build.config 中设置 "buildOptions.keepServer": true'),process.exit(0))};function ge(e){return e.split(".").map(e=>Number(e))}const ye=(e,n,o,t={},i=[],r,s,c,a)=>{console.log("开始生成behavior_packs/manifest.json"),console.log("Entry:",r);const l=new K(e+"_BP",n,a,s,t),u=new Q("行为模块","data",S(),a),p=new Q("脚本模块","script",S(),a);r&&(p.entry=r);const d=new X(["@sapdon"],"MIT",{sapdon:["1.0.0"]},"addon","https://github.com/junjun260/sapdon"),m=new Y(2,l,[u,p],[...i,{uuid:c,version:a}],null,d);return JSON.stringify(m,null,2)},he=(e,n,o,t={},i=[],r,s,c)=>{const a=new K(e+"_RP",n,c,s,t),l=new Q("资源模块","resources",S(),c),u=new X(["@sapdon"],"MIT",{sapdon:["1.0.0"]},"addon","https://github.com/junjun260/sapdon"),p=new Y(2,a,[l],[...i,{uuid:r,version:c}],null,u);return JSON.stringify(p,null,2)},je="import fs from 'fs'\nexport class FileResource {\n static cache: Record<string, FileResource> = {}\n static fileSystemLoader = (uri: string) => fs.readFileSync(uri)\n\n private _res: any\n\n /**\n * 不要调用构造器!\n * 使用 FileResource.get(uri) 方法获取实例\n * @param origin \n */\n constructor(public origin: string) {\n this.origin = origin\n FileResource.cache[origin] = this\n }\n\n /**\n * @param uri \n * @returns {FileResource}\n */\n static get(uri: string) {\n if (uri in FileResource.cache) {\n return FileResource.cache[uri]\n }\n return new FileResource(uri)\n }\n\n load(loader=FileResource.fileSystemLoader) {\n if (this._res) {\n return this._res\n }\n const content = loader(this.origin)\n this._res = content\n return content\n }\n\n clear() {\n delete FileResource.cache[this.origin]\n }\n\n loadWithoutCache(loader=FileResource.fileSystemLoader) {\n return loader(this.origin)\n }\n\n ptr() {\n const func = () => this.load()\n return Object.assign(func, this)\n }\n}",be=j.debounce;function Se(e,n,t){i.readdirSync(e).forEach(r=>{const s=o.join(e,r);i.statSync(s).isDirectory()?(t(r,e),Se(s,n,t)):n(r,e)})}var ve;function we(e){return e.replaceAll(".","_").replaceAll("-","_").replaceAll("@","$")}function _e(e){const n={type:ve.Dir,name:e,children:{}},t={[e]:n};let i=n;return Se(e,(e,n)=>{const t=o.basename(e),r=we(t.slice(0,t.lastIndexOf("."))),s={type:ve.File,name:r,origin:o.join(n,e)};i.children[r]=s},(e,n)=>{const r=we(e),s=t[n],c={type:ve.Dir,name:r,children:{}};s.children[r]=c,t[o.join(n,e)]=c,i=c}),n}function Oe(e){return!!i.existsSync(o.join(e,"build.config"))||(console.log("无法生成资源目录,请 cd 到项目根目录下执行 sapdon res"),!1)}function ke(){const{buildOptions:e}=J();if(e.buildEntry.endsWith("js"))return;const n=process.cwd(),t=o.join(n,"res");if(!Oe(n))return;i.existsSync(t)||i.mkdirSync(t);!function(e,n){const o={};!function e(n,o){for(const t in n.children){const i=n.children[t];if(i.type===ve.File)o[i.name]=`<fn>${i.origin}</fn>`;else{const n={};o[i.name]=n,e(i,n)}}}(e,o);const t=[je].join(";\n"),r=`\n;export default ${JSON.stringify(o,null,2)}`.replace(/"\<fn\>(.*)\<\/fn\>"/g,"FileResource.get('$1').ptr()");i.writeFileSync(n,t+r)}(_e(t),o.join(n,"res.hint.ts"))}!function(e){e[e.File=0]="File",e[e.Dir=1]="Dir"}(ve||(ve={}));const xe=j.debounce;function Ne(e,n){const{buildDir:t,useHMR:r}=J().buildOptions;!function(){const e=process.cwd();Oe(e)&&i.watch(o.join(e,"res"),{recursive:!0},be((e,n)=>{c.execSync("sapdon res")},3e3))}(),r&&i.watch(e,{recursive:!0},xe(async(i,r)=>{i&&r&&(r.startsWith(".")||r.startsWith("node_modules")||r.startsWith(o.join(t,"./"))||r.includes(".tmp")||(r.endsWith(".js")||r.endsWith(".ts")||"build.config"===r||"mod.info"===r)&&(process.stdout.write(`File ${r} changed, reloading...\r`),await fe(e,n),await se(e,n),console.log(`Reloaded ${r}`)))}),1e3)}const $e=t(import.meta.url),Je=o.dirname($e);process.removeAllListeners("warning"),e.command("init").description("初始化一个基于NodeJS的项目").action(()=>{const e=process.cwd(),t=o.join(e,"package.json");let r;if(i.existsSync(t)){try{r=JSON.parse(i.readFileSync(t,"utf-8"))}catch(e){return console.error("读取package.json文件时出错:",e),void console.log("请使改用create命令进行创建。")}r.scripts={...r.scripts,init:"sapdon init",compile:"sapdon compile",config:"sapdon config"};try{i.writeFileSync(t,JSON.stringify(r,null,2),"utf-8")}catch(e){return void console.error("写入package.json文件时出错:",e)}n.prompt([{type:"input",name:"min_engine_version",message:"最低引擎版本:",default:"1.19.50"}]).then(n=>{((e,n)=>{if(!(w(o.join(e,"mod.info"))&&w(o.join(e,"main.mjs"))&&w(o.join(e,"scripts"))&&w(o.join(e,"build.config"))))return void console.log("项目已存在...");const t=o.join(R,"../templates/js_sapdon");k(t,e),O(o.join(e,"mod.info"),JSON.stringify(n,null,2))})(e,{...D(e),...n}),console.log("请使用命令sapdon config配置框架的build.config文件。")})}else console.error("没有找到package.json文件,请使改用create命令进行创建。")}),e.command("create <project-name>").description("Create a new project").action(e=>{n.prompt([{type:"input",name:"name",message:"Project Name:",default:o.basename(e)},{type:"input",name:"description",message:"Project Description:",default:"A new sapdon project"},{type:"input",name:"author",message:"Author Name:",default:"Sapdon"},{type:"input",name:"version",message:"Project Version:",default:"1.0.0"},{type:"input",name:"min_engine_version",message:"Minimum Engine Version:",default:"1.19.50"},{type:"input",name:"language",message:"Language:(js/ts)",default:"ts"}]).then(n=>{const t=o.join(process.cwd(),e);console.log("项目路径:",t),((e,n)=>{if(console.log(1,n),!w(e))return void console.log("项目名称已存在,创建项目目录失败");const t=o.join(R,`../templates/${P[n.language||"js"]}`);k(t,e),O(o.join(e,"mod.info"),JSON.stringify(n,null,2)),c.execSync("npm i",{cwd:e,stdio:"inherit"})})(t,n),ce(t)})}),e.command("build <project-name>").description("Build the project").action(e=>{console.log("Building the project...");const n=o.join(process.cwd(),e),t=o.basename(n);M.projectPath=n,ke(),me(n)&&(fe(n,t),Ne(n,t))}),e.command("compile").description("Compile the current project (build without HMR)").action(()=>{console.log("Compiling the current project...");const e=process.cwd();me(e)&&fe(e,o.basename(e))}),e.command("pack").description("Package build output into .mcaddon file").action(async()=>{const e=process.cwd(),n=o.basename(e);M.projectPath=e,await(async e=>{const n=E(),t=J(),r=o.join(n,t.buildOptions.buildDir),s=o.join(r,`${e}_BP`),c=o.join(r,`${e}_RP`);if(!i.existsSync(s)||!i.existsSync(c))return void console.error("构建输出目录不存在,请先运行 sapdon compile");const a=o.join(r,`${e}.mcaddon`),l=i.createWriteStream(a),u=b("zip",{zlib:{level:9}});l.on("close",()=>{console.log(`打包完成: ${a} (${u.pointer()} bytes)`)}),u.on("error",e=>{throw e}),u.pipe(l),u.directory(s,`${e}_BP`),u.directory(c,`${e}_RP`),await u.finalize()})(n)}),e.command("lib").description("Generate lib files for development server.").action(()=>{ce(process.cwd())}),e.command("res").description("Generate resource hints.").action(()=>{ke()}),e.command("config").description("Configure build.config file").action(()=>{const e=o.join(Je,"./build.config");let n;try{n=JSON.parse(_(e))}catch(e){return void console.error("读取build.config文件时出错:",e)}}),e.parse(e.argv);
|
package/prod/core/index.d.ts
CHANGED
|
@@ -1941,7 +1941,7 @@ declare class EntityComponent {
|
|
|
1941
1941
|
static setInventoryProperties(options: {
|
|
1942
1942
|
additionalSlotsPerStrength?: number | undefined;
|
|
1943
1943
|
canBeSiphonedFrom?: boolean | undefined;
|
|
1944
|
-
containerType?: "
|
|
1944
|
+
containerType?: "horse" | "chest_boat" | "minecart_chest" | undefined;
|
|
1945
1945
|
inventorySize?: number | undefined;
|
|
1946
1946
|
isPrivate?: boolean | undefined;
|
|
1947
1947
|
restrictToOwner?: boolean | undefined;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"formatVersion": 2,
|
|
3
|
+
"buildOptions": {
|
|
4
|
+
"useHMR": true, // 热更新
|
|
5
|
+
"keepServer": false, // 构建完成后是否保持服务器常开. true=常开(配合useHMR), false=默认自动退出
|
|
6
|
+
"buildMode": "dev", // 开发模式 'dev' | 'prod' | 'debug'. prod=压缩代码, debug=仅同步dev/
|
|
7
|
+
"buildEntry": "main.mjs", // Addon构建入口文件
|
|
8
|
+
"useJs": true, // 是否使用js文件
|
|
9
|
+
"scriptEntry": "scripts/index.js", // ScriptApi脚本入口文件
|
|
10
|
+
"scriptOutput": "scripts/index.js", // ScriptApi脚本输出文件 (在 buildDir 目录下)
|
|
11
|
+
"buildDir": "dev/", // 构建输出目录
|
|
12
|
+
"dependencies": [
|
|
13
|
+
{
|
|
14
|
+
"module_name": "@minecraft/server",
|
|
15
|
+
"version": "1.17.0"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"resource": {
|
|
19
|
+
"path": "res/", // 资源文件目录
|
|
20
|
+
"resourceHints": true // 是否生成资源提示文件
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"versionType": "release" // mc游戏版本, 会影响开发文件路径
|
|
24
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sapdon",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "main.mjs",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "sapdon build ./",
|
|
7
|
+
"postinstall": "sapdon lib"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"bedrock",
|
|
11
|
+
"addon"
|
|
12
|
+
],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"sapdon": "^3.5.2",
|
|
18
|
+
"@minecraft/server": "^1.17.0",
|
|
19
|
+
"@minecraft/server-ui": "^1.3.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format_version": "1.8.0",
|
|
3
|
+
"animations": {
|
|
4
|
+
"animation.animation_item.default": {
|
|
5
|
+
"loop": true,
|
|
6
|
+
"bones": {
|
|
7
|
+
"body": {
|
|
8
|
+
"position": [0, 8, 0]
|
|
9
|
+
},
|
|
10
|
+
"rightitem": {
|
|
11
|
+
"rotation": [-80, 0, 0],
|
|
12
|
+
"position": [0, -3, 2]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"animation.animation_item.rotating": {
|
|
17
|
+
"loop": true,
|
|
18
|
+
"animation_length": 10,
|
|
19
|
+
"bones": {
|
|
20
|
+
"body": {
|
|
21
|
+
"rotation": {
|
|
22
|
+
"0.0": [0, 0, 0],
|
|
23
|
+
"10.0": [0, 360, 0]
|
|
24
|
+
},
|
|
25
|
+
"position": [0, 8, 0]
|
|
26
|
+
},
|
|
27
|
+
"rightitem": {
|
|
28
|
+
"rotation": [-80, 0, 0],
|
|
29
|
+
"position": [0, -3, 2]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format_version": "1.10.0",
|
|
3
|
+
"animations": {
|
|
4
|
+
"animation.large_item.hold": {
|
|
5
|
+
"loop": true,
|
|
6
|
+
"bones": {
|
|
7
|
+
"rightitem": {
|
|
8
|
+
"position": [
|
|
9
|
+
"c.is_first_person ? -6 : 1",
|
|
10
|
+
"c.is_first_person ? 0 : -1",
|
|
11
|
+
"c.is_first_person ? -1 : -6"
|
|
12
|
+
],
|
|
13
|
+
"rotation": [
|
|
14
|
+
"c.is_first_person ? 45 : 15",
|
|
15
|
+
"c.is_first_person ? -15 : 0",
|
|
16
|
+
"c.is_first_person ? 30 : -165"
|
|
17
|
+
],
|
|
18
|
+
"scale": [
|
|
19
|
+
"c.is_first_person ? 1 : 0.5",
|
|
20
|
+
"c.is_first_person ? 1 : 0.5",
|
|
21
|
+
"c.is_first_person ? 1 : 0.5"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format_version": "1.21.20",
|
|
3
|
+
"minecraft:geometry": [
|
|
4
|
+
{
|
|
5
|
+
"description": {
|
|
6
|
+
"identifier": "geometry.crop",
|
|
7
|
+
"texture_width": 16,
|
|
8
|
+
"texture_height": 16
|
|
9
|
+
},
|
|
10
|
+
"bones": [
|
|
11
|
+
{
|
|
12
|
+
"name": "crop",
|
|
13
|
+
"pivot": [0, 0, 0],
|
|
14
|
+
"cubes": [
|
|
15
|
+
{
|
|
16
|
+
"origin": [-8, -1, -4],
|
|
17
|
+
"size": [16, 16, 0],
|
|
18
|
+
"uv": {
|
|
19
|
+
"south": { "uv": [0, 0], "uv_size": [16, 16] }
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"origin": [-8, -1, 4],
|
|
24
|
+
"size": [16, 16, 0],
|
|
25
|
+
"uv": {
|
|
26
|
+
"north": { "uv": [0, 0], "uv_size": [16, 16] }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"origin": [4, -1, -8],
|
|
31
|
+
"size": [0, 16, 16],
|
|
32
|
+
"uv": {
|
|
33
|
+
"east": { "uv": [16, 0], "uv_size": [-16, 16] }
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"origin": [-4, -1, -8],
|
|
38
|
+
"size": [0, 16, 16],
|
|
39
|
+
"uv": {
|
|
40
|
+
"west": { "uv": [16, 0], "uv_size": [-16, 16] }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|