sapdon 3.5.0 → 3.5.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/doc/dev/core.md +2 -2
- package/doc/dev/ui-architecture.md +3 -3
- package/doc/guidebook.md +9 -1
- package/doc/user/quick-start.md +1 -2
- package/package.json +1 -1
- package/prod/cli/start.js +1 -1
- package/prod/core/index.d.ts +14 -159
- package/prod/core/index.js +1 -1
- package/doc/user/api/neo-guidebook.md +0 -409
- package/doc/user/tutorials/neo-guidebook-experience.md +0 -381
- package/doc/user/tutorials/neo-guidebook.md +0 -640
package/doc/dev/core.md
CHANGED
|
@@ -132,7 +132,7 @@ src/core/
|
|
|
132
132
|
│ ├── dataBindingObject.js # DataBindingObject 类
|
|
133
133
|
│ ├── elements/ # UI 元素 (UIElement, Panel, Button, Image, Label, Grid...)
|
|
134
134
|
│ ├── properties/ # UI 属性 (Control, Layout, DataBinding, Sprite, Text...)
|
|
135
|
-
│ └── systems/ # UI 系统 (UISystem, Chest, ServerForm, Guidebook, HUD,
|
|
135
|
+
│ └── systems/ # UI 系统 (UISystem, Chest, ServerForm, Guidebook, HUD, SapdonGuideBook...)
|
|
136
136
|
│
|
|
137
137
|
└── extra/ # ── 附加模块 ──
|
|
138
138
|
├── apperance.ts # ClientEntityApperance (实体外观管理)
|
|
@@ -686,7 +686,7 @@ UIElement (基类: name, type, template, control, layout, properties)
|
|
|
686
686
|
| `SapdonServerUI` | `systems/sapdon/sapdonServerUI.ts` | 页面壳路由系统,生成 `server_form.json` |
|
|
687
687
|
| `ChestUISystem` | `systems/chest.js` | 容器 UI 系统 |
|
|
688
688
|
| `ContainerUISystem` | `systems/containerUISystem.js` | 自定义容器 UI |
|
|
689
|
-
| `
|
|
689
|
+
| `SapdonGuideBook` | `systems/sapdon/sapdonGuideBook.ts` | 数据驱动手册框架类,详见 [guidebook.md](../guidebook.md) |
|
|
690
690
|
| `HudUISystem` | `systems/hud/hud.ts` | HUD 系统 |
|
|
691
691
|
| `HudStatePanel` | `systems/hud/hudElement.ts` | HUD 状态面板 |
|
|
692
692
|
|
|
@@ -25,7 +25,7 @@ src/core/ui/
|
|
|
25
25
|
├── chest.ts # ChestUISystem(接管 vanilla 箱子 screen)
|
|
26
26
|
├── containerUISystem.ts # ContainerUISystem(自定义容器 UI)
|
|
27
27
|
├── hud/ # HudUISystem + HudStatePanel
|
|
28
|
-
├── neoGuibook/ # NeoGuidebook
|
|
28
|
+
├── neoGuibook/ # (旧)NeoGuidebook + NeoGuidebookPage(兼容保留,新用 SapdonGuideBook)
|
|
29
29
|
└── sapdon/ # SapdonServerUI(表单路由壳)+ SapdonPanel/FormButton/FormButtonGrid
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -39,7 +39,7 @@ src/core/ui/
|
|
|
39
39
|
┌──────────────────────────────────────────────────────────┐
|
|
40
40
|
│ Layer 4: systems/ UISystem + 落地系统 │
|
|
41
41
|
│ UISystem = 一个 UI 文件;ContainerUISystem / SapdonServerUI │
|
|
42
|
-
│ /
|
|
42
|
+
│ / SapdonGuideBook / HudUISystem 等在其上叠业务能力 │
|
|
43
43
|
├──────────────────────────────────────────────────────────┤
|
|
44
44
|
│ Layer 3: elements/ 元素层 │
|
|
45
45
|
│ UIElement 基类 + Panel/StackPanel/Grid/Label/Image/Button │
|
|
@@ -204,7 +204,7 @@ elem.dataBinding.addDataBinding(
|
|
|
204
204
|
|
|
205
205
|
| 形式 | 走法 | 代表 |
|
|
206
206
|
|------|------|------|
|
|
207
|
-
| **server_form(表单 / 容器 / 书)** | `SapdonServerUI` 用 modification 把自定义页注入 vanilla `main_screen_content`,用 `#title_text` / `#form_text` 前缀门控可见性;每页 = "内容面板 + 按键面板" | `
|
|
207
|
+
| **server_form(表单 / 容器 / 书)** | `SapdonServerUI` 用 modification 把自定义页注入 vanilla `main_screen_content`,用 `#title_text` / `#form_text` 前缀门控可见性;每页 = "内容面板 + 按键面板" | `SapdonGuideBook`、`ContainerUISystem/ChestUISystem`、`SapdonPanel/FormButton/FormButtonGrid` |
|
|
208
208
|
| **HUD 常驻** | `HudUISystem` 改 vanilla `hud_title_text` 绑定,`mountRootElement` 往根面板 `insert_front` 挂元素;`HudStatePanel` 用 title 字符串做状态机驱动 `#visible` | `HudProgressBar` |
|
|
209
209
|
|
|
210
210
|
### 4.1 server_form 路由壳(`SapdonServerUI`)
|
package/doc/guidebook.md
CHANGED
|
@@ -64,6 +64,7 @@ new SapdonGuideBook(
|
|
|
64
64
|
| 方法 | 说明 |
|
|
65
65
|
|---|---|
|
|
66
66
|
| `.build(categories: GuideBookCategory[])` | 传入分类数据,生成全部页面;返回 `this` |
|
|
67
|
+
| `.setCover(title, lines)` | 自定义封面标题(可含 `\n`)与简介行,如 `.setCover(' 我的手册 \\n by Me', ['第一行简介', '第二行简介'])` |
|
|
67
68
|
| `.enableDebug()` | 开启调试(显示 `#form_text` 当前值 / 格子描边) |
|
|
68
69
|
| `.getSystem()` | 返回内部 `UISystem` |
|
|
69
70
|
|
|
@@ -232,6 +233,8 @@ world.afterEvents.itemUse.subscribe((e) => {
|
|
|
232
233
|
});
|
|
233
234
|
```
|
|
234
235
|
|
|
236
|
+
> **打开触发**默认是手持**木棍右键**(`minecraft:stick`)。若手册由某个具体物品打开(如 more-golem 的指南书),把 `e.itemStack.typeId` 换成该物品的 id,或改为在物品的 `onUse` 自定义组件里直接调 `openIndex(player)`。
|
|
237
|
+
|
|
235
238
|
---
|
|
236
239
|
|
|
237
240
|
## 7. 完整教程(从零做一个手册)
|
|
@@ -279,10 +282,15 @@ sapdon build ./
|
|
|
279
282
|
"buildEntry": "main.ts",
|
|
280
283
|
"scriptEntry": "scripts/index.ts",
|
|
281
284
|
"scriptOutput": "scripts/index.js",
|
|
282
|
-
"buildMode": "dev"
|
|
285
|
+
"buildMode": "dev",
|
|
286
|
+
"dependencies": [
|
|
287
|
+
{ "module_name": "@minecraft/server-ui", "version": "2.1.0" },
|
|
288
|
+
{ "module_name": "@minecraft/server", "version": "2.8.0" }
|
|
289
|
+
]
|
|
283
290
|
}
|
|
284
291
|
}
|
|
285
292
|
```
|
|
293
|
+
> `dependencies` 里的 `@minecraft/server-ui` 是运行时路由(`ActionFormData`)必需的,别忘了。
|
|
286
294
|
|
|
287
295
|
---
|
|
288
296
|
|
package/doc/user/quick-start.md
CHANGED
|
@@ -117,6 +117,5 @@ dev/
|
|
|
117
117
|
- [物品教程](./tutorials/item.md) — 学习创建各类物品
|
|
118
118
|
- [实体教程](./tutorials/entity.md) — 学习创建实体
|
|
119
119
|
- [方块教程](./tutorials/block.md) — 学习创建方块
|
|
120
|
-
- [
|
|
121
|
-
- [指南书实战经验](./tutorials/neo-guidebook-experience.md) — 接入流程与踩坑清单
|
|
120
|
+
- [指南书(SapdonGuideBook)](../guidebook.md) — 手册框架类文档与教程
|
|
122
121
|
- [API 参考](./api/item.md) — 完整的 API 文档
|
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.4.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.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);
|
package/prod/core/index.d.ts
CHANGED
|
@@ -4778,164 +4778,6 @@ declare class StackPanel extends Panel {
|
|
|
4778
4778
|
serialize(): SerializedElement;
|
|
4779
4779
|
}
|
|
4780
4780
|
|
|
4781
|
-
type CustomButtonConfig = {
|
|
4782
|
-
id: string;
|
|
4783
|
-
position: "bottom_left" | "bottom_right" | "bottom_middle" | "top_left" | "top_right";
|
|
4784
|
-
offset: [number, number];
|
|
4785
|
-
size: [number | string, number | string];
|
|
4786
|
-
defaultTexture: string;
|
|
4787
|
-
hoverTexture: string;
|
|
4788
|
-
pressedTexture: string;
|
|
4789
|
-
bindingButtonName: string;
|
|
4790
|
-
};
|
|
4791
|
-
type ButtonTextures = {
|
|
4792
|
-
prevDefault?: string;
|
|
4793
|
-
prevHover?: string;
|
|
4794
|
-
prevPressed?: string;
|
|
4795
|
-
nextDefault?: string;
|
|
4796
|
-
nextHover?: string;
|
|
4797
|
-
nextPressed?: string;
|
|
4798
|
-
homeDefault?: string;
|
|
4799
|
-
homeHover?: string;
|
|
4800
|
-
homePressed?: string;
|
|
4801
|
-
closeDefault?: string;
|
|
4802
|
-
closeHover?: string;
|
|
4803
|
-
closePressed?: string;
|
|
4804
|
-
};
|
|
4805
|
-
type NeoGuidebookOptions = {
|
|
4806
|
-
size?: [number, number];
|
|
4807
|
-
background?: string;
|
|
4808
|
-
debug?: boolean;
|
|
4809
|
-
buttons?: {
|
|
4810
|
-
prev?: {
|
|
4811
|
-
visible?: boolean;
|
|
4812
|
-
};
|
|
4813
|
-
next?: {
|
|
4814
|
-
visible?: boolean;
|
|
4815
|
-
};
|
|
4816
|
-
home?: {
|
|
4817
|
-
visible?: boolean;
|
|
4818
|
-
};
|
|
4819
|
-
close?: {
|
|
4820
|
-
visible?: boolean;
|
|
4821
|
-
};
|
|
4822
|
-
};
|
|
4823
|
-
textures?: ButtonTextures;
|
|
4824
|
-
};
|
|
4825
|
-
declare class NeoGuidebook {
|
|
4826
|
-
private identifier;
|
|
4827
|
-
private book_pages;
|
|
4828
|
-
private size;
|
|
4829
|
-
private background_image;
|
|
4830
|
-
private debug_mode;
|
|
4831
|
-
private system;
|
|
4832
|
-
private content_panel_name;
|
|
4833
|
-
private content_panel_id;
|
|
4834
|
-
private buttons_panel_name;
|
|
4835
|
-
private buttons_panel_id;
|
|
4836
|
-
private root_panel_elements;
|
|
4837
|
-
private custom_buttons;
|
|
4838
|
-
private button_visibility;
|
|
4839
|
-
private textures;
|
|
4840
|
-
private dirty;
|
|
4841
|
-
constructor(identifier: string, path: string, size?: [number, number], options?: NeoGuidebookOptions);
|
|
4842
|
-
getPageIds(): string[];
|
|
4843
|
-
getPageCount(): number;
|
|
4844
|
-
addCustomButton(config: CustomButtonConfig): this;
|
|
4845
|
-
addSinglePageStack(page_id: string, page_content: Panel): void;
|
|
4846
|
-
addDoublePageStack(page_id: string, left_page: Panel, right_page: Panel, ratio?: [string, string]): void;
|
|
4847
|
-
private flush;
|
|
4848
|
-
private createPagesPanel;
|
|
4849
|
-
private initUI;
|
|
4850
|
-
private createNavButtons;
|
|
4851
|
-
private createCustomButtons;
|
|
4852
|
-
private updateUI;
|
|
4853
|
-
private tex;
|
|
4854
|
-
private createCloseButton;
|
|
4855
|
-
private createPageButton;
|
|
4856
|
-
private createHomeButton;
|
|
4857
|
-
private createBookPage;
|
|
4858
|
-
private createDebugText;
|
|
4859
|
-
registerElement(element: UIElement): this;
|
|
4860
|
-
addRootElement(element: UIElement): this;
|
|
4861
|
-
addRootElements(elements: UIElement[]): this;
|
|
4862
|
-
}
|
|
4863
|
-
|
|
4864
|
-
/**
|
|
4865
|
-
* @deprecated 图标/纹理按钮请改用 FormButton(@common.button + 三态纹理 + 门控绑定)。
|
|
4866
|
-
* 本类仅为兼容 NeoGuidebook 保留;后续随 guidebook 迁移一并移除。
|
|
4867
|
-
*/
|
|
4868
|
-
declare class SapdonTexturedButton extends UIElement {
|
|
4869
|
-
constructor(id: string, bindingButtonName?: string);
|
|
4870
|
-
setDefaultTexture(texture: string): this;
|
|
4871
|
-
setHoverTexture(texture: string): this;
|
|
4872
|
-
setPressedTexture(texture: string): this;
|
|
4873
|
-
/** 设置锚点对齐 */
|
|
4874
|
-
setAnchor(anchor: string, size?: [number | string, number | string]): this;
|
|
4875
|
-
}
|
|
4876
|
-
|
|
4877
|
-
declare class EmptySpace extends Panel {
|
|
4878
|
-
constructor(id: string, size?: [string, string]);
|
|
4879
|
-
}
|
|
4880
|
-
declare class BookTitle extends Label {
|
|
4881
|
-
constructor(id: string, title: string, size?: [string, string]);
|
|
4882
|
-
}
|
|
4883
|
-
declare class BookText extends Label {
|
|
4884
|
-
constructor(id: string, text: string, size?: [string, string]);
|
|
4885
|
-
}
|
|
4886
|
-
declare class BookTitleBar extends Panel {
|
|
4887
|
-
private size;
|
|
4888
|
-
constructor(id: string, text: string, size?: [string, string]);
|
|
4889
|
-
getSize(): [string, string];
|
|
4890
|
-
}
|
|
4891
|
-
declare class Divider extends StackPanel {
|
|
4892
|
-
constructor(id: string, size?: [string, string]);
|
|
4893
|
-
}
|
|
4894
|
-
declare class BookButton extends SapdonTexturedButton {
|
|
4895
|
-
constructor(id: string, texture: string, size?: [string, string]);
|
|
4896
|
-
}
|
|
4897
|
-
declare class BookImage extends Image {
|
|
4898
|
-
constructor(id: string, texture: string, size?: [string, string]);
|
|
4899
|
-
}
|
|
4900
|
-
declare class BookCategoryGrid extends StackPanel {
|
|
4901
|
-
constructor(id: string, row: number, col: number, buttons: Array<{
|
|
4902
|
-
id: string;
|
|
4903
|
-
texture: string;
|
|
4904
|
-
}>);
|
|
4905
|
-
}
|
|
4906
|
-
declare class BookRecipeGrid extends StackPanel {
|
|
4907
|
-
constructor(id: string, row: number, col: number, items: string[]);
|
|
4908
|
-
}
|
|
4909
|
-
declare class ChapterItem extends Panel {
|
|
4910
|
-
constructor(index: number, chapterName: string, texture: string, prefix?: string);
|
|
4911
|
-
}
|
|
4912
|
-
declare class NeoGuidebookPage {
|
|
4913
|
-
private panel;
|
|
4914
|
-
private categories;
|
|
4915
|
-
private chapters;
|
|
4916
|
-
constructor(id: string, size?: [string, string]);
|
|
4917
|
-
addCategoryTitle(title: string, size?: [string, string]): this;
|
|
4918
|
-
addBookTitleBar(text: string, size?: [string, string]): this;
|
|
4919
|
-
addBookText(text: string, size?: [string, string]): this;
|
|
4920
|
-
addEmptySpace(size?: [string, string]): this;
|
|
4921
|
-
addDivider(size?: [string, string]): this;
|
|
4922
|
-
addRecipeGrid(row: number, col: number, items: string[], size?: [string, string]): this;
|
|
4923
|
-
addBookCategory(title: string, row: number, col: number, buttons: Array<{
|
|
4924
|
-
id: string;
|
|
4925
|
-
texture: string;
|
|
4926
|
-
}>): this;
|
|
4927
|
-
addChapter(chapterName: string, texture: string): this;
|
|
4928
|
-
addChapters(chapters: Array<{
|
|
4929
|
-
chapter_name: string;
|
|
4930
|
-
chapter_texture: string;
|
|
4931
|
-
}>): this;
|
|
4932
|
-
buildChapterList(prefix?: string): this;
|
|
4933
|
-
addControl(control: UIElement): this;
|
|
4934
|
-
addStack(size: [string, string], control: UIElement, debug?: boolean): this;
|
|
4935
|
-
getPanel(): StackPanel;
|
|
4936
|
-
clear(): this;
|
|
4937
|
-
}
|
|
4938
|
-
|
|
4939
4781
|
declare namespace HudUISystem {
|
|
4940
4782
|
/**
|
|
4941
4783
|
* 获取HUD UI系统实例
|
|
@@ -5122,6 +4964,19 @@ declare class FormButtonGrid {
|
|
|
5122
4964
|
build(): UIElement;
|
|
5123
4965
|
}
|
|
5124
4966
|
|
|
4967
|
+
/**
|
|
4968
|
+
* @deprecated 图标/纹理按钮请改用 FormButton(@common.button + 三态纹理 + 门控绑定)。
|
|
4969
|
+
* 本类仅为兼容 NeoGuidebook 保留;后续随 guidebook 迁移一并移除。
|
|
4970
|
+
*/
|
|
4971
|
+
declare class SapdonTexturedButton extends UIElement {
|
|
4972
|
+
constructor(id: string, bindingButtonName?: string);
|
|
4973
|
+
setDefaultTexture(texture: string): this;
|
|
4974
|
+
setHoverTexture(texture: string): this;
|
|
4975
|
+
setPressedTexture(texture: string): this;
|
|
4976
|
+
/** 设置锚点对齐 */
|
|
4977
|
+
setAnchor(anchor: string, size?: [number | string, number | string]): this;
|
|
4978
|
+
}
|
|
4979
|
+
|
|
5125
4980
|
/**
|
|
5126
4981
|
* SapdonGuideBook —— 帕秋莉式手册(分类索引 INDEX + 词条列表 CAT + 内容页 ENT + home/prev/next 导航)。
|
|
5127
4982
|
*
|
|
@@ -5283,5 +5138,5 @@ declare namespace registry {
|
|
|
5283
5138
|
function submit(): void;
|
|
5284
5139
|
}
|
|
5285
5140
|
|
|
5286
|
-
export { AddonAnimationController, AddonAnimationStateMachine, AddonAttachable, AddonAttachableDefinition, AddonAttachableDescription, AddonBiome, AddonBiomeDefinition, AddonBiomeDescription, AddonBlock, AddonBlockDefinition, AddonBlockDescription, AddonClientEntity, AddonClientEntityDefinition, AddonClientEntityDescription, AddonEntity, AddonEntityDefinition, AddonEntityDescription, AddonFeatureRule, AddonFeatureRuleDecription, AddonFeatureRuleDenifition, AddonItem, AddonItemDefinition, AddonItemDescription, AddonManifest, AddonManifestDependency, AddonManifestHeader, AddonManifestMetadata, AddonManifestModule, AddonMenuCategory, AddonOreFeature, AddonOreFeatureDefinition, AddonOreFeatureDescription, AddonRecipe, AddonRecipeFurnace, AddonRecipeFurnace_1_12, AddonRecipeFurnace_1_17, AddonRecipeShaped, AddonRecipeShaped_1_12, AddonRecipeShaped_1_17, AddonRecipeShaped_1_19, AddonRecipeShaped_1_20, AddonRecipeShapeless, AddonRecipeShapeless_1_12, AddonRecipeShapeless_1_17, AddonRenderController, AddonRenderControllerGroup, AddonSemanticVersion, Armor, ArmorType, Attachable, BasicBlock, BasicBundle, BasicEntity, BasicMovementBundle, Biome, BiomeAPI, BiomeComponent, BiomeFilter, Block, BlockAPI, BlockComponent, BlockCustomComponentBuilder,
|
|
5141
|
+
export { AddonAnimationController, AddonAnimationStateMachine, AddonAttachable, AddonAttachableDefinition, AddonAttachableDescription, AddonBiome, AddonBiomeDefinition, AddonBiomeDescription, AddonBlock, AddonBlockDefinition, AddonBlockDescription, AddonClientEntity, AddonClientEntityDefinition, AddonClientEntityDescription, AddonEntity, AddonEntityDefinition, AddonEntityDescription, AddonFeatureRule, AddonFeatureRuleDecription, AddonFeatureRuleDenifition, AddonItem, AddonItemDefinition, AddonItemDescription, AddonManifest, AddonManifestDependency, AddonManifestHeader, AddonManifestMetadata, AddonManifestModule, AddonMenuCategory, AddonOreFeature, AddonOreFeatureDefinition, AddonOreFeatureDescription, AddonRecipe, AddonRecipeFurnace, AddonRecipeFurnace_1_12, AddonRecipeFurnace_1_17, AddonRecipeShaped, AddonRecipeShaped_1_12, AddonRecipeShaped_1_17, AddonRecipeShaped_1_19, AddonRecipeShaped_1_20, AddonRecipeShapeless, AddonRecipeShapeless_1_12, AddonRecipeShapeless_1_17, AddonRenderController, AddonRenderControllerGroup, AddonSemanticVersion, Armor, ArmorType, Attachable, BasicBlock, BasicBundle, BasicEntity, BasicMovementBundle, Biome, BiomeAPI, BiomeComponent, BiomeFilter, Block, BlockAPI, BlockComponent, BlockCustomComponentBuilder, Button, ButtonMapping, ChestUISystem, ClientEntity, CollectionPanel, ContainerUISystem, Control, CoordinateDistribution, CropBlock, DataBinding, DataBindingObject, DummyEntity, Entity, EntityAPI, EntityComponent, Factory, FeatureAPI, FeatureConditions, FeatureDistribution, FeatureRule, FenceBlock, FlipbookItem, FlipbookTextureConfig, FlipbookTextures, FollowMobBehavior, FollowParentBehavior, Food, FormButton, FormButtonGrid, GeometryBlock, GlassBlock, GoHomeBehavior, Grid, GridProp, HeadBlock, HudProgressBar, HudStatePanel, HudUISystem, Image, Input, Item, ItemAPI, ItemCatalog, ItemCategory, ItemComponent, ItemTextureManager, Label, Layout, Modifications, MoveTowardsHomeRestrictionBehavior, NativeEntity, NativeEntityData, Navigation, NearestAttackableTargetBehavor, NonNullMap, OreBlock, OreFeature, Panel, PickupItemsBehavior, Projectile, RandomStrollBehavior, RecipeAPI, RecipeInputTags, RecipeTags, RecipeTypes, RotatableBlock, RotationTypes, SapdonGuideBook, SapdonPanel, SapdonServerUI, SapdonTexturedButton, ScrollView, ScrollingPanel, Serializable, Serializer, Sound, Sprite, StackPanel, StairBlock, TemptBehavior, TerrainTextureManager, Text, TextureVariationConfig, TileBlock, TintMethod, TrapdoorBlock, UIElement, UISystem, UISystemRegistry, UiAPI, decode, defaultSerializer, encode, f64, getMetadata, getOrCreateMetadata, isRawJSON, jsonEncodeDecoder, jsonEncoderReplacer, mixin, registerBlock, registerEntity, registry, serialize };
|
|
5287
5142
|
export type { ArmorOptions, ArmorSpec, BeforeOnPlayerPlaceEvent, BlockCustomComponentHandlers, BlockDescriptor, BlockPlacerOptions, ConstructorOf, CooldownOptions, CreateModelItemOptions, DiggerOptions, DurabilitySensorOptions, DurabilityThreshold, EncodeDecoder, EntityPlacerOptions, FlipbookEntry, FlipbookItemOptions, FloatLiteral, FoodComponentOptions, FoodOptions, GuideBookCategory, GuideBookChapter, GuideBookPageType, ISerializer, IconTextures, ItemCatalogCategory, ItemCatalogGroupOptions, ItemComponentMap, ItemOptions, ItemRarity, KineticWeaponOptions, ModelBoneTransform, OnBlockStateChangeEvent, OnBreakEvent, OnEntityEvent, OnEntityFallOnEvent, OnPlaceEvent, OnPlayerBreakEvent, OnPlayerInteractEvent, OnRandomTickEvent, OnRedstoneUpdateEvent, OnStepOffEvent, OnStepOnEvent, OnTickEvent, PiercingWeaponOptions, Range, RawType, RecordOptions, RepairItem, SapdonPageRegistration, SerializedElement, ShooterAmmunition, ShooterOptions, StorageItemOptions, SwingSoundsOptions, TextureEntry, TextureVariation, ThrowableOptions, UseModifiersOptions };
|