diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 65b5c564..f746f345 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -59,15 +59,16 @@ export default withMermaid({ // https://vitepress.dev/reference/default-theme-config nav: [ { text: '首页', link: '/' }, - { text: 'Wiki', link: '/wiki' }, - { text: 'API文档', link: '/mcdocs/0-欢迎' }, - { text: '开发指南', link: '/mcguide/0-欢迎' }, - { text: '教学课程', link: '/mconline/0-欢迎' }, + { text: 'Wiki', link: '/wiki', activeMatch: '^/wiki/' }, + { text: 'API文档', link: '/mcdocs/0-欢迎', activeMatch: '^/mcdocs/' }, + { text: '开发指南', link: '/mcguide/0-欢迎', activeMatch: '^/mcguide/' }, + { text: '教学课程', link: '/mconline/0-欢迎', activeMatch: '^/mconline/' }, ], sidebar: await generateSidebar(), socialLinks: [ + { icon: 'qq', link: 'https://qm.qq.com/q/NGIRFwEoMw' }, { icon: 'github', link: 'https://github.com/EaseCation/netease-modsdk-wiki' } ], @@ -76,6 +77,15 @@ export default withMermaid({ text: '在 GitHub 上编辑此页' }, + footer: { + message: 'ICP备案/许可证号 浙ICP备2022033471号-1', + copyright: 'Made with ❤️ by EaseCation' + }, + + sitemap: { + hostname: 'https://mcwiki.easecation.net' + }, + search: { provider: 'algolia', options: { diff --git a/docs/.vitepress/config.mts.timestamp-1742482973657-8bee96eedb873.mjs b/docs/.vitepress/config.mts.timestamp-1742482973657-8bee96eedb873.mjs deleted file mode 100644 index 14d6e0ea..00000000 --- a/docs/.vitepress/config.mts.timestamp-1742482973657-8bee96eedb873.mjs +++ /dev/null @@ -1,476 +0,0 @@ -// docs/.vitepress/config.mts -import { fileURLToPath, URL } from "node:url"; - -// scripts/sidebar.ts -import fs2 from "fs/promises"; -import path2 from "path"; -import fg from "file:///Users/fangyizhou/Documents/coding/netease-modsdk-wiki/node_modules/fast-glob/out/index.js"; -import matter2 from "file:///Users/fangyizhou/Documents/coding/netease-modsdk-wiki/node_modules/gray-matter/index.js"; - -// scripts/sidebar-wiki.ts -import fs from "fs"; -import path from "path"; -import matter from "file:///Users/fangyizhou/Documents/coding/netease-modsdk-wiki/node_modules/gray-matter/index.js"; -var excludeFiles = [ - "entities/vanilla-usage-components.md", - "entities/vanilla-usage-spawn-rules.md", - "entities/vuc-full.md", - "entities/vusr-full.md" -]; -var fastBuild = process.env.fastBuild === "true "; -if (fastBuild && process.env.NODE_ENV == "production") { - console.log( - ` -INFO: fastBuild selected. the files: -${JSON.stringify( - excludeFiles, - null, - 4 - )} -will not be compiled! -` - ); -} -function formatLink(path3) { - return path3.split(/\\|\//g).join("/").replace(".md", ""); -} -function getCategoryOrder(frontMatter) { - const data = {}; - if (!frontMatter.data.categories) { - return data; - } - frontMatter.data.categories.forEach(function(category, index) { - data[category.title] = index + 1; - }); - return data; -} -function getCategories(frontMatter) { - const data = []; - if (!frontMatter.data.categories) { - return data; - } - frontMatter.data.categories.forEach(function(category, index) { - category.nav_order = -1; - category.category = category.title; - data.push({ - text: category.title, - data: category, - tags: category.tags, - prefix: category.prefix, - section: true, - color: category.color, - link: "", - activeMatch: " " - }); - }); - return data; -} -var order; -function generateWikiSidebar(base, dir) { - const data = []; - const files = fs.readdirSync(dir); - files.forEach(function(file) { - let joinedPath = path.join(dir, file); - const stats = fs.statSync(joinedPath); - if (stats.isDirectory() && fs.existsSync(path.join(joinedPath, "index.md"))) { - const str = fs.readFileSync( - path.join(joinedPath, "index.md"), - "utf8" - ); - let frontMatter; - try { - frontMatter = matter(str); - } catch (e) { - joinedPath = path.relative( - process.cwd(), - path.join(joinedPath, "index.md") - ); - console.log( - // @ts-ignore - `::error file=${joinedPath},line=1,col=1::File ${joinedPath} has invalid frontmatter! ${e.message}` - ); - throw new Error( - // @ts-ignore - `File ${joinedPath} has invalid frontmatter! ${e.message}` - ); - } - order = getCategoryOrder(frontMatter); - const children = generateWikiSidebar(base, joinedPath).concat( - getCategories(frontMatter) - ); - children.sort( - ({ data: dataA, text: textA }, { data: dataB, text: textB }) => { - const navA = (dataA.nav_order || 50) + (order[dataA.category] || 0) * 100 || Number.MAX_SAFE_INTEGER; - const navB = (dataB.nav_order || 50) + (order[dataB.category] || 0) * 100 || Number.MAX_SAFE_INTEGER; - if (navA == navB) { - return textA.localeCompare(textB); - } - return navA - navB; - } - ); - data.push({ - text: frontMatter.data.title, - data: frontMatter.data, - children - }); - if (frontMatter.data.title === void 0) { - throw new Error( - "File " + path.join(joinedPath, "index.md") + " has invalid frontmatter!" - ); - } - } else if (stats.isFile()) { - if (!file.endsWith(".md") || file.endsWith("index.md")) return; - const str = fs.readFileSync(joinedPath, "utf8"); - let frontMatter; - try { - frontMatter = matter(str); - } catch (e) { - joinedPath = path.relative(process.cwd(), joinedPath); - console.log( - // @ts-ignore - `::error file=${joinedPath},line=1,col=1::File ${joinedPath} has invalid frontmatter! ${e.message}` - ); - throw new Error( - // @ts-ignore - `File ${joinedPath} has invalid frontmatter! ${e.message}` - ); - } - const link = formatLink(joinedPath.toString().replace(base, "")); - if (frontMatter.data.hidden === true) return; - let prefix = null; - if (frontMatter.data.prefix != null) { - prefix = frontMatter.data.prefix; - } - let tags = null; - if (frontMatter.data.tags != null) { - tags = frontMatter.data.tags; - } - data.push({ - text: frontMatter.data.title, - data: frontMatter.data, - tags, - prefix, - section: frontMatter.data.section || false, - color: frontMatter.data.color || "none", - link, - activeMatch: `^${link}` - }); - if (frontMatter.data.title === void 0) { - joinedPath = path.relative(process.cwd(), joinedPath); - console.log( - `::error file=${joinedPath},line=1,col=1::File ${joinedPath} has invalid frontmatter!` - ); - throw new Error(`File ${joinedPath} has invalid frontmatter!`); - } - } - }); - return data.sort( - ({ data: dataA, text: textA }, { data: dataB, text: textB }) => { - const navA = (dataA.nav_order || 50) + (order[dataA.category] || 0) * 100 || Number.MAX_SAFE_INTEGER; - const navB = (dataB.nav_order || 50) + (order[dataB.category] || 0) * 100 || Number.MAX_SAFE_INTEGER; - if (navA == navB) { - return textA.localeCompare(textB); - } - return navA - navB; - } - ); -} - -// scripts/sidebar.ts -var DOCS_DIR = "docs"; -var IGNORE_PATHS = ["README.md", "readme.md", "index.md"]; -var DEFAULT_COLLAPSED_INDEX_MAP = { - "wiki": 1, - "mcdocs": 1, - "mcguide": 0, - "mconline": 0 -}; -var CATEGORY_MAP = { - "wiki": "Wiki", - "mcdocs": "API\u6587\u6863", - "mcguide": "\u5F00\u53D1\u6307\u5357", - "mconline": "\u6559\u5B66\u8BFE\u7A0B" -}; -function extractOrderNumber(name, matterData) { - const match = name.match(/^(\d+)-/); - if (match) { - return parseInt(match[1], 10); - } else if (matterData.order) { - return parseInt(matterData.order); - } else if (matterData.nav_order) { - return parseInt(matterData.nav_order); - } - return Number.MAX_SAFE_INTEGER; -} -async function generateSidebar() { - const sidebar = {}; - const files = await fg([`${DOCS_DIR}/**/*.md`]); - for (const filePath of files) { - if (filePath.includes("wiki")) continue; - const relativePath = path2.relative(DOCS_DIR, filePath); - if (IGNORE_PATHS.some((ignore) => relativePath.toLowerCase().includes(ignore.toLowerCase()))) continue; - const segments = relativePath.split(path2.sep); - const categoryKey = segments[0]; - const fileContent = await fs2.readFile(filePath, "utf-8"); - const { data: matterData } = matter2(fileContent); - if (matterData.hidden) { - continue; - } - const categoryName = CATEGORY_MAP[categoryKey] || categoryKey; - let currentLevel = sidebar[categoryKey] || []; - if (!sidebar[categoryKey]) { - sidebar[categoryKey] = currentLevel; - } - for (let i = 0; i < segments.length; i++) { - const segment = segments[i].replace(".md", ""); - const isLast = i === segments.length - 1; - let link; - if (isLast) { - link = `/${segments.slice(0, i + 1).join("/")}`.replace(/\.md$/, ""); - } else if (i === 0) { - link = `/${segment}`; - } - const order2 = extractOrderNumber(segment, matterData); - if (isLast) { - const title = await getTitleFromFile(filePath, matterData); - const activeMatch = `^${link}(?:/|$)`; - currentLevel.push({ text: title, link, order: order2, activeMatch }); - } else { - let displayText = i === 0 ? categoryName : segment; - displayText = displayText.replace(/^\d+-\s*/, ""); - let group = currentLevel.find( - (item) => i === 0 && item.text === categoryName || i !== 0 && item.text === displayText - ); - if (!group) { - const groupLink = i === 0 ? `/${segment}` : void 0; - group = { - text: displayText, - items: [], - order: order2, - collapsed: i > DEFAULT_COLLAPSED_INDEX_MAP[segments[0]], - // 为目录添加活动匹配模式 - activeMatch: `^/${segment}(?:/|$)`, - link: groupLink - }; - currentLevel.push(group); - } - currentLevel = group.items || []; - } - } - } - for (const key in sidebar) { - sortSidebarItems(sidebar[key]); - } - const sidebarFlat = {}; - for (const key in sidebar) { - sidebarFlat[key] = []; - sidebar[key].forEach((item) => { - if (item.items) { - sidebarFlat[key].push(...item.items); - } else { - sidebarFlat[key].push(item); - } - }); - } - const wiki = generateWikiSidebar(path2.join(process.cwd(), "docs"), path2.join(process.cwd(), "docs/wiki")); - const wikiSidebar = []; - wiki.forEach((item) => { - if (item.data.categories) { - const secondUrls = []; - const second = item.data.categories.map((category) => { - ; - return { - text: category.title, - collapsed: false, - items: item.children.filter((child) => child.data.category === category.title).filter((child) => child.link).map((child) => { - secondUrls.push(child.link); - return { - text: child.text, - link: child.link, - activeMatch: child.activeMatch - }; - }) - }; - }); - const notMatched = item.children.filter((child) => !secondUrls.includes(child.link)).filter((child) => child.link).map((child) => { - return { - text: child.text, - link: child.link, - activeMatch: child.activeMatch - }; - }); - wikiSidebar.push({ - text: item.data.title, - collapsed: true, - items: [...second, ...notMatched] - }); - } else { - wikiSidebar.push({ - text: item.text, - collapsed: true, - items: item.children.filter((child) => child.link).map((child) => { - return { - text: child.text, - link: child.link, - activeMatch: child.activeMatch - }; - }) - }); - } - }); - sidebarFlat["wiki"] = wikiSidebar; - return sidebarFlat; -} -function sortSidebarItems(items) { - items.sort((a, b) => { - const orderA = a.order ?? Number.MAX_SAFE_INTEGER; - const orderB = b.order ?? Number.MAX_SAFE_INTEGER; - return orderA - orderB; - }); - items.forEach((item) => { - if (item.items && item.items.length > 0) { - sortSidebarItems(item.items); - } - }); -} -async function getTitleFromFile(filePath, matterData) { - if (matterData.title) { - return matterData.title.trim().replace(/['"]/g, ""); - } - const basename = path2.basename(filePath, ".md"); - return basename.replace(/^\d+-\s*/, "").replace(/-/g, " "); -} -var sidebar_default = generateSidebar; - -// docs/.vitepress/config.mts -import { withMermaid } from "file:///Users/fangyizhou/Documents/coding/netease-modsdk-wiki/node_modules/vitepress-plugin-mermaid/dist/vitepress-plugin-mermaid.es.mjs"; -var __vite_injected_original_import_meta_url = "file:///Users/fangyizhou/Documents/coding/netease-modsdk-wiki/docs/.vitepress/config.mts"; -var config_default = withMermaid({ - lang: "zh-CN", - title: "\u6211\u7684\u4E16\u754C\u4E2D\u56FD\u7248 Wiki", - description: "ModSDK \u5F00\u53D1\u8005\u6587\u6863 \u955C\u50CF\uFF0C\u4F46\u63D0\u4F9B\u66F4\u4F18\u8D28\u7684\u641C\u7D22", - ignoreDeadLinks: true, - // 替换原生搜索组件,自定义展示的搜索结果内容 - vite: { - resolve: { - alias: [ - { - find: /^.*\/VPAlgoliaSearchBox\.vue$/, - replacement: fileURLToPath( - new URL("./theme/components/AlgoliaSearch.vue", __vite_injected_original_import_meta_url) - ) - } - ] - } - }, - locales: { - root: { - label: "\u7B80\u4F53\u4E2D\u6587", - lang: "zh-CN", - themeConfig: { - // 右侧导航栏的本地化文本 - outlineTitle: "\u672C\u9875\u76EE\u5F55", - // 文档底部的本地化文本 - docFooter: { - prev: "\u4E0A\u4E00\u9875", - next: "\u4E0B\u4E00\u9875" - }, - // 最后更新时间的本地化文本 - lastUpdatedText: "\u6700\u540E\u66F4\u65B0\u4E8E", - // 返回顶部按钮的本地化文本 - returnToTopLabel: "\u8FD4\u56DE\u9876\u90E8", - // 移动端菜单的本地化文本 - sidebarMenuLabel: "\u83DC\u5355", - darkModeSwitchLabel: "\u4E3B\u9898", - lightModeSwitchTitle: "\u5207\u6362\u5230\u6D45\u8272\u6A21\u5F0F", - darkModeSwitchTitle: "\u5207\u6362\u5230\u6DF1\u8272\u6A21\u5F0F" - } - } - }, - head: [ - ["script", { async: "", src: "https://www.googletagmanager.com/gtag/js?id=G-HPBDPVLP03" }], - ["script", {}, ` - window.dataLayer = window.dataLayer || []; - function gtag(){dataLayer.push(arguments);} - gtag('js', new Date()); - gtag('config', 'G-HPBDPVLP03'); - `] - ], - themeConfig: { - // https://vitepress.dev/reference/default-theme-config - nav: [ - { text: "\u9996\u9875", link: "/" }, - { text: "Wiki", link: "/wiki" }, - { text: "API\u6587\u6863", link: "/mcdocs/0-\u6B22\u8FCE" }, - { text: "\u5F00\u53D1\u6307\u5357", link: "/mcguide/0-\u6B22\u8FCE" }, - { text: "\u6559\u5B66\u8BFE\u7A0B", link: "/mconline/0-\u6B22\u8FCE" } - ], - sidebar: await sidebar_default(), - socialLinks: [ - { icon: "github", link: "https://github.com/EaseCation/netease-modsdk-wiki" } - ], - editLink: { - pattern: "https://github.com/EaseCation/netease-modsdk-wiki/edit/main/docs/:path", - text: "\u5728 GitHub \u4E0A\u7F16\u8F91\u6B64\u9875" - }, - search: { - provider: "algolia", - options: { - appId: "F8HD84CUON", - apiKey: "ccaf9255472c593d8a8b0724a940bb29", - indexName: "netease-modsdk", - searchParameters: { - // 筛选掉 rootType 为 mconline 的项目 - facetFilters: ["rootType:-mconline"] - }, - locales: { - root: { - placeholder: "\u641C\u7D22\u6587\u6863", - translations: { - button: { - buttonText: "\u641C\u7D22\u6587\u6863", - buttonAriaLabel: "\u641C\u7D22\u6587\u6863" - }, - modal: { - searchBox: { - resetButtonTitle: "\u6E05\u9664\u67E5\u8BE2\u6761\u4EF6", - resetButtonAriaLabel: "\u6E05\u9664\u67E5\u8BE2\u6761\u4EF6", - cancelButtonText: "\u53D6\u6D88", - cancelButtonAriaLabel: "\u53D6\u6D88" - }, - startScreen: { - recentSearchesTitle: "\u641C\u7D22\u5386\u53F2", - noRecentSearchesText: "\u6CA1\u6709\u641C\u7D22\u5386\u53F2", - saveRecentSearchButtonTitle: "\u4FDD\u5B58\u81F3\u641C\u7D22\u5386\u53F2", - removeRecentSearchButtonTitle: "\u4ECE\u641C\u7D22\u5386\u53F2\u4E2D\u79FB\u9664", - favoriteSearchesTitle: "\u6536\u85CF", - removeFavoriteSearchButtonTitle: "\u4ECE\u6536\u85CF\u4E2D\u79FB\u9664" - }, - errorScreen: { - titleText: "\u65E0\u6CD5\u83B7\u53D6\u7ED3\u679C", - helpText: "\u4F60\u53EF\u80FD\u9700\u8981\u68C0\u67E5\u4F60\u7684\u7F51\u7EDC\u8FDE\u63A5" - }, - footer: { - selectText: "\u9009\u62E9", - navigateText: "\u5207\u6362", - closeText: "\u5173\u95ED", - searchByText: "\u641C\u7D22\u63D0\u4F9B\u5546" - }, - noResultsScreen: { - noResultsText: "\u65E0\u6CD5\u627E\u5230\u76F8\u5173\u7ED3\u679C", - suggestedQueryText: "\u4F60\u53EF\u4EE5\u5C1D\u8BD5\u67E5\u8BE2", - reportMissingResultsText: "\u4F60\u8BA4\u4E3A\u8BE5\u67E5\u8BE2\u5E94\u8BE5\u6709\u7ED3\u679C\uFF1F", - reportMissingResultsLinkText: "\u70B9\u51FB\u53CD\u9988" - } - } - } - } - } - } - } - } -}); -export { - config_default as default -}; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZG9jcy8udml0ZXByZXNzL2NvbmZpZy5tdHMiLCAic2NyaXB0cy9zaWRlYmFyLnRzIiwgInNjcmlwdHMvc2lkZWJhci13aWtpLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL2Zhbmd5aXpob3UvRG9jdW1lbnRzL2NvZGluZy9uZXRlYXNlLW1vZHNkay13aWtpL2RvY3MvLnZpdGVwcmVzc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL2Zhbmd5aXpob3UvRG9jdW1lbnRzL2NvZGluZy9uZXRlYXNlLW1vZHNkay13aWtpL2RvY3MvLnZpdGVwcmVzcy9jb25maWcubXRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9mYW5neWl6aG91L0RvY3VtZW50cy9jb2RpbmcvbmV0ZWFzZS1tb2RzZGstd2lraS9kb2NzLy52aXRlcHJlc3MvY29uZmlnLm10c1wiO2ltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gJ3ZpdGVwcmVzcyc7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoLCBVUkwgfSBmcm9tICdub2RlOnVybCdcbmltcG9ydCBnZW5lcmF0ZVNpZGViYXIgZnJvbSAnLi4vLi4vc2NyaXB0cy9zaWRlYmFyLmpzJztcbmltcG9ydCB7IHdpdGhNZXJtYWlkIH0gZnJvbSBcInZpdGVwcmVzcy1wbHVnaW4tbWVybWFpZFwiO1xuXG4vLyBodHRwczovL3ZpdGVwcmVzcy5kZXYvcmVmZXJlbmNlL3NpdGUtY29uZmlnXG5leHBvcnQgZGVmYXVsdCB3aXRoTWVybWFpZCh7XG4gIGxhbmc6ICd6aC1DTicsXG4gIHRpdGxlOiBcIlx1NjIxMVx1NzY4NFx1NEUxNlx1NzU0Q1x1NEUyRFx1NTZGRFx1NzI0OCBXaWtpXCIsXG4gIGRlc2NyaXB0aW9uOiBcIk1vZFNESyBcdTVGMDBcdTUzRDFcdTgwMDVcdTY1ODdcdTY4NjMgXHU5NTVDXHU1MENGXHVGRjBDXHU0RjQ2XHU2M0QwXHU0RjlCXHU2NkY0XHU0RjE4XHU4RDI4XHU3Njg0XHU2NDFDXHU3RDIyXCIsXG4gIGlnbm9yZURlYWRMaW5rczogdHJ1ZSxcbiAgLy8gXHU2NkZGXHU2MzYyXHU1MzlGXHU3NTFGXHU2NDFDXHU3RDIyXHU3RUM0XHU0RUY2XHVGRjBDXHU4MUVBXHU1QjlBXHU0RTQ5XHU1QzU1XHU3OTNBXHU3Njg0XHU2NDFDXHU3RDIyXHU3RUQzXHU2NzlDXHU1MTg1XHU1QkI5XG4gIHZpdGU6IHtcbiAgICByZXNvbHZlOiB7XG4gICAgICBhbGlhczogW1xuICAgICAgICB7XG4gICAgICAgICAgZmluZDogL14uKlxcL1ZQQWxnb2xpYVNlYXJjaEJveFxcLnZ1ZSQvLFxuICAgICAgICAgIHJlcGxhY2VtZW50OiBmaWxlVVJMVG9QYXRoKFxuICAgICAgICAgICAgbmV3IFVSTCgnLi90aGVtZS9jb21wb25lbnRzL0FsZ29saWFTZWFyY2gudnVlJywgaW1wb3J0Lm1ldGEudXJsKVxuICAgICAgICAgIClcbiAgICAgICAgfVxuICAgICAgXVxuICAgIH1cbiAgfSxcbiAgbG9jYWxlczoge1xuICAgIHJvb3Q6IHtcbiAgICAgIGxhYmVsOiAnXHU3QjgwXHU0RjUzXHU0RTJEXHU2NTg3JyxcbiAgICAgIGxhbmc6ICd6aC1DTicsXG4gICAgICB0aGVtZUNvbmZpZzoge1xuICAgICAgICAvLyBcdTUzRjNcdTRGQTdcdTVCRkNcdTgyMkFcdTY4MEZcdTc2ODRcdTY3MkNcdTU3MzBcdTUzMTZcdTY1ODdcdTY3MkNcbiAgICAgICAgb3V0bGluZVRpdGxlOiAnXHU2NzJDXHU5ODc1XHU3NkVFXHU1RjU1JyxcbiAgICAgICAgLy8gXHU2NTg3XHU2ODYzXHU1RTk1XHU5MEU4XHU3Njg0XHU2NzJDXHU1NzMwXHU1MzE2XHU2NTg3XHU2NzJDXG4gICAgICAgIGRvY0Zvb3Rlcjoge1xuICAgICAgICAgIHByZXY6ICdcdTRFMEFcdTRFMDBcdTk4NzUnLFxuICAgICAgICAgIG5leHQ6ICdcdTRFMEJcdTRFMDBcdTk4NzUnXG4gICAgICAgIH0sXG4gICAgICAgIC8vIFx1NjcwMFx1NTQwRVx1NjZGNFx1NjVCMFx1NjVGNlx1OTVGNFx1NzY4NFx1NjcyQ1x1NTczMFx1NTMxNlx1NjU4N1x1NjcyQ1xuICAgICAgICBsYXN0VXBkYXRlZFRleHQ6ICdcdTY3MDBcdTU0MEVcdTY2RjRcdTY1QjBcdTRFOEUnLFxuICAgICAgICAvLyBcdThGRDRcdTU2REVcdTk4NzZcdTkwRThcdTYzMDlcdTk0QUVcdTc2ODRcdTY3MkNcdTU3MzBcdTUzMTZcdTY1ODdcdTY3MkNcbiAgICAgICAgcmV0dXJuVG9Ub3BMYWJlbDogJ1x1OEZENFx1NTZERVx1OTg3Nlx1OTBFOCcsXG4gICAgICAgIC8vIFx1NzlGQlx1NTJBOFx1N0FFRlx1ODNEQ1x1NTM1NVx1NzY4NFx1NjcyQ1x1NTczMFx1NTMxNlx1NjU4N1x1NjcyQ1xuICAgICAgICBzaWRlYmFyTWVudUxhYmVsOiAnXHU4M0RDXHU1MzU1JyxcbiAgICAgICAgZGFya01vZGVTd2l0Y2hMYWJlbDogJ1x1NEUzQlx1OTg5OCcsXG4gICAgICAgIGxpZ2h0TW9kZVN3aXRjaFRpdGxlOiAnXHU1MjA3XHU2MzYyXHU1MjMwXHU2RDQ1XHU4MjcyXHU2QTIxXHU1RjBGJyxcbiAgICAgICAgZGFya01vZGVTd2l0Y2hUaXRsZTogJ1x1NTIwN1x1NjM2Mlx1NTIzMFx1NkRGMVx1ODI3Mlx1NkEyMVx1NUYwRidcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIGhlYWQ6IFtcbiAgICBbJ3NjcmlwdCcsIHsgYXN5bmM6ICcnLCBzcmM6ICdodHRwczovL3d3dy5nb29nbGV0YWdtYW5hZ2VyLmNvbS9ndGFnL2pzP2lkPUctSFBCRFBWTFAwMycgfV0sXG4gICAgWydzY3JpcHQnLCB7fSwgYFxuICAgICAgd2luZG93LmRhdGFMYXllciA9IHdpbmRvdy5kYXRhTGF5ZXIgfHwgW107XG4gICAgICBmdW5jdGlvbiBndGFnKCl7ZGF0YUxheWVyLnB1c2goYXJndW1lbnRzKTt9XG4gICAgICBndGFnKCdqcycsIG5ldyBEYXRlKCkpO1xuICAgICAgZ3RhZygnY29uZmlnJywgJ0ctSFBCRFBWTFAwMycpO1xuICAgIGBdXG4gIF0sXG4gIHRoZW1lQ29uZmlnOiB7XG4gICAgLy8gaHR0cHM6Ly92aXRlcHJlc3MuZGV2L3JlZmVyZW5jZS9kZWZhdWx0LXRoZW1lLWNvbmZpZ1xuICAgIG5hdjogW1xuICAgICAgeyB0ZXh0OiAnXHU5OTk2XHU5ODc1JywgbGluazogJy8nIH0sXG4gICAgICB7IHRleHQ6ICdXaWtpJywgbGluazogJy93aWtpJyB9LFxuICAgICAgeyB0ZXh0OiAnQVBJXHU2NTg3XHU2ODYzJywgbGluazogJy9tY2RvY3MvMC1cdTZCMjJcdThGQ0UnIH0sXG4gICAgICB7IHRleHQ6ICdcdTVGMDBcdTUzRDFcdTYzMDdcdTUzNTcnLCBsaW5rOiAnL21jZ3VpZGUvMC1cdTZCMjJcdThGQ0UnIH0sXG4gICAgICB7IHRleHQ6ICdcdTY1NTlcdTVCNjZcdThCRkVcdTdBMEInLCBsaW5rOiAnL21jb25saW5lLzAtXHU2QjIyXHU4RkNFJyB9LFxuICAgIF0sXG5cbiAgICBzaWRlYmFyOiBhd2FpdCBnZW5lcmF0ZVNpZGViYXIoKSxcblxuICAgIHNvY2lhbExpbmtzOiBbXG4gICAgICB7IGljb246ICdnaXRodWInLCBsaW5rOiAnaHR0cHM6Ly9naXRodWIuY29tL0Vhc2VDYXRpb24vbmV0ZWFzZS1tb2RzZGstd2lraScgfVxuICAgIF0sXG5cbiAgICBlZGl0TGluazoge1xuICAgICAgcGF0dGVybjogJ2h0dHBzOi8vZ2l0aHViLmNvbS9FYXNlQ2F0aW9uL25ldGVhc2UtbW9kc2RrLXdpa2kvZWRpdC9tYWluL2RvY3MvOnBhdGgnLFxuICAgICAgdGV4dDogJ1x1NTcyOCBHaXRIdWIgXHU0RTBBXHU3RjE2XHU4RjkxXHU2QjY0XHU5ODc1J1xuICAgIH0sXG5cbiAgICBzZWFyY2g6IHtcbiAgICAgIHByb3ZpZGVyOiAnYWxnb2xpYScsXG4gICAgICBvcHRpb25zOiB7XG4gICAgICAgIGFwcElkOiAnRjhIRDg0Q1VPTicsXG4gICAgICAgIGFwaUtleTogJ2NjYWY5MjU1NDcyYzU5M2Q4YThiMDcyNGE5NDBiYjI5JyxcbiAgICAgICAgaW5kZXhOYW1lOiAnbmV0ZWFzZS1tb2RzZGsnLFxuICAgICAgICBzZWFyY2hQYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgLy8gXHU3QjVCXHU5MDA5XHU2Mzg5IHJvb3RUeXBlIFx1NEUzQSBtY29ubGluZSBcdTc2ODRcdTk4NzlcdTc2RUVcbiAgICAgICAgICBmYWNldEZpbHRlcnM6IFsncm9vdFR5cGU6LW1jb25saW5lJ11cbiAgICAgICAgfSxcbiAgICAgICAgbG9jYWxlczoge1xuICAgICAgICAgIHJvb3Q6IHtcbiAgICAgICAgICAgIHBsYWNlaG9sZGVyOiAnXHU2NDFDXHU3RDIyXHU2NTg3XHU2ODYzJyxcbiAgICAgICAgICAgIHRyYW5zbGF0aW9uczoge1xuICAgICAgICAgICAgICBidXR0b246IHtcbiAgICAgICAgICAgICAgICBidXR0b25UZXh0OiAnXHU2NDFDXHU3RDIyXHU2NTg3XHU2ODYzJyxcbiAgICAgICAgICAgICAgICBidXR0b25BcmlhTGFiZWw6ICdcdTY0MUNcdTdEMjJcdTY1ODdcdTY4NjMnXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIG1vZGFsOiB7XG4gICAgICAgICAgICAgICAgc2VhcmNoQm94OiB7XG4gICAgICAgICAgICAgICAgICByZXNldEJ1dHRvblRpdGxlOiAnXHU2RTA1XHU5NjY0XHU2N0U1XHU4QkUyXHU2NzYxXHU0RUY2JyxcbiAgICAgICAgICAgICAgICAgIHJlc2V0QnV0dG9uQXJpYUxhYmVsOiAnXHU2RTA1XHU5NjY0XHU2N0U1XHU4QkUyXHU2NzYxXHU0RUY2JyxcbiAgICAgICAgICAgICAgICAgIGNhbmNlbEJ1dHRvblRleHQ6ICdcdTUzRDZcdTZEODgnLFxuICAgICAgICAgICAgICAgICAgY2FuY2VsQnV0dG9uQXJpYUxhYmVsOiAnXHU1M0Q2XHU2RDg4J1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgc3RhcnRTY3JlZW46IHtcbiAgICAgICAgICAgICAgICAgIHJlY2VudFNlYXJjaGVzVGl0bGU6ICdcdTY0MUNcdTdEMjJcdTUzODZcdTUzRjInLFxuICAgICAgICAgICAgICAgICAgbm9SZWNlbnRTZWFyY2hlc1RleHQ6ICdcdTZDQTFcdTY3MDlcdTY0MUNcdTdEMjJcdTUzODZcdTUzRjInLFxuICAgICAgICAgICAgICAgICAgc2F2ZVJlY2VudFNlYXJjaEJ1dHRvblRpdGxlOiAnXHU0RkREXHU1QjU4XHU4MUYzXHU2NDFDXHU3RDIyXHU1Mzg2XHU1M0YyJyxcbiAgICAgICAgICAgICAgICAgIHJlbW92ZVJlY2VudFNlYXJjaEJ1dHRvblRpdGxlOiAnXHU0RUNFXHU2NDFDXHU3RDIyXHU1Mzg2XHU1M0YyXHU0RTJEXHU3OUZCXHU5NjY0JyxcbiAgICAgICAgICAgICAgICAgIGZhdm9yaXRlU2VhcmNoZXNUaXRsZTogJ1x1NjUzNlx1ODVDRicsXG4gICAgICAgICAgICAgICAgICByZW1vdmVGYXZvcml0ZVNlYXJjaEJ1dHRvblRpdGxlOiAnXHU0RUNFXHU2NTM2XHU4NUNGXHU0RTJEXHU3OUZCXHU5NjY0J1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZXJyb3JTY3JlZW46IHtcbiAgICAgICAgICAgICAgICAgIHRpdGxlVGV4dDogJ1x1NjVFMFx1NkNENVx1ODNCN1x1NTNENlx1N0VEM1x1Njc5QycsXG4gICAgICAgICAgICAgICAgICBoZWxwVGV4dDogJ1x1NEY2MFx1NTNFRlx1ODBGRFx1OTcwMFx1ODk4MVx1NjhDMFx1NjdFNVx1NEY2MFx1NzY4NFx1N0Y1MVx1N0VEQ1x1OEZERVx1NjNBNSdcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZvb3Rlcjoge1xuICAgICAgICAgICAgICAgICAgc2VsZWN0VGV4dDogJ1x1OTAwOVx1NjJFOScsXG4gICAgICAgICAgICAgICAgICBuYXZpZ2F0ZVRleHQ6ICdcdTUyMDdcdTYzNjInLFxuICAgICAgICAgICAgICAgICAgY2xvc2VUZXh0OiAnXHU1MTczXHU5NUVEJyxcbiAgICAgICAgICAgICAgICAgIHNlYXJjaEJ5VGV4dDogJ1x1NjQxQ1x1N0QyMlx1NjNEMFx1NEY5Qlx1NTU0NidcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIG5vUmVzdWx0c1NjcmVlbjoge1xuICAgICAgICAgICAgICAgICAgbm9SZXN1bHRzVGV4dDogJ1x1NjVFMFx1NkNENVx1NjI3RVx1NTIzMFx1NzZGOFx1NTE3M1x1N0VEM1x1Njc5QycsXG4gICAgICAgICAgICAgICAgICBzdWdnZXN0ZWRRdWVyeVRleHQ6ICdcdTRGNjBcdTUzRUZcdTRFRTVcdTVDMURcdThCRDVcdTY3RTVcdThCRTInLFxuICAgICAgICAgICAgICAgICAgcmVwb3J0TWlzc2luZ1Jlc3VsdHNUZXh0OiAnXHU0RjYwXHU4QkE0XHU0RTNBXHU4QkU1XHU2N0U1XHU4QkUyXHU1RTk0XHU4QkU1XHU2NzA5XHU3RUQzXHU2NzlDXHVGRjFGJyxcbiAgICAgICAgICAgICAgICAgIHJlcG9ydE1pc3NpbmdSZXN1bHRzTGlua1RleHQ6ICdcdTcwQjlcdTUxRkJcdTUzQ0RcdTk5ODgnXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG59KVxuIiwgImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvZmFuZ3lpemhvdS9Eb2N1bWVudHMvY29kaW5nL25ldGVhc2UtbW9kc2RrLXdpa2kvc2NyaXB0c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL2Zhbmd5aXpob3UvRG9jdW1lbnRzL2NvZGluZy9uZXRlYXNlLW1vZHNkay13aWtpL3NjcmlwdHMvc2lkZWJhci50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vVXNlcnMvZmFuZ3lpemhvdS9Eb2N1bWVudHMvY29kaW5nL25ldGVhc2UtbW9kc2RrLXdpa2kvc2NyaXB0cy9zaWRlYmFyLnRzXCI7aW1wb3J0IGZzIGZyb20gJ2ZzL3Byb21pc2VzJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IGZnIGZyb20gJ2Zhc3QtZ2xvYic7XG5pbXBvcnQgbWF0dGVyIGZyb20gJ2dyYXktbWF0dGVyJztcbmltcG9ydCB7IGdlbmVyYXRlV2lraVNpZGViYXIgfSBmcm9tICcuL3NpZGViYXItd2lraSc7XG5cbi8vIFx1NUI5QVx1NEU0OVx1NEZBN1x1OEZCOVx1NjgwRlx1OTg3OVx1NzZFRVx1NjNBNVx1NTNFM1xuaW50ZXJmYWNlIFNpZGViYXJJdGVtIHtcbiAgICB0ZXh0OiBzdHJpbmc7XG4gICAgbGluaz86IHN0cmluZztcbiAgICBpdGVtcz86IFNpZGViYXJJdGVtW107XG4gICAgb3JkZXI/OiBudW1iZXI7IC8vIFx1NkRGQlx1NTJBMFx1NjM5Mlx1NUU4Rlx1NUI1N1x1NkJCNVxuICAgIGNvbGxhcHNlZD86IGJvb2xlYW47IC8vIFx1NkRGQlx1NTJBMFx1NjI5OFx1NTNFMFx1NzJCNlx1NjAwMVx1NjNBN1x1NTIzNlxuICAgIGFjdGl2ZU1hdGNoPzogc3RyaW5nOyAvLyBcdTZERkJcdTUyQTBcdTZEM0JcdTUyQThcdTUzMzlcdTkxNERcdTZBMjFcdTVGMEZcbn1cblxuLy8gXHU5MTREXHU3RjZFXHU1M0MyXHU2NTcwXG5jb25zdCBET0NTX0RJUiA9ICdkb2NzJzsgICAgICAgICAgLy8gXHU2NTg3XHU2ODYzXHU2ODM5XHU3NkVFXHU1RjU1XG5jb25zdCBJR05PUkVfUEFUSFMgPSBbJ1JFQURNRS5tZCcsICdyZWFkbWUubWQnLCAnaW5kZXgubWQnXTsgLy8gXHU1RkZEXHU3NTY1XHU3Njg0XHU2NTg3XHU0RUY2XHU1NDBEXG5jb25zdCBERUZBVUxUX0NPTExBUFNFRF9JTkRFWF9NQVAgPSB7XG4gICAgJ3dpa2knOiAxLFxuICAgICdtY2RvY3MnOiAxLFxuICAgICdtY2d1aWRlJzogMCxcbiAgICAnbWNvbmxpbmUnOiAwXG59O1xuXG4vLyBcdTRFMDBcdTdFQTdcdTc2RUVcdTVGNTVcdTU0MERcdTc5RjBcdTY2MjBcdTVDMDRcdTg4NjhcbmNvbnN0IENBVEVHT1JZX01BUDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICBcIndpa2lcIjogXCJXaWtpXCIsXG4gICAgJ21jZG9jcyc6ICdBUElcdTY1ODdcdTY4NjMnLFxuICAgICdtY2d1aWRlJzogJ1x1NUYwMFx1NTNEMVx1NjMwN1x1NTM1NycsXG4gICAgJ21jb25saW5lJzogJ1x1NjU1OVx1NUI2Nlx1OEJGRVx1N0EwQidcbn07XG5cbi8qKlxuICogXHU0RUNFXHU1NDBEXHU3OUYwXHU0RTJEXHU2M0QwXHU1M0Q2XHU2MzkyXHU1RThGXHU2NTcwXHU1QjU3XG4gKiBcdTRGOEJcdTU5ODJcdUZGMUEnMC1cdTY5ODJcdThGRjAnIFx1OEZENFx1NTZERSAwXHVGRjBDJzEtXHU1N0ZBXHU3ODQwJyBcdThGRDRcdTU2REUgMVxuICovXG5mdW5jdGlvbiBleHRyYWN0T3JkZXJOdW1iZXIobmFtZTogc3RyaW5nLCBtYXR0ZXJEYXRhOiBhbnkpOiBudW1iZXIge1xuICAgIGNvbnN0IG1hdGNoID0gbmFtZS5tYXRjaCgvXihcXGQrKS0vKTtcbiAgICBpZiAobWF0Y2gpIHtcbiAgICAgICAgcmV0dXJuIHBhcnNlSW50KG1hdGNoWzFdLCAxMCk7XG4gICAgfSBlbHNlIGlmIChtYXR0ZXJEYXRhLm9yZGVyKSB7XG4gICAgICAgIHJldHVybiBwYXJzZUludChtYXR0ZXJEYXRhLm9yZGVyKTtcbiAgICB9IGVsc2UgaWYgKG1hdHRlckRhdGEubmF2X29yZGVyKSB7XG4gICAgICAgIHJldHVybiBwYXJzZUludChtYXR0ZXJEYXRhLm5hdl9vcmRlcik7XG4gICAgfVxuICAgIHJldHVybiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUjtcbn1cblxuLyoqXG4gKiBcdTc1MUZcdTYyMTBcdTRGQTdcdThGQjlcdTY4MEZcdTkxNERcdTdGNkVcdTk4NzlcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVTaWRlYmFyKCk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgU2lkZWJhckl0ZW1bXT4+IHtcbiAgICBjb25zdCBzaWRlYmFyOiBSZWNvcmQ8c3RyaW5nLCBTaWRlYmFySXRlbVtdPiA9IHt9O1xuICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgZmcoW2Ake0RPQ1NfRElSfS8qKi8qLm1kYF0pO1xuXG4gICAgLy8gXHU1OTA0XHU3NDA2XHU2MjQwXHU2NzA5XHU5NzVFIHdpa2kgXHU2NTg3XHU0RUY2XG4gICAgZm9yIChjb25zdCBmaWxlUGF0aCBvZiBmaWxlcykge1xuICAgICAgICAvLyBcdThERjNcdThGQzd3aWtpXG4gICAgICAgIGlmIChmaWxlUGF0aC5pbmNsdWRlcygnd2lraScpKSBjb250aW51ZTtcbiAgICAgICAgY29uc3QgcmVsYXRpdmVQYXRoID0gcGF0aC5yZWxhdGl2ZShET0NTX0RJUiwgZmlsZVBhdGgpO1xuICAgICAgICBpZiAoSUdOT1JFX1BBVEhTLnNvbWUoaWdub3JlID0+IHJlbGF0aXZlUGF0aC50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKGlnbm9yZS50b0xvd2VyQ2FzZSgpKSkpIGNvbnRpbnVlO1xuXG4gICAgICAgIGNvbnN0IHNlZ21lbnRzID0gcmVsYXRpdmVQYXRoLnNwbGl0KHBhdGguc2VwKTtcbiAgICAgICAgY29uc3QgY2F0ZWdvcnlLZXkgPSBzZWdtZW50c1swXTtcblxuICAgICAgICAvLyBcdThCRkJcdTUzRDZcdTY1ODdcdTRFRjZcdTUxODVcdTVCQjlcdUZGMENcdTcxMzZcdTU0MEVcdTkwMUFcdThGQzdtYXR0ZXJcdThCRkJcdTUzRDZcdTU5MzRcdTkwRThcdTRGRTFcdTYwNkZcbiAgICAgICAgY29uc3QgZmlsZUNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShmaWxlUGF0aCwgJ3V0Zi04Jyk7XG4gICAgICAgIGNvbnN0IHsgZGF0YTogbWF0dGVyRGF0YSB9ID0gbWF0dGVyKGZpbGVDb250ZW50KTtcblxuICAgICAgICBpZiAobWF0dGVyRGF0YS5oaWRkZW4pIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gXHU0RjdGXHU3NTI4XHU2NjIwXHU1QzA0XHU4ODY4XHU4M0I3XHU1M0Q2XHU2NjNFXHU3OTNBXHU1NDBEXHU3OUYwXG4gICAgICAgIGNvbnN0IGNhdGVnb3J5TmFtZSA9IENBVEVHT1JZX01BUFtjYXRlZ29yeUtleV0gfHwgY2F0ZWdvcnlLZXk7XG5cbiAgICAgICAgbGV0IGN1cnJlbnRMZXZlbDogU2lkZWJhckl0ZW1bXSA9IHNpZGViYXJbY2F0ZWdvcnlLZXldIHx8IFtdO1xuXG4gICAgICAgIGlmICghc2lkZWJhcltjYXRlZ29yeUtleV0pIHtcbiAgICAgICAgICAgIHNpZGViYXJbY2F0ZWdvcnlLZXldID0gY3VycmVudExldmVsO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gXHU5MDEyXHU1RjUyXHU2Nzg0XHU1RUZBXHU1QzQyXHU3RUE3XHU3RUQzXHU2Nzg0XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2VnbWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IHNlZ21lbnQgPSBzZWdtZW50c1tpXS5yZXBsYWNlKCcubWQnLCAnJyk7XG4gICAgICAgICAgICBjb25zdCBpc0xhc3QgPSBpID09PSBzZWdtZW50cy5sZW5ndGggLSAxO1xuXG4gICAgICAgICAgICAvLyBcdTRGRUVcdTY1MzlcdTk0RkVcdTYzQTVcdTc1MUZcdTYyMTBcdTkwM0JcdThGOTFcbiAgICAgICAgICAgIGxldCBsaW5rO1xuICAgICAgICAgICAgaWYgKGlzTGFzdCkge1xuICAgICAgICAgICAgICAgIC8vIFx1NEUzQVx1NjU4N1x1NEVGNlx1NzUxRlx1NjIxMFx1OTRGRVx1NjNBNVxuICAgICAgICAgICAgICAgIGxpbmsgPSBgLyR7c2VnbWVudHMuc2xpY2UoMCwgaSArIDEpLmpvaW4oJy8nKX1gLnJlcGxhY2UoL1xcLm1kJC8sICcnKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoaSA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGxpbmsgPSBgLyR7c2VnbWVudH1gO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBvcmRlciA9IGV4dHJhY3RPcmRlck51bWJlcihzZWdtZW50LCBtYXR0ZXJEYXRhKTsgLy8gXHU2M0QwXHU1M0Q2XHU2MzkyXHU1RThGXHU1M0Y3XG5cbiAgICAgICAgICAgIGlmIChpc0xhc3QpIHtcbiAgICAgICAgICAgICAgICAvLyBcdTZERkJcdTUyQTBcdTY3MDBcdTdFQzhcdTY1ODdcdTRFRjZcdTk4NzlcbiAgICAgICAgICAgICAgICBjb25zdCB0aXRsZSA9IGF3YWl0IGdldFRpdGxlRnJvbUZpbGUoZmlsZVBhdGgsIG1hdHRlckRhdGEpO1xuICAgICAgICAgICAgICAgIC8vIFx1NkRGQlx1NTJBMCBhY3RpdmVNYXRjaCBcdTRFRTVcdTY1MkZcdTYzMDFcdTY2RjRcdTdDQkVcdTc4NkVcdTc2ODRcdTlBRDhcdTRFQUVcdTUzMzlcdTkxNERcbiAgICAgICAgICAgICAgICBjb25zdCBhY3RpdmVNYXRjaCA9IGBeJHtsaW5rfSg/Oi98JClgO1xuICAgICAgICAgICAgICAgIGN1cnJlbnRMZXZlbC5wdXNoKHsgdGV4dDogdGl0bGUsIGxpbmssIG9yZGVyLCBhY3RpdmVNYXRjaCB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gXHU2N0U1XHU2MjdFXHU2MjE2XHU1MjFCXHU1RUZBXHU3NkVFXHU1RjU1XHU1MjA2XHU3RUM0XG4gICAgICAgICAgICAgICAgbGV0IGRpc3BsYXlUZXh0ID0gaSA9PT0gMCA/IGNhdGVnb3J5TmFtZSA6IHNlZ21lbnQ7XG5cbiAgICAgICAgICAgICAgICAvLyBcdTc5RkJcdTk2NjRcdTY1NzBcdTVCNTdcdTUyNERcdTdGMDBcbiAgICAgICAgICAgICAgICBkaXNwbGF5VGV4dCA9IGRpc3BsYXlUZXh0LnJlcGxhY2UoL15cXGQrLVxccyovLCAnJyk7XG5cbiAgICAgICAgICAgICAgICBsZXQgZ3JvdXAgPSBjdXJyZW50TGV2ZWwuZmluZChpdGVtID0+XG4gICAgICAgICAgICAgICAgICAgIChpID09PSAwICYmIGl0ZW0udGV4dCA9PT0gY2F0ZWdvcnlOYW1lKSB8fFxuICAgICAgICAgICAgICAgICAgICAoaSAhPT0gMCAmJiBpdGVtLnRleHQgPT09IGRpc3BsYXlUZXh0KVxuICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICBpZiAoIWdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGdyb3VwTGluayA9IGkgPT09IDAgPyBgLyR7c2VnbWVudH1gIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICBncm91cCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRleHQ6IGRpc3BsYXlUZXh0LFxuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbXM6IFtdLFxuICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZWQ6IGkgPiBERUZBVUxUX0NPTExBUFNFRF9JTkRFWF9NQVBbc2VnbWVudHNbMF1dLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gXHU0RTNBXHU3NkVFXHU1RjU1XHU2REZCXHU1MkEwXHU2RDNCXHU1MkE4XHU1MzM5XHU5MTREXHU2QTIxXHU1RjBGXG4gICAgICAgICAgICAgICAgICAgICAgICBhY3RpdmVNYXRjaDogYF4vJHtzZWdtZW50fSg/Oi98JClgLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGluazogZ3JvdXBMaW5rXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRMZXZlbC5wdXNoKGdyb3VwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY3VycmVudExldmVsID0gZ3JvdXAuaXRlbXMgfHwgW107XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBcdTVCRjlcdTZCQ0ZcdTRFMkFcdTVDNDJcdTdFQTdcdThGREJcdTg4NENcdTYzOTJcdTVFOEZcbiAgICBmb3IgKGNvbnN0IGtleSBpbiBzaWRlYmFyKSB7XG4gICAgICAgIHNvcnRTaWRlYmFySXRlbXMoc2lkZWJhcltrZXldKTtcbiAgICB9XG5cbiAgICAvLyBcdTc5RkJcdTk2NjRcdTdCMkNcdTRFMDBcdTdFQTdcdUZGMENcdTVDMDZcdTZCQ0ZcdTRFMDBcdTRFMkFcdTdCMkNcdTRFMDBcdTdFQTdcdTRFMkRcdTc2ODRpdGVtc1x1NUU3M1x1OTRGQVx1NTIzMFx1NEUwMFx1N0VBN1xuICAgIGNvbnN0IHNpZGViYXJGbGF0OiBSZWNvcmQ8c3RyaW5nLCBTaWRlYmFySXRlbVtdPiA9IHt9O1xuICAgIGZvciAoY29uc3Qga2V5IGluIHNpZGViYXIpIHtcbiAgICAgICAgc2lkZWJhckZsYXRba2V5XSA9IFtdO1xuICAgICAgICBzaWRlYmFyW2tleV0uZm9yRWFjaChpdGVtID0+IHtcbiAgICAgICAgICAgIGlmIChpdGVtLml0ZW1zKSB7XG4gICAgICAgICAgICAgICAgc2lkZWJhckZsYXRba2V5XS5wdXNoKC4uLml0ZW0uaXRlbXMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzaWRlYmFyRmxhdFtrZXldLnB1c2goaXRlbSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIFx1NTkwNFx1NzQwNndpa2lcbiAgICBjb25zdCB3aWtpID0gZ2VuZXJhdGVXaWtpU2lkZWJhcihwYXRoLmpvaW4ocHJvY2Vzcy5jd2QoKSwgJ2RvY3MnKSwgcGF0aC5qb2luKHByb2Nlc3MuY3dkKCksICdkb2NzL3dpa2knKSk7XG4gICAgY29uc3Qgd2lraVNpZGViYXI6IFNpZGViYXJJdGVtW10gPSBbXTtcbiAgICB3aWtpLmZvckVhY2goaXRlbSA9PiB7XG4gICAgICAgIGlmIChpdGVtLmRhdGEuY2F0ZWdvcmllcykge1xuICAgICAgICAgICAgLy8gXHU0RTAwXHU3RUE3XHU1OTI3XHU1MjA2XHU3QzdCXG5cbiAgICAgICAgICAgIC8vIFx1NEU4Q1x1N0VBN1x1NTIwNlx1N0M3QlxuICAgICAgICAgICAgY29uc3Qgc2Vjb25kVXJsczogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgICAgIGNvbnN0IHNlY29uZCA9IGl0ZW0uZGF0YS5jYXRlZ29yaWVzLm1hcCgoY2F0ZWdvcnk6IGFueSkgPT4geztcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICB0ZXh0OiBjYXRlZ29yeS50aXRsZSxcbiAgICAgICAgICAgICAgICAgICAgY29sbGFwc2VkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgaXRlbXM6IGl0ZW0uY2hpbGRyZW5cbiAgICAgICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoY2hpbGQgPT4gY2hpbGQuZGF0YS5jYXRlZ29yeSA9PT0gY2F0ZWdvcnkudGl0bGUpXG4gICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKGNoaWxkID0+IGNoaWxkLmxpbmspXG4gICAgICAgICAgICAgICAgICAgICAgICAubWFwKGNoaWxkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWNvbmRVcmxzLnB1c2goY2hpbGQubGluayk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dDogY2hpbGQudGV4dCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluazogY2hpbGQubGluayxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWN0aXZlTWF0Y2g6IGNoaWxkLmFjdGl2ZU1hdGNoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIC8vIFx1NTMzOVx1OTE0RFx1NTIzMFx1NEUwMFx1N0VBN1x1NEY0Nlx1NjYyRlx1NjcyQVx1NTMzOVx1OTE0RFx1NTIzMFx1NEU4Q1x1N0VBN1xuICAgICAgICAgICAgY29uc3Qgbm90TWF0Y2hlZCA9IGl0ZW0uY2hpbGRyZW5cbiAgICAgICAgICAgICAgICAuZmlsdGVyKGNoaWxkID0+ICFzZWNvbmRVcmxzLmluY2x1ZGVzKGNoaWxkLmxpbmspKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoY2hpbGQgPT4gY2hpbGQubGluaylcbiAgICAgICAgICAgICAgICAubWFwKGNoaWxkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRleHQ6IGNoaWxkLnRleHQsXG4gICAgICAgICAgICAgICAgICAgICAgICBsaW5rOiBjaGlsZC5saW5rLFxuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aXZlTWF0Y2g6IGNoaWxkLmFjdGl2ZU1hdGNoXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgd2lraVNpZGViYXIucHVzaCh7XG4gICAgICAgICAgICAgICAgdGV4dDogaXRlbS5kYXRhLnRpdGxlLFxuICAgICAgICAgICAgICAgIGNvbGxhcHNlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBpdGVtczogWy4uLnNlY29uZCwgLi4ubm90TWF0Y2hlZF1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gXHU0RTAwXHU3RUE3XHU1OTI3XHU1MjA2XHU3QzdCXG4gICAgICAgICAgICB3aWtpU2lkZWJhci5wdXNoKHtcbiAgICAgICAgICAgICAgICB0ZXh0OiBpdGVtLnRleHQsXG4gICAgICAgICAgICAgICAgY29sbGFwc2VkOiB0cnVlLFxuICAgICAgICAgICAgICAgIGl0ZW1zOiBpdGVtLmNoaWxkcmVuXG4gICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoY2hpbGQgPT4gY2hpbGQubGluaylcbiAgICAgICAgICAgICAgICAgICAgLm1hcChjaGlsZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHQ6IGNoaWxkLnRleHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluazogY2hpbGQubGluayxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3RpdmVNYXRjaDogY2hpbGQuYWN0aXZlTWF0Y2hcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfSk7XG4gICAgLy8gXHU2REZCXHU1MkEwIHdpa2lcbiAgICBzaWRlYmFyRmxhdFsnd2lraSddID0gd2lraVNpZGViYXI7XG5cbiAgICByZXR1cm4gc2lkZWJhckZsYXQ7XG59XG5cbi8qKlxuICogXHU5MDEyXHU1RjUyXHU2MzkyXHU1RThGXHU0RkE3XHU4RkI5XHU2ODBGXHU5ODc5XHU3NkVFXG4gKi9cbmZ1bmN0aW9uIHNvcnRTaWRlYmFySXRlbXMoaXRlbXM6IFNpZGViYXJJdGVtW10pOiB2b2lkIHtcbiAgICAvLyBcdTY4MzlcdTYzNkUgb3JkZXIgXHU1QjU3XHU2QkI1XHU2MzkyXHU1RThGXG4gICAgaXRlbXMuc29ydCgoYSwgYikgPT4ge1xuICAgICAgICBjb25zdCBvcmRlckEgPSBhLm9yZGVyID8/IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSO1xuICAgICAgICBjb25zdCBvcmRlckIgPSBiLm9yZGVyID8/IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSO1xuICAgICAgICByZXR1cm4gb3JkZXJBIC0gb3JkZXJCO1xuICAgIH0pO1xuXG4gICAgLy8gXHU5MDEyXHU1RjUyXHU2MzkyXHU1RThGXHU1QjUwXHU5ODc5XG4gICAgaXRlbXMuZm9yRWFjaChpdGVtID0+IHtcbiAgICAgICAgaWYgKGl0ZW0uaXRlbXMgJiYgaXRlbS5pdGVtcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBzb3J0U2lkZWJhckl0ZW1zKGl0ZW0uaXRlbXMpO1xuICAgICAgICB9XG4gICAgfSk7XG59XG5cbi8qKlxuICogXHU0RUNFXHU2NTg3XHU0RUY2IEZyb250bWF0dGVyIFx1NjIxNlx1NjU4N1x1NEVGNlx1NTQwRFx1NjNEMFx1NTNENlx1NjgwN1x1OTg5OFxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRUaXRsZUZyb21GaWxlKGZpbGVQYXRoOiBzdHJpbmcsIG1hdHRlckRhdGE6IGFueSk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKG1hdHRlckRhdGEudGl0bGUpIHtcbiAgICAgICAgcmV0dXJuIG1hdHRlckRhdGEudGl0bGUudHJpbSgpLnJlcGxhY2UoL1snXCJdL2csICcnKTtcbiAgICB9XG4gICAgLy8gXHU1OTgyXHU2NzlDXHU2Q0ExXHU2NzA5IGZyb250bWF0dGVyIHRpdGxlXHVGRjBDXHU0RUNFXHU2NTg3XHU0RUY2XHU1NDBEXHU4M0I3XHU1M0Q2XG4gICAgY29uc3QgYmFzZW5hbWUgPSBwYXRoLmJhc2VuYW1lKGZpbGVQYXRoLCAnLm1kJyk7XG4gICAgLy8gXHU2NjZFXHU5MDFBXHU2NTg3XHU0RUY2XHVGRjBDXHU3OUZCXHU5NjY0XHU2NTcwXHU1QjU3XHU1MjREXHU3RjAwXHU1NDhDXHU4RkRFXHU1QjU3XHU3QjI2XG4gICAgcmV0dXJuIGJhc2VuYW1lLnJlcGxhY2UoL15cXGQrLVxccyovLCAnJykucmVwbGFjZSgvLS9nLCAnICcpO1xufVxuXG5leHBvcnQgZGVmYXVsdCBnZW5lcmF0ZVNpZGViYXI7XG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9Vc2Vycy9mYW5neWl6aG91L0RvY3VtZW50cy9jb2RpbmcvbmV0ZWFzZS1tb2RzZGstd2lraS9zY3JpcHRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvVXNlcnMvZmFuZ3lpemhvdS9Eb2N1bWVudHMvY29kaW5nL25ldGVhc2UtbW9kc2RrLXdpa2kvc2NyaXB0cy9zaWRlYmFyLXdpa2kudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL1VzZXJzL2Zhbmd5aXpob3UvRG9jdW1lbnRzL2NvZGluZy9uZXRlYXNlLW1vZHNkay13aWtpL3NjcmlwdHMvc2lkZWJhci13aWtpLnRzXCI7aW1wb3J0IGZzIGZyb20gJ2ZzJ1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCdcbmltcG9ydCBtYXR0ZXIgZnJvbSAnZ3JheS1tYXR0ZXInXG5pbXBvcnQgZmV0Y2ggZnJvbSAnbm9kZS1mZXRjaCdcblxuY29uc3QgYmFzZVVybCA9ICcvJ1xuXG4vLyBkZWZpbmUgd2hldGhlciBiaWcgcGFnZXMgc2hvdWxkIGJlIGJ1aWx0LlxuLy8gZmFzdEJ1aWxkIHNob3VsZCBvbmx5IGJlIHVzZWQgd2hlbiB0ZXN0aW5nLCBzaW5jZSBpdCB3aWxsIG5vdCBjb21waWxlIHNvbWUgb2YgdGhlIHdpa2lzIGNvbnRlbnQuXG5jb25zdCBleGNsdWRlRmlsZXMgPSBbXG4gICAgJ2VudGl0aWVzL3ZhbmlsbGEtdXNhZ2UtY29tcG9uZW50cy5tZCcsXG4gICAgJ2VudGl0aWVzL3ZhbmlsbGEtdXNhZ2Utc3Bhd24tcnVsZXMubWQnLFxuICAgICdlbnRpdGllcy92dWMtZnVsbC5tZCcsXG4gICAgJ2VudGl0aWVzL3Z1c3ItZnVsbC5tZCcsXG5dXG5cbmNvbnN0IGZhc3RCdWlsZCA9IHByb2Nlc3MuZW52LmZhc3RCdWlsZCA9PT0gJ3RydWUgJyAvLyBTUEFDRSBoYXMgdG8gYmUgdGhlcmUsIHNpbmNlIHRoZSBTRVQgdmFyPXZhbCBjb21tYW5kIGFkZHMgYSBzcGFjZSBhdCB0aGUgZW5kIVxuXG5pZiAoZmFzdEJ1aWxkICYmIHByb2Nlc3MuZW52Lk5PREVfRU5WID09ICdwcm9kdWN0aW9uJykge1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBgXFxuSU5GTzogZmFzdEJ1aWxkIHNlbGVjdGVkLiB0aGUgZmlsZXM6XFxuJHtKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgIGV4Y2x1ZGVGaWxlcyxcbiAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICA0XG4gICAgICAgICl9XFxud2lsbCBub3QgYmUgY29tcGlsZWQhXFxuYFxuICAgIClcbn1cblxuZnVuY3Rpb24gZm9ybWF0TGluayhwYXRoOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gcGF0aC5zcGxpdCgvXFxcXHxcXC8vZykuam9pbignLycpLnJlcGxhY2UoJy5tZCcsICcnKVxufVxuXG4vKlxuR2V0cyB0aGUgY2F0ZWdvcmllcyBmcm9tIHdpdGhpbiB0aGUgZnJvbnRtYXR0ZXIgb2YgYW4gaW5kZXgubWQgZmlsZSwgYW5kIHJldHVybnMgdGhlbSBhcyBsaXN0LlxuICovXG5mdW5jdGlvbiBnZXRDYXRlZ29yeU9yZGVyKGZyb250TWF0dGVyOiBtYXR0ZXIuR3JheU1hdHRlckZpbGU8c3RyaW5nPikge1xuICAgIGNvbnN0IGRhdGE6IHsgW0tleTogc3RyaW5nXTogbnVtYmVyIH0gPSB7fVxuICAgIGlmICghZnJvbnRNYXR0ZXIuZGF0YS5jYXRlZ29yaWVzKSB7XG4gICAgICAgIHJldHVybiBkYXRhXG4gICAgfVxuXG4gICAgZnJvbnRNYXR0ZXIuZGF0YS5jYXRlZ29yaWVzLmZvckVhY2goZnVuY3Rpb24gKFxuICAgICAgICBjYXRlZ29yeTogeyB0aXRsZTogc3RyaW5nIHwgbnVtYmVyIH0sXG4gICAgICAgIGluZGV4OiBudW1iZXJcbiAgICApIHtcbiAgICAgICAgZGF0YVtjYXRlZ29yeS50aXRsZV0gPSBpbmRleCArIDFcbiAgICB9KVxuXG4gICAgcmV0dXJuIGRhdGFcbn1cblxuZnVuY3Rpb24gZ2V0Q2F0ZWdvcmllcyhmcm9udE1hdHRlcjogbWF0dGVyLkdyYXlNYXR0ZXJGaWxlPHN0cmluZz4pIHtcbiAgICBjb25zdCBkYXRhOiB7XG4gICAgICAgIHRleHQ6IGFueVxuICAgICAgICBkYXRhOiBhbnlcbiAgICAgICAgdGFnczogYW55XG4gICAgICAgIHByZWZpeDogYW55XG4gICAgICAgIHNlY3Rpb246IGJvb2xlYW5cbiAgICAgICAgY29sb3I6IGFueVxuICAgICAgICBsaW5rOiBzdHJpbmdcbiAgICAgICAgYWN0aXZlTWF0Y2g6IHN0cmluZ1xuICAgIH1bXSA9IFtdXG4gICAgaWYgKCFmcm9udE1hdHRlci5kYXRhLmNhdGVnb3JpZXMpIHtcbiAgICAgICAgcmV0dXJuIGRhdGFcbiAgICB9XG5cbiAgICBmcm9udE1hdHRlci5kYXRhLmNhdGVnb3JpZXMuZm9yRWFjaChmdW5jdGlvbiAoXG4gICAgICAgIGNhdGVnb3J5OiB7XG4gICAgICAgICAgICBuYXZfb3JkZXI6IG51bWJlclxuICAgICAgICAgICAgY2F0ZWdvcnk6IGFueVxuICAgICAgICAgICAgdGl0bGU6IGFueVxuICAgICAgICAgICAgdGFnczogYW55XG4gICAgICAgICAgICBwcmVmaXg6IGFueVxuICAgICAgICAgICAgY29sb3I6IGFueVxuICAgICAgICB9LFxuICAgICAgICBpbmRleDogYW55XG4gICAgKSB7XG4gICAgICAgIGNhdGVnb3J5Lm5hdl9vcmRlciA9IC0xXG4gICAgICAgIGNhdGVnb3J5LmNhdGVnb3J5ID0gY2F0ZWdvcnkudGl0bGVcbiAgICAgICAgZGF0YS5wdXNoKHtcbiAgICAgICAgICAgIHRleHQ6IGNhdGVnb3J5LnRpdGxlLFxuICAgICAgICAgICAgZGF0YTogY2F0ZWdvcnksXG4gICAgICAgICAgICB0YWdzOiBjYXRlZ29yeS50YWdzLFxuICAgICAgICAgICAgcHJlZml4OiBjYXRlZ29yeS5wcmVmaXgsXG4gICAgICAgICAgICBzZWN0aW9uOiB0cnVlLFxuICAgICAgICAgICAgY29sb3I6IGNhdGVnb3J5LmNvbG9yLFxuICAgICAgICAgICAgbGluazogJycsXG4gICAgICAgICAgICBhY3RpdmVNYXRjaDogJyAnLFxuICAgICAgICB9KVxuICAgIH0pXG5cbiAgICByZXR1cm4gZGF0YVxufVxuXG5sZXQgb3JkZXI6IHsgW0tleTogc3RyaW5nXTogbnVtYmVyIH1cblxuLypcblJlY3Vyc2l2ZWx5IGdlbmVyYXRlIHRoZSBuYXZpZ2F0aW9uIGxpbmtzIGZvciB0aGUgc2lkZWJhci5cbiovXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVXaWtpU2lkZWJhcihiYXNlOiBzdHJpbmcsIGRpcjogc3RyaW5nKSB7XG4gICAgY29uc3QgZGF0YToge1xuICAgICAgICB0ZXh0OiBhbnlcbiAgICAgICAgZGF0YTogeyBba2V5OiBzdHJpbmddOiBhbnkgfVxuICAgICAgICBjaGlsZHJlbj86IGFueVxuICAgICAgICB0YWdzPzogYW55XG4gICAgICAgIHByZWZpeD86IGFueVxuICAgICAgICBzZWN0aW9uPzogYW55XG4gICAgICAgIGNvbG9yPzogYW55XG4gICAgICAgIGxpbms/OiBzdHJpbmdcbiAgICAgICAgYWN0aXZlTWF0Y2g/OiBzdHJpbmdcbiAgICB9W10gPSBbXVxuICAgIGNvbnN0IGZpbGVzID0gZnMucmVhZGRpclN5bmMoZGlyKVxuXG4gICAgZmlsZXMuZm9yRWFjaChmdW5jdGlvbiAoZmlsZSkge1xuICAgICAgICBsZXQgam9pbmVkUGF0aCA9IHBhdGguam9pbihkaXIsIGZpbGUpXG4gICAgICAgIGNvbnN0IHN0YXRzID0gZnMuc3RhdFN5bmMoam9pbmVkUGF0aClcbiAgICAgICAgLy8gSGFuZGxlIHRvcCBsZXZlbCBkaXJlY3Rvcmllc1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICBzdGF0cy5pc0RpcmVjdG9yeSgpICYmXG4gICAgICAgICAgICBmcy5leGlzdHNTeW5jKHBhdGguam9pbihqb2luZWRQYXRoLCAnaW5kZXgubWQnKSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCBzdHIgPSBmcy5yZWFkRmlsZVN5bmMoXG4gICAgICAgICAgICAgICAgcGF0aC5qb2luKGpvaW5lZFBhdGgsICdpbmRleC5tZCcpLFxuICAgICAgICAgICAgICAgICd1dGY4J1xuICAgICAgICAgICAgKVxuICAgICAgICAgICAgbGV0IGZyb250TWF0dGVyXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGZyb250TWF0dGVyID0gbWF0dGVyKHN0cilcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBqb2luZWRQYXRoID0gcGF0aC5yZWxhdGl2ZShcbiAgICAgICAgICAgICAgICAgICAgcHJvY2Vzcy5jd2QoKSxcbiAgICAgICAgICAgICAgICAgICAgcGF0aC5qb2luKGpvaW5lZFBhdGgsICdpbmRleC5tZCcpXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgICAgICAgIGA6OmVycm9yIGZpbGU9JHtqb2luZWRQYXRofSxsaW5lPTEsY29sPTE6OkZpbGUgJHtqb2luZWRQYXRofSBoYXMgaW52YWxpZCBmcm9udG1hdHRlciEgJHtlLm1lc3NhZ2V9YFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgICAgICAgICAgICAgYEZpbGUgJHtqb2luZWRQYXRofSBoYXMgaW52YWxpZCBmcm9udG1hdHRlciEgJHtlLm1lc3NhZ2V9YFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3JkZXIgPSBnZXRDYXRlZ29yeU9yZGVyKGZyb250TWF0dGVyKVxuXG4gICAgICAgICAgICBjb25zdCBjaGlsZHJlbiA9IGdlbmVyYXRlV2lraVNpZGViYXIoYmFzZSwgam9pbmVkUGF0aCkuY29uY2F0KFxuICAgICAgICAgICAgICAgIGdldENhdGVnb3JpZXMoZnJvbnRNYXR0ZXIpXG4gICAgICAgICAgICApXG5cbiAgICAgICAgICAgIGNoaWxkcmVuLnNvcnQoXG4gICAgICAgICAgICAgICAgKFxuICAgICAgICAgICAgICAgICAgICB7IGRhdGE6IGRhdGFBLCB0ZXh0OiB0ZXh0QSB9LFxuICAgICAgICAgICAgICAgICAgICB7IGRhdGE6IGRhdGFCLCB0ZXh0OiB0ZXh0QiB9XG4gICAgICAgICAgICAgICAgKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8vIERlZmF1bHQgdG8gbWF4IGludCwgc28gd2l0aG91dCBuYXYgb3JkZXIgeW91IHdpbGwgc2hvdyBzZWNvbmRcbiAgICAgICAgICAgICAgICAgICAgLy8gTXVsdGlwbHkgYnkgY2F0ZWdvcnkgdmFsdWUgaWYgaXQgZXhpc3RzXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG5hdkEgPVxuICAgICAgICAgICAgICAgICAgICAgICAgKGRhdGFBLm5hdl9vcmRlciB8fCA1MCkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgKG9yZGVyW2RhdGFBLmNhdGVnb3J5XSB8fCAwKSAqIDEwMCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbmF2QiA9XG4gICAgICAgICAgICAgICAgICAgICAgICAoZGF0YUIubmF2X29yZGVyIHx8IDUwKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAob3JkZXJbZGF0YUIuY2F0ZWdvcnldIHx8IDApICogMTAwIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUlxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFRpZSBnb2VzIHRvIHRoZSB0ZXh0IGNvbXBhcmUhIChXaWxsIGFsc28gYXBwbHkgZm9yIGVsZW1lbnRzIHdpdGhvdXQgbmF2IG9yZGVyKVxuICAgICAgICAgICAgICAgICAgICBpZiAobmF2QSA9PSBuYXZCKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGV4dEEubG9jYWxlQ29tcGFyZSh0ZXh0QilcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFJldHVybiBuYXYgb3JkZXJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5hdkEgLSBuYXZCXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgZGF0YS5wdXNoKHtcbiAgICAgICAgICAgICAgICB0ZXh0OiBmcm9udE1hdHRlci5kYXRhLnRpdGxlLFxuICAgICAgICAgICAgICAgIGRhdGE6IGZyb250TWF0dGVyLmRhdGEsXG4gICAgICAgICAgICAgICAgY2hpbGRyZW46IGNoaWxkcmVuLFxuICAgICAgICAgICAgfSlcblxuICAgICAgICAgICAgaWYgKGZyb250TWF0dGVyLmRhdGEudGl0bGUgPT09IHZvaWQgMCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgJ0ZpbGUgJyArXG4gICAgICAgICAgICAgICAgICAgIHBhdGguam9pbihqb2luZWRQYXRoLCAnaW5kZXgubWQnKSArXG4gICAgICAgICAgICAgICAgICAgICcgaGFzIGludmFsaWQgZnJvbnRtYXR0ZXIhJ1xuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEhhbmRsZSB0aGUgbm9ybWFsIGZpbGVzXG4gICAgICAgIGVsc2UgaWYgKHN0YXRzLmlzRmlsZSgpKSB7XG4gICAgICAgICAgICAvLyBEb24ndCBpbmNsdWRlIG5vbi1tYXJrZG93biBmaWxlcywgb3IgdGhlIGluZGV4IHBhZ2UgaXRzZWxmXG4gICAgICAgICAgICBpZiAoIWZpbGUuZW5kc1dpdGgoJy5tZCcpIHx8IGZpbGUuZW5kc1dpdGgoJ2luZGV4Lm1kJykpIHJldHVyblxuXG4gICAgICAgICAgICBjb25zdCBzdHIgPSBmcy5yZWFkRmlsZVN5bmMoam9pbmVkUGF0aCwgJ3V0ZjgnKVxuICAgICAgICAgICAgbGV0IGZyb250TWF0dGVyXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGZyb250TWF0dGVyID0gbWF0dGVyKHN0cilcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBqb2luZWRQYXRoID0gcGF0aC5yZWxhdGl2ZShwcm9jZXNzLmN3ZCgpLCBqb2luZWRQYXRoKVxuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgICAgICAgIGA6OmVycm9yIGZpbGU9JHtqb2luZWRQYXRofSxsaW5lPTEsY29sPTE6OkZpbGUgJHtqb2luZWRQYXRofSBoYXMgaW52YWxpZCBmcm9udG1hdHRlciEgJHtlLm1lc3NhZ2V9YFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgICAgICAgICAgICAgYEZpbGUgJHtqb2luZWRQYXRofSBoYXMgaW52YWxpZCBmcm9udG1hdHRlciEgJHtlLm1lc3NhZ2V9YFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGxpbmsgPSBmb3JtYXRMaW5rKGpvaW5lZFBhdGgudG9TdHJpbmcoKS5yZXBsYWNlKGJhc2UsICcnKSlcblxuICAgICAgICAgICAgLy8gRG9uJ3QgaW5jbHVkZSBoaWRkZW4gcGFnZXMgKGlnbm9yZXMgY2hpbGRyZW4pXG4gICAgICAgICAgICBpZiAoZnJvbnRNYXR0ZXIuZGF0YS5oaWRkZW4gPT09IHRydWUpIHJldHVyblxuXG4gICAgICAgICAgICBsZXQgcHJlZml4ID0gbnVsbFxuXG4gICAgICAgICAgICBpZiAoZnJvbnRNYXR0ZXIuZGF0YS5wcmVmaXggIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHByZWZpeCA9IGZyb250TWF0dGVyLmRhdGEucHJlZml4XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCB0YWdzID0gbnVsbFxuXG4gICAgICAgICAgICBpZiAoZnJvbnRNYXR0ZXIuZGF0YS50YWdzICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICB0YWdzID0gZnJvbnRNYXR0ZXIuZGF0YS50YWdzXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkYXRhLnB1c2goe1xuICAgICAgICAgICAgICAgIHRleHQ6IGZyb250TWF0dGVyLmRhdGEudGl0bGUsXG4gICAgICAgICAgICAgICAgZGF0YTogZnJvbnRNYXR0ZXIuZGF0YSxcbiAgICAgICAgICAgICAgICB0YWdzOiB0YWdzLFxuICAgICAgICAgICAgICAgIHByZWZpeDogcHJlZml4LFxuICAgICAgICAgICAgICAgIHNlY3Rpb246IGZyb250TWF0dGVyLmRhdGEuc2VjdGlvbiB8fCBmYWxzZSxcbiAgICAgICAgICAgICAgICBjb2xvcjogZnJvbnRNYXR0ZXIuZGF0YS5jb2xvciB8fCAnbm9uZScsXG4gICAgICAgICAgICAgICAgbGluayxcbiAgICAgICAgICAgICAgICBhY3RpdmVNYXRjaDogYF4ke2xpbmt9YCxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICBpZiAoZnJvbnRNYXR0ZXIuZGF0YS50aXRsZSA9PT0gdm9pZCAwKSB7XG4gICAgICAgICAgICAgICAgam9pbmVkUGF0aCA9IHBhdGgucmVsYXRpdmUocHJvY2Vzcy5jd2QoKSwgam9pbmVkUGF0aClcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAgICAgYDo6ZXJyb3IgZmlsZT0ke2pvaW5lZFBhdGh9LGxpbmU9MSxjb2w9MTo6RmlsZSAke2pvaW5lZFBhdGh9IGhhcyBpbnZhbGlkIGZyb250bWF0dGVyIWBcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBGaWxlICR7am9pbmVkUGF0aH0gaGFzIGludmFsaWQgZnJvbnRtYXR0ZXIhYClcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0pXG5cbiAgICByZXR1cm4gZGF0YS5zb3J0KFxuICAgICAgICAoeyBkYXRhOiBkYXRhQSwgdGV4dDogdGV4dEEgfSwgeyBkYXRhOiBkYXRhQiwgdGV4dDogdGV4dEIgfSkgPT4ge1xuICAgICAgICAgICAgLy8gRGVmYXVsdCB0byBtYXggaW50LCBzbyB3aXRob3V0IG5hdiBvcmRlciB5b3Ugd2lsbCBzaG93IHNlY29uZFxuICAgICAgICAgICAgLy8gTXVsdGlwbHkgYnkgY2F0ZWdvcnkgdmFsdWUgaWYgaXQgZXhpc3RzXG4gICAgICAgICAgICBjb25zdCBuYXZBID1cbiAgICAgICAgICAgICAgICAoZGF0YUEubmF2X29yZGVyIHx8IDUwKSArIChvcmRlcltkYXRhQS5jYXRlZ29yeV0gfHwgMCkgKiAxMDAgfHxcbiAgICAgICAgICAgICAgICBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUlxuICAgICAgICAgICAgY29uc3QgbmF2QiA9XG4gICAgICAgICAgICAgICAgKGRhdGFCLm5hdl9vcmRlciB8fCA1MCkgKyAob3JkZXJbZGF0YUIuY2F0ZWdvcnldIHx8IDApICogMTAwIHx8XG4gICAgICAgICAgICAgICAgTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVJcblxuICAgICAgICAgICAgLy8gVGllIGdvZXMgdG8gdGhlIHRleHQgY29tcGFyZSEgKFdpbGwgYWxzbyBhcHBseSBmb3IgZWxlbWVudHMgd2l0aG91dCBuYXYgb3JkZXIpXG4gICAgICAgICAgICBpZiAobmF2QSA9PSBuYXZCKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRleHRBLmxvY2FsZUNvbXBhcmUodGV4dEIpXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFJldHVybiBuYXYgb3JkZXJcbiAgICAgICAgICAgIHJldHVybiBuYXZBIC0gbmF2QlxuICAgICAgICB9XG4gICAgKVxufSJdLAogICJtYXBwaW5ncyI6ICI7QUFDQSxTQUFTLGVBQWUsV0FBVzs7O0FDRGlVLE9BQU9BLFNBQVE7QUFDblgsT0FBT0MsV0FBVTtBQUNqQixPQUFPLFFBQVE7QUFDZixPQUFPQyxhQUFZOzs7QUNIMlYsT0FBTyxRQUFRO0FBQzdYLE9BQU8sVUFBVTtBQUNqQixPQUFPLFlBQVk7QUFPbkIsSUFBTSxlQUFlO0FBQUEsRUFDakI7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFDSjtBQUVBLElBQU0sWUFBWSxRQUFRLElBQUksY0FBYztBQUU1QyxJQUFJLGFBQWEsUUFBUSxJQUFJLFlBQVksY0FBYztBQUNuRCxVQUFRO0FBQUEsSUFDSjtBQUFBO0FBQUEsRUFBMkMsS0FBSztBQUFBLE1BQzVDO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxJQUNKLENBQUM7QUFBQTtBQUFBO0FBQUEsRUFDTDtBQUNKO0FBRUEsU0FBUyxXQUFXQyxPQUFjO0FBQzlCLFNBQU9BLE1BQUssTUFBTSxRQUFRLEVBQUUsS0FBSyxHQUFHLEVBQUUsUUFBUSxPQUFPLEVBQUU7QUFDM0Q7QUFLQSxTQUFTLGlCQUFpQixhQUE0QztBQUNsRSxRQUFNLE9BQWtDLENBQUM7QUFDekMsTUFBSSxDQUFDLFlBQVksS0FBSyxZQUFZO0FBQzlCLFdBQU87QUFBQSxFQUNYO0FBRUEsY0FBWSxLQUFLLFdBQVcsUUFBUSxTQUNoQyxVQUNBLE9BQ0Y7QUFDRSxTQUFLLFNBQVMsS0FBSyxJQUFJLFFBQVE7QUFBQSxFQUNuQyxDQUFDO0FBRUQsU0FBTztBQUNYO0FBRUEsU0FBUyxjQUFjLGFBQTRDO0FBQy9ELFFBQU0sT0FTQSxDQUFDO0FBQ1AsTUFBSSxDQUFDLFlBQVksS0FBSyxZQUFZO0FBQzlCLFdBQU87QUFBQSxFQUNYO0FBRUEsY0FBWSxLQUFLLFdBQVcsUUFBUSxTQUNoQyxVQVFBLE9BQ0Y7QUFDRSxhQUFTLFlBQVk7QUFDckIsYUFBUyxXQUFXLFNBQVM7QUFDN0IsU0FBSyxLQUFLO0FBQUEsTUFDTixNQUFNLFNBQVM7QUFBQSxNQUNmLE1BQU07QUFBQSxNQUNOLE1BQU0sU0FBUztBQUFBLE1BQ2YsUUFBUSxTQUFTO0FBQUEsTUFDakIsU0FBUztBQUFBLE1BQ1QsT0FBTyxTQUFTO0FBQUEsTUFDaEIsTUFBTTtBQUFBLE1BQ04sYUFBYTtBQUFBLElBQ2pCLENBQUM7QUFBQSxFQUNMLENBQUM7QUFFRCxTQUFPO0FBQ1g7QUFFQSxJQUFJO0FBS0csU0FBUyxvQkFBb0IsTUFBYyxLQUFhO0FBQzNELFFBQU0sT0FVQSxDQUFDO0FBQ1AsUUFBTSxRQUFRLEdBQUcsWUFBWSxHQUFHO0FBRWhDLFFBQU0sUUFBUSxTQUFVLE1BQU07QUFDMUIsUUFBSSxhQUFhLEtBQUssS0FBSyxLQUFLLElBQUk7QUFDcEMsVUFBTSxRQUFRLEdBQUcsU0FBUyxVQUFVO0FBRXBDLFFBQ0ksTUFBTSxZQUFZLEtBQ2xCLEdBQUcsV0FBVyxLQUFLLEtBQUssWUFBWSxVQUFVLENBQUMsR0FDakQ7QUFDRSxZQUFNLE1BQU0sR0FBRztBQUFBLFFBQ1gsS0FBSyxLQUFLLFlBQVksVUFBVTtBQUFBLFFBQ2hDO0FBQUEsTUFDSjtBQUNBLFVBQUk7QUFDSixVQUFJO0FBQ0Esc0JBQWMsT0FBTyxHQUFHO0FBQUEsTUFDNUIsU0FBUyxHQUFHO0FBQ1IscUJBQWEsS0FBSztBQUFBLFVBQ2QsUUFBUSxJQUFJO0FBQUEsVUFDWixLQUFLLEtBQUssWUFBWSxVQUFVO0FBQUEsUUFDcEM7QUFDQSxnQkFBUTtBQUFBO0FBQUEsVUFFSixnQkFBZ0IsVUFBVSx1QkFBdUIsVUFBVSw2QkFBNkIsRUFBRSxPQUFPO0FBQUEsUUFDckc7QUFDQSxjQUFNLElBQUk7QUFBQTtBQUFBLFVBRU4sUUFBUSxVQUFVLDZCQUE2QixFQUFFLE9BQU87QUFBQSxRQUM1RDtBQUFBLE1BQ0o7QUFFQSxjQUFRLGlCQUFpQixXQUFXO0FBRXBDLFlBQU0sV0FBVyxvQkFBb0IsTUFBTSxVQUFVLEVBQUU7QUFBQSxRQUNuRCxjQUFjLFdBQVc7QUFBQSxNQUM3QjtBQUVBLGVBQVM7QUFBQSxRQUNMLENBQ0ksRUFBRSxNQUFNLE9BQU8sTUFBTSxNQUFNLEdBQzNCLEVBQUUsTUFBTSxPQUFPLE1BQU0sTUFBTSxNQUMxQjtBQUdELGdCQUFNLFFBQ0QsTUFBTSxhQUFhLE9BQ25CLE1BQU0sTUFBTSxRQUFRLEtBQUssS0FBSyxPQUMvQixPQUFPO0FBQ1gsZ0JBQU0sUUFDRCxNQUFNLGFBQWEsT0FDbkIsTUFBTSxNQUFNLFFBQVEsS0FBSyxLQUFLLE9BQy9CLE9BQU87QUFHWCxjQUFJLFFBQVEsTUFBTTtBQUNkLG1CQUFPLE1BQU0sY0FBYyxLQUFLO0FBQUEsVUFDcEM7QUFHQSxpQkFBTyxPQUFPO0FBQUEsUUFDbEI7QUFBQSxNQUNKO0FBQ0EsV0FBSyxLQUFLO0FBQUEsUUFDTixNQUFNLFlBQVksS0FBSztBQUFBLFFBQ3ZCLE1BQU0sWUFBWTtBQUFBLFFBQ2xCO0FBQUEsTUFDSixDQUFDO0FBRUQsVUFBSSxZQUFZLEtBQUssVUFBVSxRQUFRO0FBQ25DLGNBQU0sSUFBSTtBQUFBLFVBQ04sVUFDQSxLQUFLLEtBQUssWUFBWSxVQUFVLElBQ2hDO0FBQUEsUUFDSjtBQUFBLE1BQ0o7QUFBQSxJQUNKLFdBR1MsTUFBTSxPQUFPLEdBQUc7QUFFckIsVUFBSSxDQUFDLEtBQUssU0FBUyxLQUFLLEtBQUssS0FBSyxTQUFTLFVBQVUsRUFBRztBQUV4RCxZQUFNLE1BQU0sR0FBRyxhQUFhLFlBQVksTUFBTTtBQUM5QyxVQUFJO0FBQ0osVUFBSTtBQUNBLHNCQUFjLE9BQU8sR0FBRztBQUFBLE1BQzVCLFNBQVMsR0FBRztBQUNSLHFCQUFhLEtBQUssU0FBUyxRQUFRLElBQUksR0FBRyxVQUFVO0FBQ3BELGdCQUFRO0FBQUE7QUFBQSxVQUVKLGdCQUFnQixVQUFVLHVCQUF1QixVQUFVLDZCQUE2QixFQUFFLE9BQU87QUFBQSxRQUNyRztBQUNBLGNBQU0sSUFBSTtBQUFBO0FBQUEsVUFFTixRQUFRLFVBQVUsNkJBQTZCLEVBQUUsT0FBTztBQUFBLFFBQzVEO0FBQUEsTUFDSjtBQUNBLFlBQU0sT0FBTyxXQUFXLFdBQVcsU0FBUyxFQUFFLFFBQVEsTUFBTSxFQUFFLENBQUM7QUFHL0QsVUFBSSxZQUFZLEtBQUssV0FBVyxLQUFNO0FBRXRDLFVBQUksU0FBUztBQUViLFVBQUksWUFBWSxLQUFLLFVBQVUsTUFBTTtBQUNqQyxpQkFBUyxZQUFZLEtBQUs7QUFBQSxNQUM5QjtBQUVBLFVBQUksT0FBTztBQUVYLFVBQUksWUFBWSxLQUFLLFFBQVEsTUFBTTtBQUMvQixlQUFPLFlBQVksS0FBSztBQUFBLE1BQzVCO0FBQ0EsV0FBSyxLQUFLO0FBQUEsUUFDTixNQUFNLFlBQVksS0FBSztBQUFBLFFBQ3ZCLE1BQU0sWUFBWTtBQUFBLFFBQ2xCO0FBQUEsUUFDQTtBQUFBLFFBQ0EsU0FBUyxZQUFZLEtBQUssV0FBVztBQUFBLFFBQ3JDLE9BQU8sWUFBWSxLQUFLLFNBQVM7QUFBQSxRQUNqQztBQUFBLFFBQ0EsYUFBYSxJQUFJLElBQUk7QUFBQSxNQUN6QixDQUFDO0FBQ0QsVUFBSSxZQUFZLEtBQUssVUFBVSxRQUFRO0FBQ25DLHFCQUFhLEtBQUssU0FBUyxRQUFRLElBQUksR0FBRyxVQUFVO0FBQ3BELGdCQUFRO0FBQUEsVUFDSixnQkFBZ0IsVUFBVSx1QkFBdUIsVUFBVTtBQUFBLFFBQy9EO0FBQ0EsY0FBTSxJQUFJLE1BQU0sUUFBUSxVQUFVLDJCQUEyQjtBQUFBLE1BQ2pFO0FBQUEsSUFDSjtBQUFBLEVBQ0osQ0FBQztBQUVELFNBQU8sS0FBSztBQUFBLElBQ1IsQ0FBQyxFQUFFLE1BQU0sT0FBTyxNQUFNLE1BQU0sR0FBRyxFQUFFLE1BQU0sT0FBTyxNQUFNLE1BQU0sTUFBTTtBQUc1RCxZQUFNLFFBQ0QsTUFBTSxhQUFhLE9BQU8sTUFBTSxNQUFNLFFBQVEsS0FBSyxLQUFLLE9BQ3pELE9BQU87QUFDWCxZQUFNLFFBQ0QsTUFBTSxhQUFhLE9BQU8sTUFBTSxNQUFNLFFBQVEsS0FBSyxLQUFLLE9BQ3pELE9BQU87QUFHWCxVQUFJLFFBQVEsTUFBTTtBQUNkLGVBQU8sTUFBTSxjQUFjLEtBQUs7QUFBQSxNQUNwQztBQUdBLGFBQU8sT0FBTztBQUFBLElBQ2xCO0FBQUEsRUFDSjtBQUNKOzs7QUR4UEEsSUFBTSxXQUFXO0FBQ2pCLElBQU0sZUFBZSxDQUFDLGFBQWEsYUFBYSxVQUFVO0FBQzFELElBQU0sOEJBQThCO0FBQUEsRUFDaEMsUUFBUTtBQUFBLEVBQ1IsVUFBVTtBQUFBLEVBQ1YsV0FBVztBQUFBLEVBQ1gsWUFBWTtBQUNoQjtBQUdBLElBQU0sZUFBdUM7QUFBQSxFQUN6QyxRQUFRO0FBQUEsRUFDUixVQUFVO0FBQUEsRUFDVixXQUFXO0FBQUEsRUFDWCxZQUFZO0FBQ2hCO0FBTUEsU0FBUyxtQkFBbUIsTUFBYyxZQUF5QjtBQUMvRCxRQUFNLFFBQVEsS0FBSyxNQUFNLFNBQVM7QUFDbEMsTUFBSSxPQUFPO0FBQ1AsV0FBTyxTQUFTLE1BQU0sQ0FBQyxHQUFHLEVBQUU7QUFBQSxFQUNoQyxXQUFXLFdBQVcsT0FBTztBQUN6QixXQUFPLFNBQVMsV0FBVyxLQUFLO0FBQUEsRUFDcEMsV0FBVyxXQUFXLFdBQVc7QUFDN0IsV0FBTyxTQUFTLFdBQVcsU0FBUztBQUFBLEVBQ3hDO0FBQ0EsU0FBTyxPQUFPO0FBQ2xCO0FBS0EsZUFBZSxrQkFBMEQ7QUFDckUsUUFBTSxVQUF5QyxDQUFDO0FBQ2hELFFBQU0sUUFBUSxNQUFNLEdBQUcsQ0FBQyxHQUFHLFFBQVEsVUFBVSxDQUFDO0FBRzlDLGFBQVcsWUFBWSxPQUFPO0FBRTFCLFFBQUksU0FBUyxTQUFTLE1BQU0sRUFBRztBQUMvQixVQUFNLGVBQWVDLE1BQUssU0FBUyxVQUFVLFFBQVE7QUFDckQsUUFBSSxhQUFhLEtBQUssWUFBVSxhQUFhLFlBQVksRUFBRSxTQUFTLE9BQU8sWUFBWSxDQUFDLENBQUMsRUFBRztBQUU1RixVQUFNLFdBQVcsYUFBYSxNQUFNQSxNQUFLLEdBQUc7QUFDNUMsVUFBTSxjQUFjLFNBQVMsQ0FBQztBQUc5QixVQUFNLGNBQWMsTUFBTUMsSUFBRyxTQUFTLFVBQVUsT0FBTztBQUN2RCxVQUFNLEVBQUUsTUFBTSxXQUFXLElBQUlDLFFBQU8sV0FBVztBQUUvQyxRQUFJLFdBQVcsUUFBUTtBQUNuQjtBQUFBLElBQ0o7QUFHQSxVQUFNLGVBQWUsYUFBYSxXQUFXLEtBQUs7QUFFbEQsUUFBSSxlQUE4QixRQUFRLFdBQVcsS0FBSyxDQUFDO0FBRTNELFFBQUksQ0FBQyxRQUFRLFdBQVcsR0FBRztBQUN2QixjQUFRLFdBQVcsSUFBSTtBQUFBLElBQzNCO0FBR0EsYUFBUyxJQUFJLEdBQUcsSUFBSSxTQUFTLFFBQVEsS0FBSztBQUN0QyxZQUFNLFVBQVUsU0FBUyxDQUFDLEVBQUUsUUFBUSxPQUFPLEVBQUU7QUFDN0MsWUFBTSxTQUFTLE1BQU0sU0FBUyxTQUFTO0FBR3ZDLFVBQUk7QUFDSixVQUFJLFFBQVE7QUFFUixlQUFPLElBQUksU0FBUyxNQUFNLEdBQUcsSUFBSSxDQUFDLEVBQUUsS0FBSyxHQUFHLENBQUMsR0FBRyxRQUFRLFNBQVMsRUFBRTtBQUFBLE1BQ3ZFLFdBQVcsTUFBTSxHQUFHO0FBQ2hCLGVBQU8sSUFBSSxPQUFPO0FBQUEsTUFDdEI7QUFFQSxZQUFNQyxTQUFRLG1CQUFtQixTQUFTLFVBQVU7QUFFcEQsVUFBSSxRQUFRO0FBRVIsY0FBTSxRQUFRLE1BQU0saUJBQWlCLFVBQVUsVUFBVTtBQUV6RCxjQUFNLGNBQWMsSUFBSSxJQUFJO0FBQzVCLHFCQUFhLEtBQUssRUFBRSxNQUFNLE9BQU8sTUFBTSxPQUFBQSxRQUFPLFlBQVksQ0FBQztBQUFBLE1BQy9ELE9BQU87QUFFSCxZQUFJLGNBQWMsTUFBTSxJQUFJLGVBQWU7QUFHM0Msc0JBQWMsWUFBWSxRQUFRLFlBQVksRUFBRTtBQUVoRCxZQUFJLFFBQVEsYUFBYTtBQUFBLFVBQUssVUFDekIsTUFBTSxLQUFLLEtBQUssU0FBUyxnQkFDekIsTUFBTSxLQUFLLEtBQUssU0FBUztBQUFBLFFBQzlCO0FBRUEsWUFBSSxDQUFDLE9BQU87QUFDUixnQkFBTSxZQUFZLE1BQU0sSUFBSSxJQUFJLE9BQU8sS0FBSztBQUM1QyxrQkFBUTtBQUFBLFlBQ0osTUFBTTtBQUFBLFlBQ04sT0FBTyxDQUFDO0FBQUEsWUFDUixPQUFBQTtBQUFBLFlBQ0EsV0FBVyxJQUFJLDRCQUE0QixTQUFTLENBQUMsQ0FBQztBQUFBO0FBQUEsWUFFdEQsYUFBYSxLQUFLLE9BQU87QUFBQSxZQUN6QixNQUFNO0FBQUEsVUFDVjtBQUNBLHVCQUFhLEtBQUssS0FBSztBQUFBLFFBQzNCO0FBQ0EsdUJBQWUsTUFBTSxTQUFTLENBQUM7QUFBQSxNQUNuQztBQUFBLElBQ0o7QUFBQSxFQUNKO0FBR0EsYUFBVyxPQUFPLFNBQVM7QUFDdkIscUJBQWlCLFFBQVEsR0FBRyxDQUFDO0FBQUEsRUFDakM7QUFHQSxRQUFNLGNBQTZDLENBQUM7QUFDcEQsYUFBVyxPQUFPLFNBQVM7QUFDdkIsZ0JBQVksR0FBRyxJQUFJLENBQUM7QUFDcEIsWUFBUSxHQUFHLEVBQUUsUUFBUSxVQUFRO0FBQ3pCLFVBQUksS0FBSyxPQUFPO0FBQ1osb0JBQVksR0FBRyxFQUFFLEtBQUssR0FBRyxLQUFLLEtBQUs7QUFBQSxNQUN2QyxPQUFPO0FBQ0gsb0JBQVksR0FBRyxFQUFFLEtBQUssSUFBSTtBQUFBLE1BQzlCO0FBQUEsSUFDSixDQUFDO0FBQUEsRUFDTDtBQUdBLFFBQU0sT0FBTyxvQkFBb0JILE1BQUssS0FBSyxRQUFRLElBQUksR0FBRyxNQUFNLEdBQUdBLE1BQUssS0FBSyxRQUFRLElBQUksR0FBRyxXQUFXLENBQUM7QUFDeEcsUUFBTSxjQUE2QixDQUFDO0FBQ3BDLE9BQUssUUFBUSxVQUFRO0FBQ2pCLFFBQUksS0FBSyxLQUFLLFlBQVk7QUFJdEIsWUFBTSxhQUF1QixDQUFDO0FBQzlCLFlBQU0sU0FBUyxLQUFLLEtBQUssV0FBVyxJQUFJLENBQUMsYUFBa0I7QUFBQztBQUN4RCxlQUFPO0FBQUEsVUFDSCxNQUFNLFNBQVM7QUFBQSxVQUNmLFdBQVc7QUFBQSxVQUNYLE9BQU8sS0FBSyxTQUNQLE9BQU8sV0FBUyxNQUFNLEtBQUssYUFBYSxTQUFTLEtBQUssRUFDdEQsT0FBTyxXQUFTLE1BQU0sSUFBSSxFQUMxQixJQUFJLFdBQVM7QUFDVix1QkFBVyxLQUFLLE1BQU0sSUFBSTtBQUMxQixtQkFBTztBQUFBLGNBQ0gsTUFBTSxNQUFNO0FBQUEsY0FDWixNQUFNLE1BQU07QUFBQSxjQUNaLGFBQWEsTUFBTTtBQUFBLFlBQ3ZCO0FBQUEsVUFDSixDQUFDO0FBQUEsUUFDVDtBQUFBLE1BQ0osQ0FBQztBQUVELFlBQU0sYUFBYSxLQUFLLFNBQ25CLE9BQU8sV0FBUyxDQUFDLFdBQVcsU0FBUyxNQUFNLElBQUksQ0FBQyxFQUNoRCxPQUFPLFdBQVMsTUFBTSxJQUFJLEVBQzFCLElBQUksV0FBUztBQUNWLGVBQU87QUFBQSxVQUNILE1BQU0sTUFBTTtBQUFBLFVBQ1osTUFBTSxNQUFNO0FBQUEsVUFDWixhQUFhLE1BQU07QUFBQSxRQUN2QjtBQUFBLE1BQ0osQ0FBQztBQUVMLGtCQUFZLEtBQUs7QUFBQSxRQUNiLE1BQU0sS0FBSyxLQUFLO0FBQUEsUUFDaEIsV0FBVztBQUFBLFFBQ1gsT0FBTyxDQUFDLEdBQUcsUUFBUSxHQUFHLFVBQVU7QUFBQSxNQUNwQyxDQUFDO0FBQUEsSUFDTCxPQUFPO0FBRUgsa0JBQVksS0FBSztBQUFBLFFBQ2IsTUFBTSxLQUFLO0FBQUEsUUFDWCxXQUFXO0FBQUEsUUFDWCxPQUFPLEtBQUssU0FDUCxPQUFPLFdBQVMsTUFBTSxJQUFJLEVBQzFCLElBQUksV0FBUztBQUNWLGlCQUFPO0FBQUEsWUFDSCxNQUFNLE1BQU07QUFBQSxZQUNaLE1BQU0sTUFBTTtBQUFBLFlBQ1osYUFBYSxNQUFNO0FBQUEsVUFDdkI7QUFBQSxRQUNKLENBQUM7QUFBQSxNQUNULENBQUM7QUFBQSxJQUNMO0FBQUEsRUFDSixDQUFDO0FBRUQsY0FBWSxNQUFNLElBQUk7QUFFdEIsU0FBTztBQUNYO0FBS0EsU0FBUyxpQkFBaUIsT0FBNEI7QUFFbEQsUUFBTSxLQUFLLENBQUMsR0FBRyxNQUFNO0FBQ2pCLFVBQU0sU0FBUyxFQUFFLFNBQVMsT0FBTztBQUNqQyxVQUFNLFNBQVMsRUFBRSxTQUFTLE9BQU87QUFDakMsV0FBTyxTQUFTO0FBQUEsRUFDcEIsQ0FBQztBQUdELFFBQU0sUUFBUSxVQUFRO0FBQ2xCLFFBQUksS0FBSyxTQUFTLEtBQUssTUFBTSxTQUFTLEdBQUc7QUFDckMsdUJBQWlCLEtBQUssS0FBSztBQUFBLElBQy9CO0FBQUEsRUFDSixDQUFDO0FBQ0w7QUFLQSxlQUFlLGlCQUFpQixVQUFrQixZQUFrQztBQUNoRixNQUFJLFdBQVcsT0FBTztBQUNsQixXQUFPLFdBQVcsTUFBTSxLQUFLLEVBQUUsUUFBUSxTQUFTLEVBQUU7QUFBQSxFQUN0RDtBQUVBLFFBQU0sV0FBV0EsTUFBSyxTQUFTLFVBQVUsS0FBSztBQUU5QyxTQUFPLFNBQVMsUUFBUSxZQUFZLEVBQUUsRUFBRSxRQUFRLE1BQU0sR0FBRztBQUM3RDtBQUVBLElBQU8sa0JBQVE7OztBRHpQZixTQUFTLG1CQUFtQjtBQUhvTixJQUFNLDJDQUEyQztBQU1qUyxJQUFPLGlCQUFRLFlBQVk7QUFBQSxFQUN6QixNQUFNO0FBQUEsRUFDTixPQUFPO0FBQUEsRUFDUCxhQUFhO0FBQUEsRUFDYixpQkFBaUI7QUFBQTtBQUFBLEVBRWpCLE1BQU07QUFBQSxJQUNKLFNBQVM7QUFBQSxNQUNQLE9BQU87QUFBQSxRQUNMO0FBQUEsVUFDRSxNQUFNO0FBQUEsVUFDTixhQUFhO0FBQUEsWUFDWCxJQUFJLElBQUksd0NBQXdDLHdDQUFlO0FBQUEsVUFDakU7QUFBQSxRQUNGO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBQUEsRUFDQSxTQUFTO0FBQUEsSUFDUCxNQUFNO0FBQUEsTUFDSixPQUFPO0FBQUEsTUFDUCxNQUFNO0FBQUEsTUFDTixhQUFhO0FBQUE7QUFBQSxRQUVYLGNBQWM7QUFBQTtBQUFBLFFBRWQsV0FBVztBQUFBLFVBQ1QsTUFBTTtBQUFBLFVBQ04sTUFBTTtBQUFBLFFBQ1I7QUFBQTtBQUFBLFFBRUEsaUJBQWlCO0FBQUE7QUFBQSxRQUVqQixrQkFBa0I7QUFBQTtBQUFBLFFBRWxCLGtCQUFrQjtBQUFBLFFBQ2xCLHFCQUFxQjtBQUFBLFFBQ3JCLHNCQUFzQjtBQUFBLFFBQ3RCLHFCQUFxQjtBQUFBLE1BQ3ZCO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFBQSxFQUNBLE1BQU07QUFBQSxJQUNKLENBQUMsVUFBVSxFQUFFLE9BQU8sSUFBSSxLQUFLLDJEQUEyRCxDQUFDO0FBQUEsSUFDekYsQ0FBQyxVQUFVLENBQUMsR0FBRztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsS0FLZDtBQUFBLEVBQ0g7QUFBQSxFQUNBLGFBQWE7QUFBQTtBQUFBLElBRVgsS0FBSztBQUFBLE1BQ0gsRUFBRSxNQUFNLGdCQUFNLE1BQU0sSUFBSTtBQUFBLE1BQ3hCLEVBQUUsTUFBTSxRQUFRLE1BQU0sUUFBUTtBQUFBLE1BQzlCLEVBQUUsTUFBTSxtQkFBUyxNQUFNLHlCQUFlO0FBQUEsTUFDdEMsRUFBRSxNQUFNLDRCQUFRLE1BQU0sMEJBQWdCO0FBQUEsTUFDdEMsRUFBRSxNQUFNLDRCQUFRLE1BQU0sMkJBQWlCO0FBQUEsSUFDekM7QUFBQSxJQUVBLFNBQVMsTUFBTSxnQkFBZ0I7QUFBQSxJQUUvQixhQUFhO0FBQUEsTUFDWCxFQUFFLE1BQU0sVUFBVSxNQUFNLG9EQUFvRDtBQUFBLElBQzlFO0FBQUEsSUFFQSxVQUFVO0FBQUEsTUFDUixTQUFTO0FBQUEsTUFDVCxNQUFNO0FBQUEsSUFDUjtBQUFBLElBRUEsUUFBUTtBQUFBLE1BQ04sVUFBVTtBQUFBLE1BQ1YsU0FBUztBQUFBLFFBQ1AsT0FBTztBQUFBLFFBQ1AsUUFBUTtBQUFBLFFBQ1IsV0FBVztBQUFBLFFBQ1gsa0JBQWtCO0FBQUE7QUFBQSxVQUVoQixjQUFjLENBQUMsb0JBQW9CO0FBQUEsUUFDckM7QUFBQSxRQUNBLFNBQVM7QUFBQSxVQUNQLE1BQU07QUFBQSxZQUNKLGFBQWE7QUFBQSxZQUNiLGNBQWM7QUFBQSxjQUNaLFFBQVE7QUFBQSxnQkFDTixZQUFZO0FBQUEsZ0JBQ1osaUJBQWlCO0FBQUEsY0FDbkI7QUFBQSxjQUNBLE9BQU87QUFBQSxnQkFDTCxXQUFXO0FBQUEsa0JBQ1Qsa0JBQWtCO0FBQUEsa0JBQ2xCLHNCQUFzQjtBQUFBLGtCQUN0QixrQkFBa0I7QUFBQSxrQkFDbEIsdUJBQXVCO0FBQUEsZ0JBQ3pCO0FBQUEsZ0JBQ0EsYUFBYTtBQUFBLGtCQUNYLHFCQUFxQjtBQUFBLGtCQUNyQixzQkFBc0I7QUFBQSxrQkFDdEIsNkJBQTZCO0FBQUEsa0JBQzdCLCtCQUErQjtBQUFBLGtCQUMvQix1QkFBdUI7QUFBQSxrQkFDdkIsaUNBQWlDO0FBQUEsZ0JBQ25DO0FBQUEsZ0JBQ0EsYUFBYTtBQUFBLGtCQUNYLFdBQVc7QUFBQSxrQkFDWCxVQUFVO0FBQUEsZ0JBQ1o7QUFBQSxnQkFDQSxRQUFRO0FBQUEsa0JBQ04sWUFBWTtBQUFBLGtCQUNaLGNBQWM7QUFBQSxrQkFDZCxXQUFXO0FBQUEsa0JBQ1gsY0FBYztBQUFBLGdCQUNoQjtBQUFBLGdCQUNBLGlCQUFpQjtBQUFBLGtCQUNmLGVBQWU7QUFBQSxrQkFDZixvQkFBb0I7QUFBQSxrQkFDcEIsMEJBQTBCO0FBQUEsa0JBQzFCLDhCQUE4QjtBQUFBLGdCQUNoQztBQUFBLGNBQ0Y7QUFBQSxZQUNGO0FBQUEsVUFDRjtBQUFBLFFBQ0Y7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFDRixDQUFDOyIsCiAgIm5hbWVzIjogWyJmcyIsICJwYXRoIiwgIm1hdHRlciIsICJwYXRoIiwgInBhdGgiLCAiZnMiLCAibWF0dGVyIiwgIm9yZGVyIl0KfQo= diff --git a/docs/index.md b/docs/index.md index 5787627f..873b857a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -28,4 +28,6 @@ features:
-> 如果需要查看官方文档,请访问 [我的世界开发者平台](https://mc.163.com/dev/)。 \ No newline at end of file +> 如果需要查看我的世界官方文档,请访问 [我的世界开发者平台](https://mc.163.com/dev/)。 + +> 欢迎加入我们的 [交流QQ群](https://qm.qq.com/q/NGIRFwEoMw),一起贡献教程和文档吧! \ No newline at end of file diff --git a/docs/wiki/animation-controllers/afk-animation-controller.md b/docs/wiki/animation-controllers/afk-animation-controller.md new file mode 100644 index 00000000..618a3909 --- /dev/null +++ b/docs/wiki/animation-controllers/afk-animation-controller.md @@ -0,0 +1,72 @@ +--- +title: AFK检测器 +tags: + - 配方 +mentions: + - SirLich + - BlueFrog130 + - SmokeyStack + - Keyyard + - Ultr4Anubis +--- + +# AFK检测器 + + + +### AFK检测动画控制器 + +了解更多动画控制器知识 + +这是一个用于检测挂机玩家的示例实现。 + +::: code-group +```json [BP/animation_controllers/afk.ac.json] +{ + "format_version": "1.10.0", + "animation_controllers": { + "controller.animation.player.afk": { + "states": { + "default": { + "transitions": [ + { + "stands_still": "!q.is_moving" + } + ] + }, + "stands_still": { + "on_entry": [ + "v.afk = q.life_time;" + ], + "transitions": [ + { + "afk": "(q.life_time - v.afk) >= 30 && !q.is_moving" + }, + { + "default": "q.is_moving" + } + ] + }, + "afk": { + "on_entry": ["/tag @s add AFK", "/say 我现在处于挂机状态"], + "animations": ["afk_animation"], + "transitions": [ + { + "default": "q.is_moving" + } + ], + "on_exit": ["/tag @s remove AFK", "/say 我已结束挂机状态"] + } + } + } + } +} +``` +::: + +- `controller.animation.player.afk` 是该控制器的唯一标识符 +- 当[Molang](https://bedrock.dev/zh/MoLang)查询`!q.is_moving`返回false时(表示玩家未移动),状态会切换到"stands_still" +- "stands_still"状态会持续检测:若玩家30秒内无移动则进入"afk"状态,否则返回"default"状态 +- 进入"afk"状态时,会触发"on_entry"中的命令 +- "animations"字段包含该状态激活期间持续播放的行为动画简称(用法与[资源动画控制器](#animation-controller)相同) +- 当玩家恢复移动时,状态将转回"default"状态,并执行"on_exit"中的命令 \ No newline at end of file diff --git a/docs/wiki/animation-controllers/animation-controllers-intro.md b/docs/wiki/animation-controllers/animation-controllers-intro.md new file mode 100644 index 00000000..b1ebda26 --- /dev/null +++ b/docs/wiki/animation-controllers/animation-controllers-intro.md @@ -0,0 +1,310 @@ +--- +title: 动画控制器入门 +nav_order: 1 +tags: + - 指南 +mentions: + - SirLich + - solvedDev + - Joelant05 + - MedicalJewel105 + - stirante + - cda94581 + - ThijsHankelMC + - MetalManiacMc + - ThomasOrs +--- + +# 动画控制器入门 + + + +动画控制器(AC)是一种可在资源包(RP)和行为包(BP)中使用的状态机。在资源包中,动画控制器(RPAC)用于播放动画;在行为包中(BPAC),它们用于执行命令和"动画"指令。 + +## 什么是状态机? + +状态机是一种特殊的逻辑管理方式,它依赖于一系列状态。每个状态具有两个属性: + +- 当前状态下执行的操作 +- 如何转移到其他状态 + +状态机在各类系统中广泛应用,尤其在传统编程领域。它们不仅存在于Minecraft中!您可以通过[此链接](https://www.itemis.com/en/yakindu/state-machine/documentation/user-guide/overview_what_are_state_machines)深入了解状态机。 + +状态机同一时间只能处于**一个**状态。当状态机"运行"时,可以理解为它在不同状态间转移,执行其中的逻辑,并遵循`transitions`规则转移到其他状态。 + +## 状态机示例 + +状态机的优势在于能够将动画自然分解为逻辑流程,每个状态独立处理自身动画**和**逻辑。 + +例如,假设您想为直升机螺旋桨制作动画,但仅在地面时停止旋转。这里有两个状态: + +- `地面状态` +- `飞行状态` + +我们可以用前文提到的两个属性来注解这些状态: + +- `地面状态`: + - 不播放动画 + - 若处于空中则转移到`飞行状态` +- `飞行状态`: + - 播放飞行动画 + - 若着陆则返回`地面状态` + +以下是状态机的流程图表示: + +![](/assets/images/concepts/animation-controllers/two_state_FSM.png) + +在流程图中,状态用矩形表示,箭头表示状态间的**转移**。让我们看一个更复杂的示例,新增了`爆炸状态`: + +![](/assets/images/concepts/animation-controllers/three_state_FSM.png) + +可见,一个状态可同时转移到多个状态。状态也可以是终止状态(直升机损毁后无需继续动画)。这种分支流程体现了动画控制器的强大之处。 + +## 什么是动画控制器? + +动画控制器是Minecraft中用于播放动画和执行指令的状态机。动画控制器文件必须存放在资源包或行为包的`animation_controllers`文件夹中。 + +### 将控制器附加到实体 + +动画控制器需在实体文件中进行"附加"才能生效。附加AC需要完成两个步骤: + +1. 为动画控制器定义简称 +2. 通过`scripts`运行动画控制器 + +以下示例展示了如何在`animations`中定义AC,并通过`scripts/animate`播放: + +::: code-group +```json [RP/entity/helicopter.ce.json 或 BP/entities/helicopter.se.json] +"description": { + "identifier": "wiki:helicopter", + "animations": { + "blade_controller": "controller.animation.helicopter.blade" + }, + "scripts": { + "animate": [ + "blade_controller" + ] + } +} +``` +::: + +若需要条件触发动画控制器,可添加Molang参数。当参数为真时控制器才会运行: + +::: code-group +```json [RP/entity/helicopter.ce.json 或 BP/entities/helicopter.se.json] +"scripts": { + "animate": [ + { + // 仅在直升机有骑手时播放blade_controller + "blade_controller": "q.has_rider" + } + ] +} +``` +::: + +### RP动画控制器 + +资源包动画控制器位于RP中,可附加到RP实体。用于播放骨骼动画。 + +### BP动画控制器 + +行为包动画控制器位于BP中,可附加到BP实体。用于执行命令和向实体发送事件。 + +## 动画控制器示例 + +### 基础示例 + +::: code-group +```json [RP/animation_controllers/helicopter.ac.json] +{ + "format_version": "1.10.0", + "animation_controllers": { + "controller.animation.helicopter.blade": { + "initial_state": "ground", + "states": { + "ground": { + "transitions": [ + { + "flying": "!q.is_on_ground" + } + ] + }, + "flying": { + "animations": ["flying"], + "transitions": [ + { + "ground": "q.is_on_ground" + } + ] + } + } + } + } +} +``` +::: + +解析关键点: +- `initial_state`: "ground" 表示初始状态 +- `ground`状态包含转移到"flying"状态的逻辑 +- `flying`状态播放"flying"动画并包含返回逻辑 + +### 完整示例 + +::: code-group +```json [RP/animation_controllers/helicopter.ac.json] +{ + "format_version": "1.10.0", + "animation_controllers": { + "controller.animation.helicopter.blade": { + "initial_state": "ground", + "states": { + "ground": { + "transitions": [ + {"flying": "!q.is_on_ground"}, + {"explode": "!q.is_alive"} + ] + }, + "flying": { + "animations": ["flying"], + "transitions": [ + {"ground": "q.is_on_ground"}, + {"explode": "!q.is_alive"} + ] + }, + "explode": { + "animations": ["explode"] + } + } + } + } +} +``` +::: + +## RP动画控制器扩展功能 + +资源包动画控制器可触发音效和粒子效果。使用前需在客户端实体文件中预先定义: + +::: code-group +```json [RP/entities/custom_tnt.json#minecraft:client_entity/description] +"sound_effects": { + "explosion": "wiki.custom_tnt.explosion" // 其中wiki.custom_tnt.explosion是在sound_definitions中定义的声音 +}, +"particle_effects": { + "fuse_lit": "wiki:tnt_fuse_lit_particle" +} +``` +::: + +::: code-group +```json [RP/animation_controllers/custom_tnt.animation_controllers.json#controller.animation.custom_tnt] +"states":{ + "default":{ + "transitions":[ + {"explode_state":"q.mark_variant == 1"} + ] + }, + "explode_state":{ + "sound_effects":[{"effect":"explosion"}], + "particle_effects": [ + { + "effect": "fuse_lit" + // "locator": "<骨骼名称>" 此处也可指定定位器 + } + ], + "transitions":[ + {"default":"q.mark_variant == 0"} + ] + } +} +``` +::: + +:::warning +警告!并非所有粒子效果在此处都有效。若遇到问题,建议尝试其他粒子效果(例如参考烈焰人动画控制器中的示例)。 +::: + +## BP动画控制器功能 + +行为包动画控制器支持两个新字段: +- `on_entry`: 进入状态时执行的命令 +- `on_exit`: 退出状态时执行的命令 + +命令类型包含: +- 斜杠命令:`/say Hello!` +- 实体事件:`@s wiki:transform_into_plane` +- Molang表达式:`v.tickets += 1;` + +示例: + +::: code-group +```json [BP/animation_controllers/helicopter.ac.json] +{ + "format_version": "1.10.0", + "animation_controllers": { + "controller.animation.helicopter.commands": { + "initial_state": "ground", + "states": { + "ground": { + "on_entry": ["/say 当前处于地面状态!"], + "transitions": [ + {"flying": "!q.is_on_ground"} + ] + }, + "flying": { + "on_entry": ["/say 当前处于空中状态!"], + "transitions": [ + {"ground": "q.is_on_ground"} + ] + } + } + } + } +} +``` +::: + +## 动画控制器执行流程 + +### 加载阶段 +- 实体加载时进入初始状态(未定义时使用"default") +- 每Tick执行: + 1. 播放当前状态动画(循环或单次) + 2. 检查转移条件,执行首个有效转移 + +### 重置机制 +实体重载时(玩家进出、区块重载等)会重置到初始状态 + +## 高级功能 + +动画控制器支持变量重映射: + +```json +{ + "format_version": "1.17.30", + "animation_controllers": { + "controller.animation.sheep.move": { + "states": { + "default": { + "variables": { + "ground_speed_curve": { + "input": "q.ground_speed", + "remap_curve": { + "0.0": 0.2, + "1.0": 0.7 + } + } + }, + "animations": [ + "wiggle_nose", + {"walk": "v.ground_speed_curve"} + ] + } + } + } + } +} +``` \ No newline at end of file diff --git a/docs/wiki/animation-controllers/death-commands.md b/docs/wiki/animation-controllers/death-commands.md new file mode 100644 index 00000000..1dab6608 --- /dev/null +++ b/docs/wiki/animation-controllers/death-commands.md @@ -0,0 +1,120 @@ +--- +title: 死亡命令 +tags: + - 配方 +mentions: + - SirLich + - BlueFrog130 + - SmokeyStack + - cda94581 + - MedicalJewel105 + - Kaioga5 + - TheItsNameless +--- + +# 死亡命令 + + + +了解更多关于动画控制器的知识 + +我将"死亡效果"定义为"当实体死亡时执行某些操作"。以下是几种应该避免的错误实现方式: + +- **在实体文件中检测死亡**:通过添加组件然后尝试在动画控制器中检测该组件。这种方法是错误的,因为实体在被移除前动画控制器没有机会运行。 +- **通过外部源检测死亡**:例如使用持续运行的命令方块。这种方法并非完全错误,在某些情况下甚至可能是优选方案,但存在性能损耗且容易出错。 + +## 使用 q.is_alive 查询 + +创建死亡效果的最佳方式是使用`is_alive`查询。只需在动画控制器中创建基于`is_alive`的状态过渡,`on_entry`中的命令会在实体被移除前执行。 + +示例动画控制器: + +::: code-group +```json [BP/animation_controllers/death.ac.json] +{ + "format_version": "1.10.0", + "animation_controllers": { + "controller.animation.death": { + "initial_state":"default", + "states": { + "default": { + "transitions": [ + { + "dead": "!q.is_alive" + } + ] + }, + "dead": { + "on_entry": ["/say 我已死亡!"] + } + } + } + } +} +``` +::: + +## 在玩家实体上的应用 + +对于玩家实体,需要在死亡状态中添加额外过渡来确保状态重置: + +::: code-group +```json [BP/animation_controllers/death.ac.json] +{ + "format_version": "1.10.0", + "animation_controllers": { + "controller.animation.death": { + "initial_state":"default", + "states": { + "default": { + "transitions": [ + { + "dead": "!q.is_alive" + } + ] + }, + "dead": { + "on_entry": ["/say 我已死亡!"], + "transitions": [ + { + "default": "q.is_alive" + } + ] + } + } + } + } +} +``` +::: + +:::warning +需要启用实验性玩法 +::: + +## 使用 minecraft:on_death 组件 + +通过在行为包的`entity.json`文件中使用`minecraft:on_death`组件,可以更直接地实现死亡命令: + +1. 在组件部分添加触发逻辑: +```json +"minecraft:on_death" : { + "event" : "wiki:on_death", + "target" : "self" +} +``` + +2. 在事件部分定义执行内容: +```json +"wiki:on_death": { + "run_command": { + "command": [ + "say 我已经死了!" + ] + } +} +``` + +:::tip +使用此方法可以在实体死亡后仍然为其添加计分板分数和标签 +::: \ No newline at end of file diff --git a/docs/wiki/animation-controllers/entity-commands.md b/docs/wiki/animation-controllers/entity-commands.md new file mode 100644 index 00000000..7e387118 --- /dev/null +++ b/docs/wiki/animation-controllers/entity-commands.md @@ -0,0 +1,275 @@ +--- +title: 实体命令 +nav_order: 2 +tags: + - 中级 +mentions: + - SirLich + - solvedDev + - Joelant05 + - destruc7i0n + - Dreamedc2015 + - MedicalJewel105 + - aexer0e + - cda94581 + - ThijsHankelMC +--- + +# 实体命令 + + + +:::warning +通过`run_command`事件响应来执行实体命令是更简单的方法,但目前该功能仍处于实验性阶段。 +::: + +## 动画控制器 + +要触发斜杠命令,我们将使用行为包动画控制器。动画控制器应放置在`animation_controllers/some_controller.json`路径下。你可以在[bedrock.dev的实体事件章节](https://bedrock.dev/docs/stable/Entity%20Events)了解更多关于动画控制器的知识。 + +简而言之,动画控制器允许我们从行为包中触发事件: + +- 斜杠命令(如`/say`) +- Molang表达式(`v.foo += 1;`) +- 实体事件(如`@s wiki:my_event`) + +以下是一个动画控制器示例: + +::: code-group +```json [BP/animation_controllers/entity_commands.ac.json] +{ + "format_version": "1.10.0", + "animation_controllers": { + "controller.animation.sirlich_entity_commands": { + "states": { + "default": { + "transitions": [ + { + "on_summon": "1" // 1表示真值 + } + ] + }, + "on_summon": { + "on_entry": ["/say I have been summoned"] + } + } + } + } +} +``` +::: + +当实体被召唤到世界时,这个动画控制器会立即执行`/say I have been summoned`命令。如果对工作原理有疑问,请复习Molang、动画和实体事件相关内容。 + +简单来说,`states`可以通过`on_entry`子句触发事件。我们使用查询条件在不同状态间切换。除非定义了`initial_state`值,否则实体默认处于`default`状态。 + +:::warning +当世界/区块重新加载时,查询会重新运行。这意味着`"/say I have been summoned"`命令实际上会在每次实体"加载"时执行——而不仅在被召唤时。 +::: + +如果需要避免这种情况,需要添加额外查询条件,例如使用`skin_id`查询。首次生成实体时检查`skin_id = 0`,然后将其设置为更高的值如`skin_id = 1`。这样当实体重新加载时就不会再次触发命令。下文将展示具体实现方法。 + +## 使用动画控制器 + +要将动画控制器添加到实体中,可以在实体定义描述中使用以下代码: + +::: code-group +```json [BP/entities/entity_commands.se.json] +"description": { + "identifier": "wiki:entity_commands", + "scripts": { + "animate": [ + "wiki:entity_commands" + ] + }, + "animations": { + "wiki:entity_commands": "controller.animation.wiki_entity_commands" + } +} +``` +::: + +如果对步骤有疑问,请再次查阅[实体事件文档](https://bedrock.dev/r/Entity%20Events)。 + +## 通过事件触发命令 + +动画状态过渡使用查询条件实现。可查阅[实体查询列表](https://bedrock.dev/docs/stable/MoLang#List%20of%20Entity%20Queries)。在第一个示例中,查询条件简化为`true`,因此命令会自动执行。我们可以使用更复杂的查询条件实现更精细的控制,其中通过组件作为Molang过滤器来触发命令是便捷的方法。 + +推荐使用[skin_id](https://docs.microsoft.com/en-us/minecraft/creator/reference/content/entityreference/examples/entityproperties/minecraftproperty_skin_id)组件。 + +更新后的动画控制器基于`skin_id`触发: + +::: code-group +```json [BP/animation_controllers/entity_commands.ac.json] +{ + "format_version": "1.10.0", + "animation_controllers": { + "controller.animation.sirlich_entity_commands": { + "states": { + "default": { + "transitions": [ + { + "command_example": "q.skin_id == 1" + }, + { + "zombies": "q.skin_id == 2" + } + ] + }, + "command_example": { + "transitions": [ + { + "default": "q.skin_id != 1" + } + ], + "on_entry": ["/say Command One!", "@s execute_no_commands"] + }, + "zombies": { + "transitions": [ + { + "default": "q.skin_id != 2" + } + ], + "on_entry": [ + "/say AHH! Zombies everywhere!", + "/summon minecraft:zombie", + "/summon minecraft:zombie", + "/summon minecraft:zombie", + "/summon minecraft:zombie", + "@s execute_no_commands" + ] + } + } + } + } +} +``` +::: + +现在这个动画控制器有两个命令状态:`skin_id = 1`触发第一个,`skin_id = 2`触发第二个。注意使用`==`和`!=`运算符(不要使用单个`=`)。`@s execute_no_commands`语法用于在命令列表末尾重置`skin_id`,下文将创建这个事件。 + +## 设置组件组 + +在实体文件中,可以通过`skin_id`组件设置值: + +::: code-group +```json [BP/entities/entity_commands.se.json] +"component_groups": { + "execute_no_commands": { + "minecraft:skin_id": { + "value": 0 + } + }, + "command_example": { + "minecraft:skin_id": { + "value": 1 + } + }, + "command_zombies": { + "minecraft:skin_id": { + "value": 2 + } + } +} +``` +::: + +## 添加事件 + +创建事件以便管理组件组: + +::: code-group +```json [BP/entities/entity_commands.se.json] +"events": { + "minecraft:entity_spawned": { + "add": { + "component_groups": [ + "execute_no_commands" + ] + } + }, + "execute_no_commands": { + "add": { + "component_groups": [ + "execute_no_commands" + ] + } + }, + "command_example": { + "add": { + "component_groups": [ + "command_example" + ] + } + }, + "command_zombies": { + "add": { + "component_groups": [ + "command_zombies" + ] + } + } +} +``` +::: + +## 触发事件 + +Minecraft中有多种触发事件的方式,以下是两个典型示例: + +### 交互组件 + +此组件会在点击实体时生成僵尸: + +::: code-group +```json [BP/entities/entity_commands.se.json] +"minecraft:interact": { + "interactions": [{ + "on_interact": { + "filters": { + "all_of": [{ + "test": "is_family", + "subject": "other", + "value": "player" + } + ] + }, + "event": "command_zombies" + } + }] +} +``` +::: + +### 定时器 + +此组件每10秒触发示例命令: + +::: code-group +```json [BP/entities/entity_commands.se.json] +"minecraft:timer": { + "looping": true, + "time": 10, + "time_down_event": { + "event": "example_command" + } +} +``` +::: + +通过添加这些组件,我们可以控制`skin_id`的变化时机,从而决定哪些事件会被触发。 + +## 流程总结 + +完整工作流程如下: + +1. 通过交互或定时器等组件触发`example_command`事件 +2. 事件添加`example_command`组件组 +3. 组件组设置实体的`skin_id` +4. 动画控制器检测到`skin_id`变化,切换到对应状态 +5. 执行状态中的`/say`等命令 +6. 执行`@s execute_no_command`事件重置`skin_id` +7. 动画控制器检测重置,返回默认状态 +8. 等待新的`skin_id`触发新事件 + +通过这种机制,可以实现精准的实体行为控制。 \ No newline at end of file diff --git a/docs/wiki/animation-controllers/index.md b/docs/wiki/animation-controllers/index.md new file mode 100644 index 00000000..c91caf91 --- /dev/null +++ b/docs/wiki/animation-controllers/index.md @@ -0,0 +1,4 @@ +--- +title: 动画控制器 +nav_order: 6 +--- diff --git a/docs/wiki/animation-controllers/molang-into-scoreboard.md b/docs/wiki/animation-controllers/molang-into-scoreboard.md new file mode 100644 index 00000000..e45b88e7 --- /dev/null +++ b/docs/wiki/animation-controllers/molang-into-scoreboard.md @@ -0,0 +1,84 @@ +--- +title: 将Molang数据导入记分板 +mentions: + - SirLich + - MedicalJewel105 + - shanewolf38 + - Luthorius + - TheItsNameless + - ThomasOrs +--- + +# 将Molang数据导入记分板 + + + +以下提供了一种将任意Molang(变量、查询等)即时转换为记分板数值的方法。请确保控制器`convert`状态中调用的动画名称与实体定义中的动画名称(animation.namespace.molang_to_score)完全匹配。 + +**注意:** 需要先在游戏中执行以下两条命令进行初始化: +`/scoreboard objectives add MoLang dummy` +`/scoreboard players set "#10" MoLang 10` + +::: code-group +```json [BP/animation_controllers/molang_to_score.animation_controllers.json] +"controller.animation.namespace.molang_to_score": { + "initial_state": "idle", + "states": { + "idle": { + "transitions": [ { "convert": "<转换启动条件>" } ], + "on_exit": [ + "/scoreboard players set @s MoLang 0", + "/scoreboard players set \"#var\" MoLang 0", + "v.convert = <需要转换的变量>;", + "v.digit = 1000000000;" + ] + }, + "convert": { + "animations": [ + "molang_to_score", + "molang_to_score", + "molang_to_score", + "molang_to_score", + "molang_to_score", + "molang_to_score", + "molang_to_score", + "molang_to_score", + "molang_to_score", + "molang_to_score", + "molang_to_score" + ], + "transitions": [ { "idle": "1" } ] + } + } +} +``` +::: + +::: code-group +```json [BP/animations/molang_to_score.animation.json] +"animation.namespace.molang_to_score": { + "animation_length": 10.0, + "anim_time_update": "t.digit = Math.mod(Math.floor(v.convert / v.digit), 10) + 0.1; v.digit = v.digit / 10; return t.digit;", + "timeline": { + "0.0": [ + "/scoreboard players operation @s MoLang *= \"#10\" MoLang", + "/scoreboard players operation @s MoLang += \"#var\" MoLang", + "/scoreboard players set \"#var\" MoLang 0" + ], + "1.0": [ "/scoreboard players set \"#var\" MoLang 1" ], + "2.0": [ "/scoreboard players set \"#var\" MoLang 2" ], + "3.0": [ "/scoreboard players set \"#var\" MoLang 3" ], + "4.0": [ "/scoreboard players set \"#var\" MoLang 4" ], + "5.0": [ "/scoreboard players set \"#var\" MoLang 5" ], + "6.0": [ "/scoreboard players set \"#var\" MoLang 6" ], + "7.0": [ "/scoreboard players set \"#var\" MoLang 7" ], + "8.0": [ "/scoreboard players set \"#var\" MoLang 8" ], + "9.0": [ "/scoreboard players set \"#var\" MoLang 9" ] + } +} +``` +::: + +**实现原理:** 当转换启动时,控制器会重置玩家的MoLang分数和`#var`(虚拟玩家)的MoLang分数。转换变量`v.convert`被初始化,数字位变量`v.digit`被设置为获取第十位数字(10^10)。第一个动画运行时会根据当前位数设置动画时间,并将数字位变量调整为下一位(第9位,10^9)。由于时间轴索引会持续运行到设定时间,"0.0"时间点的事件总是会被触发。这会将玩家的MoLang分数乘以10来设置正确的位数,然后加上最后获取的数字(首次运行时由于控制器重置了`#var`,该值始终为0)。整个过程重复执行11次以获取转换变量的全部10位数字。需要注意的是每个动画处理的是前一个动画设置的数字位,因此需要运行11次动画。 + +**游戏内测试方法:** 将`<转换启动条件>`设为`q.is_using_item`,`<需要转换的变量>`设为`Math.random_integer(0, 9999)`。手持苹果开始食用,即可观察数值转换过程。 \ No newline at end of file diff --git a/docs/wiki/animation-controllers/respawn-commands.md b/docs/wiki/animation-controllers/respawn-commands.md new file mode 100644 index 00000000..5ccf794c --- /dev/null +++ b/docs/wiki/animation-controllers/respawn-commands.md @@ -0,0 +1,68 @@ +--- +title: 重生命令 +tags: + - recipe +mentions: + - SirLich + - solvedDev + - Joelant05 + - BlueFrog130 + - SmokeyStack + - MedicalJewel105 + - cda94581 +--- + +# 重生命令 + + + +了解更多关于动画控制器的信息 + +这个动画控制器可用于在玩家重生时执行命令,例如重新添加药水效果或给予物品。 + +只需将动画控制器添加到 `player.json` 中,并 + +::: code-group +```json [原CodeHeader的值] +{ + "format_version": "1.10.0", + "animation_controllers": { + "controller.animation.death": { + "initial_state": "initialization", + "states": { + "initialization": { + "transitions": [ + { + "has_died": "!q.is_alive" + } + ], + "on_exit": [ + "v.delay = 0.2 + q.life_time;", + "/<死亡命令或动画>" + ] + }, + "has_died": { + "on_exit": ["/<重生命令或动画>"], + "transitions": [ + { + "initialization": "q.is_alive && (q.life_time >= v.delay)" + } + ] + } + } + } + } +} +``` +::: + +该控制器包含两个状态: +1. **初始化状态**:当玩家死亡时设置延迟计时器(`v.delay = 0.2 + q.life_time`) +2. **死亡状态**:在延迟计时结束后触发重生命令 + +参数说明: +- `q.life_time`:玩家处于死亡状态的时间(秒) +- `v.delay`:自定义延迟时间(默认增加0.2秒容差) +- `/<>`:需要替换为实际执行的命令或动画 + +提示:可通过调整`v.delay`的公式来精确控制重生命令的触发时机。 \ No newline at end of file diff --git a/docs/wiki/blocks/block-permutations.md b/docs/wiki/blocks/block-permutations.md index b93c675f..fe24daa0 100644 --- a/docs/wiki/blocks/block-permutations.md +++ b/docs/wiki/blocks/block-permutations.md @@ -1,5 +1,5 @@ --- -title: 方块变换(置换) +title: 方块置换 description: 方块变换数组提供了一种基于当前置换条件性应用组件的方法。 category: 基础 nav_order: 7 @@ -7,7 +7,7 @@ mentions: - QuazChick --- -# 方块变换(置换) +# 方块置换 `permutations` @@ -21,6 +21,8 @@ mentions: `permutations`数组中的组件可以覆盖方块的基类组件以及其他组件列表中的组件。置换数组中最后出现的条目具有最高优先级。 +**[可旋转方块](/wiki/blocks/rotatable-blocks)** 是 **方块置换** 的一种常用用法。 + ## 定义置换 `permutations`数组是`minecraft:block`的直接子项,由包含组件的对象组成。当条件判断为真值(非false或0)时,相关组件将被应用。 diff --git a/docs/wiki/blocks/index.md b/docs/wiki/blocks/index.md index e05226a7..f68f309d 100644 --- a/docs/wiki/blocks/index.md +++ b/docs/wiki/blocks/index.md @@ -1,5 +1,6 @@ --- title: 方块 Blocks +nav_order: 3 categories: - title: 基础 color: blue diff --git a/docs/wiki/blocks/rotatable-blocks.md b/docs/wiki/blocks/rotatable-blocks.md index 6e4be02c..49483c1c 100644 --- a/docs/wiki/blocks/rotatable-blocks.md +++ b/docs/wiki/blocks/rotatable-blocks.md @@ -46,7 +46,7 @@ mentions: - 16个方向(以22.5度递增) - 4个侧面附着方向 -## 基本方向旋转 +## 基本方向旋转 {#cardinal-direction-rotation} ### 特性 @@ -108,7 +108,7 @@ mentions: ``` ::: -## 面向方向旋转 +## 面向方向旋转 {#facing-direction-rotation} ### 特性 @@ -183,7 +183,7 @@ mentions: ``` ::: -## 方块面附着旋转 +## 方块面附着旋转 {#block-face-rotation} ### 特性 @@ -258,7 +258,7 @@ mentions: ``` ::: -## 原木旋转 +## 原木旋转 {#log-rotation} 实现与原版原木相同的旋转方式 diff --git a/docs/wiki/commands/index.md b/docs/wiki/commands/index.md index 7938b906..6aeef50e 100644 --- a/docs/wiki/commands/index.md +++ b/docs/wiki/commands/index.md @@ -1,5 +1,6 @@ --- title: 命令 Commands +nav_order: 7 categories: - title: 基础 color: green diff --git a/docs/wiki/concepts/index.md b/docs/wiki/concepts/index.md index 0a5da50e..f1c62c4d 100644 --- a/docs/wiki/concepts/index.md +++ b/docs/wiki/concepts/index.md @@ -1,3 +1,4 @@ --- title: 概念 Concepts +nav_order: 8 --- diff --git a/docs/wiki/documentation/index.md b/docs/wiki/documentation/index.md index e31ea1ae..9e5edfd4 100644 --- a/docs/wiki/documentation/index.md +++ b/docs/wiki/documentation/index.md @@ -1,3 +1,4 @@ --- title: 文档 +nav_order: 9 --- diff --git a/docs/wiki/documentation/material-config-description.md b/docs/wiki/documentation/material-config-description.md index a23f9890..a630333b 100644 --- a/docs/wiki/documentation/material-config-description.md +++ b/docs/wiki/documentation/material-config-description.md @@ -1,29 +1,32 @@ --- -title: Material Configuration Description +title: 材质配置文件说明 tags: - - expert + - 专家级 mentions: - MedicalJewel105 - SmokeyStack --- +# 材质配置文件说明 + + + :::warning -Materials are not for the faint of heart. Be prepared for potential crashes, content log errors, and long loading times. +材质系统不适合心理承受能力弱的用户。请做好应对潜在崩溃、内容日志错误和长时间加载的准备。 ::: -## Foreword +## 前言 -This article is translated from https://mc.163.com/dev/mcmanual/mc-dev/mcguide/ - It is provided by Netease, the developers of china edition. The article will introduce the structure and configuration of the material file in detail. +本文译自网易中国版开发者文档 [材质配置说明](/mcguide/16-美术/7-材质与着色器/3-材质配置说明) ,将详细介绍材质文件的结构与配置方式。 -## Material files +## 材质文件结构 -We will explain the material files of native Microsoft. First of all, the files under the directory are basically files with the suffix ".material". In addition, there are three important json files, namely common. json, fancy.json, sad.json. +我们将以微软原生材质文件为例进行说明。该目录下主要包含以".material"为后缀的文件,此外还有三个重要的json文件:common.json、fancy.json和sad.json。 -Let's take a look at sad.json and fancy.json first. They are used to control the image quality performance. Each of them defines a list of material files. fancy.json usually defines several more material files than sad.json and may Some additional macros have been added to some material files, and the shader can do special processing by judging these macros: +首先观察sad.json和fancy.json,它们用于控制画面质量表现。每个文件都定义了材质文件列表。通常fancy.json会比sad.json多定义几个材质文件,并可能在某些材质文件中添加额外宏定义,着色器可通过判断这些宏进行特殊处理: -sad.json - -```json +::: code-group +```json [sad.json] [ {"path":"materials/sad.material"}, {"path":"materials/entity.material"}, @@ -34,9 +37,7 @@ Let's take a look at sad.json and fancy.json first. They are used to control the ] ``` -fancy.json - -```json +```json [fancy.json] [ {"path":"materials/fancy.material", "+defines":["FANCY"]}, {"path":"materials/entity.material", "+defines":["FANCY"]}, @@ -47,14 +48,14 @@ Let's take a look at sad.json and fancy.json first. They are used to control the {"path":"materials/wireframe.material"} ] ``` +::: -It can be seen that fancy.json defines more fancy.material and hologram.material material files than sad.json, and also defines FANCY macros for multiple material files. The switch of in-game settings/video/exquisite texture is to control the switch between sad and fancy. When the fancy texture switch is turned on, the material file in fancy.json will take effect, and when it is turned off, the material file in sad.json will take effect. +可以看出fancy.json比sad.json多定义了fancy.material和hologram.material材质文件,同时还为多个材质文件定义了FANCY宏。游戏设置/视频/精美图像选项的开关就是控制sad与fancy之间的切换。当开启精美图像时,fancy.json中的材质文件会生效;关闭时则使用sad.json中的材质文件。 -In order to achieve better performance, the material files in fancy.json usually have more complex operations, while the materials in sad.json usually sacrifice a little rendering performance in exchange for better performance. If developers need to write more complex shaders, it is recommended to write a low-cost version at the same time, and then define them in fancy and sad respectively. Let the player control whether to turn on the corresponding effect through the exquisite texture option in the game. +为了获得更好的表现效果,fancy.json中的材质文件通常包含更复杂的运算,而sad.json中的材质则通过牺牲少许渲染效果换取更佳性能。若开发者需要编写更复杂的着色器,建议同时编写低配版本,分别在fancy和sad中进行定义,让玩家通过游戏中的精美图像选项自行控制是否开启对应效果。 -common.json - -```json +::: code-group +```json [common.json] [ {"path":"materials/particles.material"}, {"path":"materials/shadows.material"}, @@ -66,25 +67,23 @@ In order to achieve better performance, the material files in fancy.json usually {"path":"materials/wireframe.material"} ] ``` +::: -Compared with sad and fancy, they can be switched between each other. The material files defined in common.json will be loaded after entering the game. Material files are not loaded except those declared in common.json, sad.json, fancy.json. +与可互相切换的sad和fancy不同,common.json中定义的材质文件会在进入游戏后始终加载。除了声明在common.json、sad.json、fancy.json中的材质文件外,其他材质文件不会被加载。 -## Material syntax +## 材质语法规范 -We use one of the material files entity.material to explain, open the file, we can see that the file starts with materials, and then defines the version number version as 1.0.0, these are fixed formats, which identify the parsing of this material file way, we can temporarily ignore it and not modify it. - -You can see that the definition of each field in the material is in the form of a key-value pair, for example: +我们以entity.material为例进行说明。打开文件可以看到文件以materials开头,接着定义了版本号version为1.0.0,这些都是固定格式,标识该材质文件的解析方式,暂时无需修改。 +可以看到材质中每个字段的定义都采用键值对形式,例如: ```json [ "vertexShader": "shaders/entity.vertex", ] ``` +冒号左侧表示键名vertexShader,右侧表示值shaders/entity.vertex; -The left side of the colon represents the key as vertexShader, and the right side represents the value shaders/entity.vertex; - -There are also definitions in list form: - +也存在列表形式的定义: ```json [ "vertexFields": [ @@ -94,61 +93,59 @@ There are also definitions in list form: ], ] ``` +带有[ ]符号的声明就是列表,内部是每个子元素的json定义。 -The declaration with the symbol [ ] is a list, and then inside is the json definition of each child element. +## 材质属性字段全览 -## Overview of all property fields of the material - -### Render state +### 渲染状态 #### `states` -Configure the rendering environment, which can have the following values: +配置渲染环境,可选值包括: -- `EnableAlphaToCoverage`:An order-independent rendering method for translucent objects. This switch is only useful in environments that support MSAA. When enabled, the edges of objects will be more accurately softened and transitioned according to the transparency. It can also be used for some complex scenes with a large number of meshes overlapping. +- `EnableAlphaToCoverage`:针对半透明物体的顺序无关渲染方式。该开关仅在支持MSAA的环境中有用。开启后物体边缘会根据透明度更精确地进行柔化过渡。也可用于大量网格重叠的复杂场景。 -- `Wireframe`: Draw wireframe mode +- `Wireframe`:线框绘制模式 -- `Blending`: Enables color blending mode, often used to render translucent objects. After declaring this, it is usually necessary to declare the blending factor blendSrc, blendDst +- `Blending`: 启用颜色混合模式,常用于渲染半透明物体。声明该选项后通常需要接着声明混合因子blendSrc、blendDst -- `DisableColorWrite`: Do not write color values to the color buffer, none of the RGBA channels are written +- `DisableColorWrite`:不向颜色缓冲区写入颜色值,RGBA通道均不写入 -- `DisableAlphaWrite`: Do not write transparency alpha values to the color buffer, allow RGB values to be written +- `DisableAlphaWrite`:不向颜色缓冲区写入透明度alpha值,允许写入RGB值 -- `DisableRGBWrite`: Do not write transparency RGB values to the color buffer, allow writing alpha values +- `DisableRGBWrite`:不向颜色缓冲区写入RGB值,允许写入alpha值 -- `DisableDepthTest`: Turn off depth testing +- `DisableDepthTest`:关闭深度测试 -- `DisableDepthWrite`: Turn off depth writing +- `DisableDepthWrite`:关闭深度写入 -- `DisableCulling`: Render front and back simultaneously +- `DisableCulling`: 同时渲染正反面 -- `InvertCulling`:Use front cropping. The default is back cropping. After declaring this, the back side is rendered and the front side is cropped. +- `InvertCulling`:使用正面裁剪。默认为背面裁剪。声明此项后背面会被渲染而正面被裁剪。 -- `StencilWrite`: Enable stencil mask writing +- `StencilWrite`: 启用模板掩码写入 -- `EnableStencilTest`: Enable stencil mask testing +- `EnableStencilTest`:启用模板掩码测试 - -### Shader path +### 着色器路径 #### `vertexShader` -The path to the vertex shader, usually shaders/XXX.vertex. +顶点着色器路径,通常为shaders/XXX.vertex。 -#### `vrGeometryShader` or `geometryShader` +#### `vrGeometryShader` 或 `geometryShader` -The path of the geometry shader, usually shaders/XXX.geometry, is not used on the mobile side, and does not need to be modified. +几何着色器路径,通常为shaders/XXX.geometry,移动端不会使用,无需修改。 #### `fragmentShader` -The path to the fragment shader, usually shaders/XXX.fragment. +片段着色器路径,通常为shaders/XXX.fragment。 -### Shader macro definition +### 着色器宏定义 #### `defines` -Define macros for the shaders used. For code reuse, we use the same shader for many different materials. At this time, if you want to execute different logic somewhere in the shader according to the current material, you can judge it through the macro declared by the material defines. We can use the material entity_for_skeleton as an illustration. Here we can see that three macros USE_SKINNING, USE_OVERLAY, and NETEASE_SKINNING are defined. +为使用的着色器定义宏。为了实现代码复用,我们会将同一个着色器用于许多不同的材质。此时若希望根据当前材质在着色器某处执行不同逻辑,可以通过材质defines声明的宏进行判断。以entity_for_skeleton材质为例,可以看到这里定义了USE_SKINNING、USE_OVERLAY和NETEASE_SKINNING三个宏。 ```json "entity_for_skeleton": { @@ -172,7 +169,7 @@ Define macros for the shaders used. For code reuse, we use the same shader for m } ``` -Looking at the vertex shader entity.vertex, there will be #ifdef, #else, #endif to judge the macro and execute different logic branches. These judgment statements of the macro are processed at compile time, unlike the if in the traditional shader. Else, the logic branch processed at compile time will not be generated in actual operation, and the performance will not be degraded due to the branch. In addition, it can be seen below that macros can also make multi-layer judgments. First, judge the NETEASE_SKINNING macro, and then judge the LARGE_VERTEX_SHADER_UNIFORMS macro in the internal execution logic: +观察顶点着色器entity.vertex,会发现通过#ifdef、#else、#endif等指令判断宏定义并执行不同逻辑分支。这些宏的判断语句是在编译期处理的,不同于传统着色器中运行时处理的if else逻辑分支,实际运行时不会产生分支性能损耗。此外可以看到宏还能做多层判断,先判断NETEASE_SKINNING宏,再在内部执行逻辑中判断LARGE_VERTEX_SHADER_UNIFORMS宏: ```glsl #ifdef NETEASE_SKINNING @@ -190,90 +187,88 @@ Looking at the vertex shader entity.vertex, there will be #ifdef, #else, #endif #endif ``` -### Runtime state +### 运行时状态 -#### Depth test +#### 深度测试 ##### `depthFunc` -The depth detection pass function can use the following values: +深度检测通过函数,可使用以下值: -- `Always`: Always pass +- `Always`: 总是通过 -- `Equal`: Passed when the depth value is equal to the buffer value +- `Equal`:深度值等于缓冲值时通过 -- `NotEqual`:Passed when the depth value is not equal to the buffer value +- `NotEqual`:深度值不等于缓冲值时通过 -- `Less`:Passed when the depth value is less than the buffer value +- `Less`:深度值小于缓冲值时通过 -- `Greater`:Passed when the depth value is greater than the buffer value +- `Greater`:深度值大于缓冲值时通过 -- `GreaterEqual`:Pass when the depth value is greater than or equal to the buffer value +- `GreaterEqual`:深度值大于等于缓冲值时通过 -- `LessEqual`:Pass when the depth value is less than or equal to the buffer value +- `LessEqual`:深度值小于等于缓冲值时通过 -Associated states rendering environment configuration: +关联状态渲染环境配置: -- `DisableDepthTest`: Turn off depth testing +- `DisableDepthTest`:关闭深度测试 -- `DisableDepthWrite`: Turn off depth writing +- `DisableDepthWrite`:关闭深度写入 -#### Stencil Mask Test +#### 模板掩码测试 ##### `stencilRef` -Value to compare with or to be written to the mask buffer +用于与掩码缓冲比较或写入的值 ##### `stencilRefOverride` -Whether to use the buffer's current value as stencilRef, 0 or 1 is supported: +是否使用缓冲当前值作为stencilRef,支持0或1: -- `1`: Use the configured stencilRef. If stencilRef is configured, stencilRefOverride will automatically take 1 +- `1`:使用配置的stencilRef。若配置了stencilRef,stencilRefOverride会自动取1 -- `0`: Use the current value of the buffer as stencilRef, in this case do not configure stencilRef +- `0`:使用缓冲当前值作为stencilRef,此时不要配置stencilRef ##### `stencilReadMask` -The mask buffer value and the stencilRef value are bit-ANDed with stencilReadMask before being compared +掩码缓冲值与stencilRef值在比较前会分别与stencilReadMask做位与运算 ##### `stencilWriteMask` -The stencilRef value is bit-ANDed with stencilWriteMask before being written to the mask buffer +stencilRef值在写入掩码缓冲前会与stencilWriteMask做位与运算 -##### `frontFace` and `backFace` +##### `frontFace` 和 `backFace` -Configure which mask test function to use on the front or back of the grid. In addition, the order of judgment is mask detection first, then depth detection. You need to configure the following operations: +配置在网格正面或背面使用哪种掩码测试函数。此外判断顺序是先掩码检测再深度检测。需要配置以下操作: - +- `stencilFunc`: stencilRef与掩码缓冲比较时使用的方法,支持以下值: + - `Always`: 总是通过 + - `Equal`:stencilRef等于缓冲值时通过 + - `NotEqual`:stencilRef不等于缓冲值时通过 + - `Less`:stencilRef小于缓冲值时通过 + - `Greater`:stencilRef大于缓冲值时通过 + - `GreaterEqual`:stencilRef大于等于缓冲值时通过 + - `LessEqual`:stencilRef小于等于缓冲值时通过 -- `stencilFunc`: The method used when stencilRef is compared with the mask buffer, the following values are supported: - - `Always`: Always pass - - `Equal`: Passed when stencilRef is equal to the buffer value - - `NotEqual` :Passed when stencilRef is not equal to the buffer value - - `Less`:Passed when stencilRef is less than the buffer value - - `Greater`:Passed when stencilRef is greater than the buffer value - - `GreaterEqual`:Passed when stencilRef is greater than or equal to the buffer value - - `LessEqual`:Passed when stencilRef is less than or equal to the buffer value +- `stencilFailOp`:stencilFunc比较函数返回失败时执行的处理,支持以下值: + - `Keep`:保持缓冲原值 + - `Replace`:将stencilRef位与stencilWriteMask的值写入缓冲 -- `stencilFailOp`:The processing performed when the stencilFunc comparison function fails to return, supports the following values: - - `Keep`: Keep the original value of the buffer - - `Replace`: Writes the stencilRef bit and the value of stencilWriteMask to the buffer +- `stencilDepthFailOp`:stencilFunc比较函数返回成功但深度测试失败时执行的处理,支持以下值: + - `Keep`:保持缓冲原值 + - `Replace`:将stencilRef位与stencilWriteMask的值写入缓冲 -- `stencilDepthFailOp` : The stencilFunc comparison function returns success, but the processing performed when the depth test fails, supports the following values: - - `Keep`: Keep the original value of the buffer - - `Replace`: Writes the stencilRef bit and the value of stencilWriteMask to the buffer +- `stencilPassOp`: stencilFunc比较函数返回成功且深度测试成功时执行的处理,支持以下值: + - `Keep`:保持缓冲原值 + - `Replace`:将stencilRef位与stencilWriteMask的值写入缓冲 -- `stencilPassOp`: The stencilFunc comparison function returns successfully, and the processing executed when the depth test is successful, supports the following values: - - `Keep`: Keep the original value of the buffer - - `Replace`: Writes the stencilRef bit and the value of stencilWriteMask to the buffer +关联状态渲染环境配置: -Associated states rendering environment configuration: +- `StencilWrite`:启用掩码写入 -- `StencilWrite`:Enable mask writing +- `EnableStencilTest`: 启用掩码测试 -- `EnableStencilTest`: Enable mask testing - -Finally, let's look at an example: +最后看一个具体示例: ```json "shadow_back": { @@ -314,49 +309,49 @@ Finally, let's look at an example: } ``` -In the example, StencilWrite represents the support for writing to the mask buffer, EnableStencilTest represents the opening of the mask test, and the configuration of frontFace represents that the mask test always passes when the front face is rendered. If the depth test fails, the buffer value remains unchanged. If it also passes, the stencil bit and the value of stencilWriteMask will be written to the buffer, that is, 1 & 1 = 1 value. The configuration of backFace is also similar. +该示例中,StencilWrite表示支持向掩码缓冲写入,EnableStencilTest表示开启掩码测试,frontFace的配置表示渲染正面时掩码测试总是通过,若深度测试失败则保持缓冲值不变,若也都通过则将stencilRef位与stencilWriteMask的值写入缓冲,即1 & 1 = 1的值。backFace的配置也类似。 -#### Blend translucent object color blend +#### 半透明物体颜色混合 -The rendering of translucent objects needs to configure the blending factor. The final output rgb color value = current color value * source blending factor + color value in buffer * destination blending factor +半透明物体的渲染需要配置混合因子。最终输出的rgb颜色值 = 当前颜色值 * 源混合因子 + 缓冲中的颜色值 * 目标混合因子 ##### `blendSrc` -source mix factor +源混合因子 ##### `blendDst` -target blending factor +目标混合因子 ##### `alphaSrc` -The source blending factor when calculating alpha, usually not configured to take the default value +计算alpha时的源混合因子,通常不配置取默认值 ##### `alphaDst` -The target blending factor when calculating alpha, usually not configured to take the default value +计算alpha时的目标混合因子,通常不配置取默认值 -In total, the blending factor can take on the following values: +混合因子总共可以取以下值: -- `DestColor`: Buffer color value +- `DestColor`:缓冲颜色值 -- `SourceColor`: Current color value +- `SourceColor`:当前颜色值 - `Zero`: (0,0,0) - `One`: (1,1,1) -- `OneMinusDestColor`: (1,1,1) - buffer color value +- `OneMinusDestColor`: (1,1,1) - 缓冲颜色值 -- `OneMinusSrcColor`: (1,1,1) - current color value +- `OneMinusSrcColor`: (1,1,1) - 当前颜色值 -- `SourceAlpha`: The alpha value in the current color +- `SourceAlpha`:当前颜色中的alpha值 -- `DestAlpha`: Alpha value in buffer color +- `DestAlpha`:缓冲颜色中的alpha值 -- `OneMinusSrcAlpha`: 1 - alpha value in the current color value +- `OneMinusSrcAlpha`:1 - 当前颜色值中的alpha值 -In the engine, the default is: +引擎中默认取值为: - `blendSrc`:SourceAlpha @@ -366,253 +361,222 @@ In the engine, the default is: - `alphaDst`:OneMinusSrcAlpha -Associated states rendering environment configuration: +关联状态渲染环境配置: -- `Blending`: Enables color blending mode, often used to render translucent objects. After declaring this, it is usually necessary - to declare the blending factor blendSrc, blendDst +- `Blending`: 启用颜色混合模式,常用于渲染半透明物体。声明该选项后通常需要接着声明混合因子blendSrc、blendDst -- `DisableColorWrite`: Do not write color values to the color buffer, none of the RGBA channels are written +- `DisableColorWrite`:不向颜色缓冲区写入颜色值,RGBA通道均不写入 -- `DisableAlphaWrite`: Do not write transparency alpha values to the color buffer, allow RGB values to be written +- `DisableAlphaWrite`:不向颜色缓冲区写入透明度alpha值,允许写入RGB值 -- `DisableRGBWrite`: Do not write transparency RGB values to the color buffer, allow writing alpha values +- `DisableRGBWrite`:不向颜色缓冲区写入RGB值,允许写入alpha值 -#### Sample texture sample +### 模板测试配置 -##### `samplerStates` +#### `stencilRef` -Configure the sampling state, the value is a list, and configure each texture according to the number of textures to be sampled. Usually, if UV0 and UV1 are declared in the vertex attribute, it means that two textures need to be sampled, and two elements need to be configured here. Let's look at the definition of child elements: +用于与模板缓冲比较或写入的参考值 +#### `stencilRefOverride` + +是否使用缓冲当前值作为stencilRef,支持0或1: +- `1`:使用配置的stencilRef(若已配置stencilRef则自动取1) +- `0`:使用缓冲当前值作为stencilRef(此时不应配置stencilRef) + +#### `stencilReadMask` + +模板缓冲值与stencilRef值在比较前会分别与stencilReadMask进行位与运算 + +#### `stencilWriteMask` + +stencilRef值在写入模板缓冲前会与stencilWriteMask进行位与运算 + +#### `frontFace` 和 `backFace` + +配置在网格正面/背面使用的模板测试函数。测试顺序为先模板测试后深度测试。需配置以下操作: + +- `stencilFunc`: stencilRef与模板缓冲的比较方式,可选: + - `Always`: 总是通过 + - `Equal`:值相等时通过 + - `NotEqual`:值不等时通过 + - `Less`:小于时通过 + - `Greater`:大于时通过 + - `GreaterEqual`:大于等于时通过 + - `LessEqual`:小于等于时通过 + +- `stencilFailOp`:模板测试失败时的处理: + - `Keep`:保持缓冲原值 + - `Replace`:将stencilRef写入缓冲 + +- `stencilDepthFailOp`:模板测试通过但深度测试失败时的处理: + - `Keep`:保持缓冲原值 + - `Replace`:将stencilRef写入缓冲 + +- `stencilPassOp`:两项测试均通过时的处理: + - `Keep`:保持缓冲原值 + - `Replace`:将stencilRef写入缓冲 + +关联渲染状态: +- `StencilWrite`:启用模板写入 +- `EnableStencilTest`:启用模板测试 + +配置示例: +```json +"shadow_back": { + "+states": [ + "StencilWrite", + "DisableColorWrite", + "DisableDepthWrite", + "InvertCulling", + "EnableStencilTest" + ], + "frontFace": { + "stencilFunc": "Always", + "stencilFailOp": "Keep", + "stencilDepthFailOp": "Keep", + "stencilPassOp": "Replace" + }, + "backFace": { /* 相同配置 */ }, + "stencilRef": 1, + "stencilReadMask": 255, + "stencilWriteMask": 1 +} +``` + +### 半透明物体混合 + +最终颜色 = 当前颜色 × blendSrc + 缓冲颜色 × blendDst + +#### 混合因子 +- `blendSrc`:源混合因子(默认SourceAlpha) +- `blendDst`:目标混合因子(默认OneMinusSrcAlpha) +- `alphaSrc`:alpha源因子(默认One) +- `alphaDst`:alpha目标因子(默认OneMinusSrcAlpha) + +可选值: +- `DestColor`:缓冲颜色 +- `SourceColor`:当前颜色 +- `Zero`:(0,0,0) +- `One`:(1,1,1) +- `OneMinusDestColor`: 1-缓冲颜色 +- `OneMinusSrcColor`: 1-当前颜色 +- `SourceAlpha`:当前alpha值 +- `DestAlpha`:缓冲alpha值 +- `OneMinusSrcAlpha`:1-当前alpha值 + +关联状态: +- `Blending`:启用混合 +- `DisableColorWrite`:禁用颜色写入 +- `DisableAlphaWrite`:禁用alpha写入 +- `DisableRGBWrite`:禁用RGB写入 + +### 纹理采样 + +#### `samplerStates` +配置采样状态(列表结构,按纹理索引配置): ```json { - "samplerIndex": 0, - "textureFilter": "Point", - "textureWrap": "Repeat" + "samplerIndex": 0, // 纹理索引(从0开始) + "textureFilter": "Point", // 过滤模式 + "textureWrap": "Repeat" // 环绕模式 } ``` -Each property is defined as follows: +##### 过滤模式 +- `Point`:点采样 +- `Bilinear`:双线性 +- `Trilinear`:三线性 +- `MipMapBilinear`:MipMap双线性 +- `TexelAA`:抗锯齿(部分设备不支持) +- `PCF`:百分比渐近过滤(部分设备不支持) -##### `samplerIndex` +##### 环绕模式 +- `Repeat`:重复纹理 +- `Clamp`:边缘拉伸 -Number, representing the attribute of the texture that is currently being set, starting from 0 +### 顶点属性 -##### `textureFilter` +#### `vertexFields` +声明网格顶点包含的属性: +- `Position`:模型空间坐标 +- `Color`:颜色 +- `Normal`:法线 +- `UV0`/`UV1`/`UV2`:纹理坐标 +- `BoneId0`:骨骼ID(骨骼模型用) -Texture filtering mode (default is Point), when the actual displayed texture map is enlarged or reduced compared to the original image, the mapping relationship between the new resolution map and the pixels on the original resolution map can have the following values: +### 光栅化配置 +#### `msaaSupport` +抗锯齿支持模式: +- `NonMSAA`:非MSAA模式下启用 +- `MSAA`:MSAA模式下启用 +- `Both`:始终启用(推荐) -- `Point`: Point sampling +#### 深度偏移 +解决z-fighting问题: +- `depthBias`:基础偏移 +- `slopeScaledDepthBias`:斜率比例偏移 +- `depthBiasOGL`:OpenGL平台偏移 +- `slopeScaledDepthBiasOGL`:OpenGL斜率偏移 -- `Bilinear`: Bilinear sampling +计算公式: +`offset = (slopeScaledDepthBias × m) + (depthBias × r)` -- `Trilinear`: Trilinear sampling +### 图元模式 -- `MipMapBilinear`: MipMap bilinear sampling +#### `primitiveMode` +渲染图元类型: +- `None`:不渲染 +- `QuadList`:四边形列表 +- `TriangleList`:三角形列表(每3个顶点构成三角形) +- `TriangleStrip`:三角形带(复用顶点) +- `LineList`:线段列表 +- `Line`:线段带 -- `TexelAA`:Texel antialiasing (not supported on all devices, not recommended) - -- `PCF`:Sampling by comparison function (not supported on all devices, not recommended) - -##### `textureWrap` - -Texture wrapping mode, which controls what kind of texture should be sampled when uv is outside [0,1]. It can have the following values: - -- `Repeat`: Repeat, that is, modulo the value to [0, 1] for sampling - -- `Clamp`: Edge sampling, sampling the value of the closest edge, that is, if 1.1 is closer to 1, then take 1; if -0.1 is closer to 0, then take 0. - - -#### Vertex - -##### `vertexFields` - -Vertex attributes, which are used to declare what attributes each vertex of the mesh that is rendered using this material holds. It is determined when the art is producing resources. The following values ​​may be used: - -- `Position`: Model space coordinates - -- `Color`: Color - -- `Normal`: Normal - -- `UV0`: Texture sample coordinates - -- `UV1`:Texture sample coordinates - -- `UV2`:Texture sample coordinates - -- `BoneId0`: Bone ID, used in the bone model - -#### Rasterizer environment configuration - -##### `msaaSupport` - -Configure MSAA (Multi-Sample Anti-Aliasing) support (the default in the engine is NonMSAA) - -- `NonMSAA`: Materials are allowed when MSAA is not enabled - -- `MSAA`: Materials are allowed when MSAA is enabled - -- `Both`:Materials are allowed with or without MSAA enabled. Usually just use this value. - - -##### `depth offset` - -Depth offset is mainly used to solve the z-fighting problem, that is, when two objects have similar depths, some frames may display this object and some frames display another object when rendering. The principle of depth offset is to offset one of the objects in the direction of large or small depth, so that their depths are no longer the same. The following four variables can be configured: - -- depthBias - -- slopeScaledDepthBias - -- depthBiasOGL - -- slopeScaledDepthBiasOGL - -The specific offset depth is: - -`offset = (slopeScaledDepthBias * m) + (depthBias * r)` - -On the OGL platform it is: - -`offset = (slopeScaledDepthBiasOGL * m) + (depthBiasOGL * r)` - -m is the maximum value in the slope of the depth of the polygon (computed at the rasterization stage). The more parallel a polygon is to the near clipping plane, the closer m is to 0. r is the smallest value that produces a discernible difference in depth values ​​in the window coordinate system, and r is a constant specified by the platform that implements OpenGL. - -Associated states rendering environment configuration: - -- `Wireframe`: Draw wireframe mode - -- `DisableCulling`: Render front and back simultaneously - -- `InvertCulling`:Use front cropping. The default is back cropping. After declaring this, the back side is rendered and the front - side is cropped. - -#### Primitive - -##### `primitiveMode` - -Primitive rendering mode (the default in the engine is TriangleList): - -- `None`: Do not render, normally not used - -- `QuadList`:Quadrilateral pattern - -- `TriangleList`: A pattern of drawing a triangle every three vertices, for example the first triangle uses vertices v0, v1, v2, and the second uses v3, v4, v5 - -- `TriangleStrip`: Each vertex will form a triangle with the first two vertices, the structure is a bit more complicated, but it - will save the amount of data - -- `LineList`: Draw a line segment every two vertices - -- `Line`: Each vertex forms a line segment with a vertex that appears before it. - -### Material variant +### 材质变体 #### `variants` - -Useful for quickly implementing multiple sub-materials based on most of the same definitions. See the actual example of entity_static below: - +快速创建衍生材质: ```json - "entity_static": { - "vertexShader": "shaders/entity.vertex", - "vrGeometryShader": "shaders/entity.geometry", - "fragmentShader": "shaders/entity.fragment", - "vertexFields": [ - { "field": "Position" }, - { "field": "Normal" }, - { "field": "UV0" } - ], - "variants": [ +"base_material": { + "vertexShader": "...", + "variants": [ { - "skinning": { - "+defines": [ "USE_SKINNING" ], - "vertexFields": [ - { "field": "Position" }, - { "field": "BoneId0" }, - { "field": "Normal" }, - { "field": "UV0" } - ] - } + "variant1": { // 变体1 + "+defines": ["MACRO_1"], + "vertexFields": [...] + } }, { - "skinning_color": { - "+defines": [ "USE_SKINNING", "USE_OVERLAY" ], - "+states": [ "Blending" ], - "vertexFields": [ - { "field": "Position" }, - { "field": "BoneId0" }, - { "field": "Color" }, - { "field": "Normal" }, - { "field": "UV0" } - ] - } + "variant2": { // 变体2 + "+states": ["Blending"] + } } - ], - "msaaSupport": "Both", - "+samplerStates": [ - { - "samplerIndex": 0, - "textureFilter": "Point" - } - ] - } -``` - -Variants are declarations of material variants. The above declarations declare two sub-variants, skinning and skinning_color. Some external fields are rewritten in the sub-variants. In actual use, it is equivalent to quickly defining two materials. The body and the variant are connected with a dot ".". The two materials are entity_static.skinning and entity_static.skinning_color. - -In addition, if there are other materials that inherit from entity_static, such as entity_dynamic, this material will also inherit these two variants, entity_dynamic.skinning and entity_dynamic.skinning_color. - -## Material Merge Rules - -When the same material is declared in different directory files, it will be merged according to the following rules after loading: 1. Normally, the material fields of the files loaded later will overwrite the previously loaded ones. 2. The following fields are special. Operations to add attributes with "+" and delete attributes with "-" are supported: - -- defines -- states -- samplerStates - -As an example, for example, such a material is declared in the package body file (irrelevant code is omitted), and three macros are defined: - -```json -"testMat": { - "defines": [ "MACRO_1", "MACRO_2", "MACRO_3" ], + ] } ``` +使用时通过`base_material.variant1`调用变体 -At this point, a mod also declares this material, defining another three macros: +### 材质合并规则 +多文件定义同一材质时的合并策略: +1. 常规字段:后加载的覆盖先加载的 +2. 特殊字段(支持`+`/`-`操作符): + - `defines`:宏定义 + - `states`:渲染状态 + - `samplerStates`:采样状态 +执行顺序:覆盖 → 添加 → 删除 + +示例: ```json -"testMat": { - "defines": [ "MACRO_4", "MACRO_5", "MACRO_6" ], +// 基础定义 +"mat": {"defines": ["A","B"]} + +// 扩展定义(添加C,删除B) +"mat": { + "+defines": ["C"], + "-defines": ["B"] } -``` -In the above case, the final runtime is equivalent to the defines field being overwritten, and the macros that take effect at the actual runtime are only: MACRO_4, MACRO_5, MACRO_6 - -If the "+" symbol is used when defining in the MOD: - -```json -"testMat": { - "+defines": [ "MACRO_4", "MACRO_5", "MACRO_6" ], -} -``` - -Equivalent to adding definitions on the original basis, the macros that take effect at actual runtime are: MACRO_1, MACRO_2, MACRO_3, MACRO_4, MACRO_5, MACRO_6 - -If the "-" symbol is used when defining in the MOD: - -```json -"testMat": { - "-defines": [ "MACRO_3"], -} -``` - -It is equivalent to deleting some definitions on the original basis, the only macros that take effect at runtime are: MACRO_1, MACRO_2 - -If multiple files define the same material, and they involve overlay, add, and delete operations, the order in which they will take effect is: first perform all overlay operations, then perform all add operations, and finally perform all delete operations . - -i.e. if one of the material files declares a delete MACRO_3 action: - -```json -"testMat": { - "-defines": [ "MACRO_3"], -} -``` - -Then no matter how other files are covered, add MACRO_3, and this material must not have MACRO_3 macro after the final synthesis. \ No newline at end of file +// 最终效果:["A","C"] +``` \ No newline at end of file diff --git a/docs/wiki/documentation/sound-definitions.md b/docs/wiki/documentation/sound-definitions.md index 968df28e..fad84562 100644 --- a/docs/wiki/documentation/sound-definitions.md +++ b/docs/wiki/documentation/sound-definitions.md @@ -1,12 +1,25 @@ --- -title: Sound Definitions +title: 音效定义 mentions: - MedicalJewel105 --- -Sounds from `sound_definitions.json` sorted by categories and subcategories based on their names. -This page was created with [Wiki Content Generator](https://github.com/Bedrock-OSS/bedrock-wiki-content-generator). If there are issues, contact us on [Bedrock OSS](https://discord.gg/XjV87YN) Discord server. -*Last updated for 1.20.10* +# 音效定义 + + + +按名称分类整理的`sound_definitions.json`中的音效文件。 +本页面由[Wiki内容生成器](https://github.com/Bedrock-OSS/bedrock-wiki-content-generator)创建。如发现问题,请在[Bedrock OSS](https://discord.gg/XjV87YN) Discord服务器联系我们。 +*最后更新于1.20.10版本* + +::: tip 说明 +- 音效文件已根据名称进行了分类和子分类 +- 专业名词如`sound_definitions.json`保留英文原格式 +- 版本号保持数字格式不变 +- 链接和Discord服务器名称保留原文 +::: + +(注:由于原文主要是说明性文字且没有具体音效列表,因此翻译保留了原文结构,添加了说明提示框使页面更友好。如果后续需要补充具体音效分类列表,可以继续扩展翻译内容。) ## ambient diff --git a/docs/wiki/entities/index.md b/docs/wiki/entities/index.md index 1cfc92a4..c1031d6a 100644 --- a/docs/wiki/entities/index.md +++ b/docs/wiki/entities/index.md @@ -1,5 +1,6 @@ --- title: 实体 Entities +nav_order: 5 categories: - title: 基础 color: blue diff --git a/docs/wiki/guide/custom-entity.md b/docs/wiki/guide/custom-entity.md index 9251c6c0..c6391a9a 100644 --- a/docs/wiki/guide/custom-entity.md +++ b/docs/wiki/guide/custom-entity.md @@ -1,7 +1,7 @@ --- -title: 'Create a custom Entity' -category: Guide -description: How to create your first custom Entity +title: '创建自定义实体' +category: 指南 +description: 如何创建你的第一个自定义实体 nav_order: 6 prefix: '6. ' mentions: @@ -21,36 +21,38 @@ mentions: - ThomasOrs --- -Similarly to custom items, we can also make custom entities with many similar mechanics to the vanilla entities in the game. These entities can be incredibly powerful allowing you to make your own animals which can be bred and tamed or an aggressive mob that attacks anything it sees. +# 创建自定义实体 -Here we will make a ghost entity which will float, attack the player and drop our ectoplasm item on death. + + +与自定义物品类似,我们也可以创建具有与游戏中原版实体相似机制的自定义实体。这些实体可以非常强大,允许你制作可繁殖驯养的动物,或是会攻击所见一切的敌对生物。 + +本文将创建一个幽灵实体,它会漂浮移动、攻击玩家,并在死亡时掉落我们之前制作的灵质物品。


-Just like items, entities are made up of two parts: +和物品一样,实体由两部分组成: -- The visuals (texture, name, animations, sounds) -- The behaviors (movement, attacks) +- 视觉部分(纹理、名称、动画、音效) +- 行为部分(移动、攻击) -Differently though, we will need two main files for our entity called the _server_ file and the _client_ file which sit in our BP and RP respectively. -We will also need additional files to describe the geometry of our entity and its animations, but we will cover those in later sections. +不同的是,我们需要为实体创建两个主文件:分别放在行为包(BP)和资源包(RP)中的 _服务端_ 文件和 _客户端_ 文件。此外还需要额外的文件来描述实体的几何模型和动画,这些将在后续章节中介绍。 -First, we will cover how to create an entity & define its behavior. Next, we will look at how to add the visuals. +首先我们将介绍如何创建实体并定义其行为,然后再添加视觉效果。 -## Entity Behavior +## 实体行为 -Like with items, we need a file to tell our entity how to behave which points an identifier to certain components which define behavior. This file will be very similar to our item behavior file except with a lot more components. +与物品类似,我们需要一个文件来定义实体行为,通过标识符关联到具体的行为组件。这个文件的结构与物品行为文件非常相似,但包含更多组件。 -We define our server file in our BP, under the `BP/entities/` folder. We will call this file `ghost.se.json`. Here the `.se` stands for _server entity_. This is for clarity and is recommend in the [Style Guide](/wiki/meta/style-guide). +我们在行为包的`BP/entities/`文件夹下创建服务端文件,命名为`ghost.se.json`。这里的`.se`代表 _server entity_ (服务端实体),这是为了清晰起见,符合[样式指南](/wiki/meta/style-guide)的推荐。 -This is a basic overview of the file: +文件基本结构如下: -BP/entities/ghost.se.json - -```json +::: code-group +```json [BP/entities/ghost.se.json] { "format_version": "1.16.0", "minecraft:entity": { @@ -59,14 +61,14 @@ This is a basic overview of the file: } } ``` +::: -Just like with the items, we have our format version and here we have `"minecraft:entity"` as this is an entity file. From now on we won't comment on the format version and recommend to use the version example that we give. +与物品文件类似,我们有格式版本标识,这里使用`"minecraft:entity"`表示这是实体文件。后续我们将不再赘述格式版本,建议直接使用示例中的版本。 -For entities we have a little bit more information under `description`: +实体在`description`部分包含更多信息: -BP/entities/ghost.se.json#minecraft:entity - -```json +::: code-group +```json [BP/entities/ghost.se.json#minecraft:entity] "description": { "identifier": "wiki:ghost", "is_summonable": true, @@ -74,29 +76,26 @@ For entities we have a little bit more information under `description`: "is_experimental": false } ``` +::: -The `identifier` key serves the same purpose, to point to which entity we are talking about. -The other keys determine what ways we can add the entity to our world: +`identifier`键的作用与之前相同,用于标识这个实体。其他键决定了实体加入世界的方式: -- `is_summonable` : Whether it can be summoned using the `/summon` command. -- `is_spawnable` : Whether it can spawn in the world using a spawn egg or spawn rules. -- `is_experimental`: Whether the entity is experimental (if so it can only be added to Experimental Worlds). +- `is_summonable`:是否可以通过`/summon`命令召唤 +- `is_spawnable`:是否可以通过刷怪蛋或生成规则在世界中自然生成 +- `is_experimental`:是否为实验性实体(如果是则只能添加到实验性世界) -We recommend leaving the settings as they are here as any changes will make it harder to test your entity in game. +建议保持这些设置不变,因为任何更改都会使你在游戏中测试实体变得更加困难。 -### Components +### 组件 -An entity has a lot more behaviors than just an item, so we need to define more components for it. -We will break down the types of components will use into categories and then look at them closer. -For more information on components in entities, you can check out our page [here](/wiki/entities/entity-intro-bp). +实体比物品拥有更多行为,因此需要定义更多组件。我们将这些组件分类并详细讲解。更多关于实体组件的信息,可以参考[此页面](/wiki/entities/entity-intro-bp)。 -### Stat Components +### 基础属性组件 -These are the components that you will generally have on every entity. This define some core attributes to your entity. +这些是每个实体通常都会具备的组件,定义了实体的核心属性。 -BP/entities/ghost.se.json#minecraft:entity#components - -```json +::: code-group +```json [BP/entities/ghost.se.json#minecraft:entity#components] "minecraft:type_family": { "family": ["ghost", "monster"] }, @@ -118,22 +117,22 @@ These are the components that you will generally have on every entity. This defi "table": "loot_tables/entities/ghost.json" }, ``` +::: -The components `minecraft:health` and `minecraft:attack` and `minecraft:movement` are straight forward and set the entities health, attack damage and movement speed. The collision box of an entity is the box within which the entity interacts with or collides with blocks or other entities. This is defined with `minecraft:collision_box` which will center the box on the middle on the entity. +`minecraft:health`、`minecraft:attack`和`minecraft:movement`组件直接设置实体的生命值、攻击伤害和移动速度。实体的碰撞箱是它与方块或其他实体交互/碰撞的范围,由`minecraft:collision_box`定义,这个箱子会以实体为中心。 -`minecraft:type_family` adds family tags to the entity. Family tags are used to group entities in a similar category together. For example `monster` includes zombies, skeletons and creepers. This allows us to be able to select all entities with the `monster` tag. +`minecraft:type_family`为实体添加家族标签。家族标签用于将相似类别的实体分组。例如`monster`包括僵尸、骷髅和苦力怕,这样我们就可以选择所有带有`monster`标签的实体。 -`minecraft:loot` defines the path to the loot table that the entity will drop on death. We will create this loot table in a later section using this path. +`minecraft:loot`定义了实体死亡时掉落的战利品表路径。我们将在后续章节使用这个路径创建战利品表。 -### Movement Components +### 移动组件 -In order for an entity to move around, we need to define two things, _how_ it moves and _where_ it can move to. This is defined using the `movement` and `navigation` components respectively. +为了让实体能够移动,我们需要定义两件事: _如何_ 移动和 _可以_ 移动到哪里。这分别通过`movement`和`navigation`组件实现。 -You will always need a `movement` and `navigation` component if you want your entity to be able to move. +如果你希望实体能够移动,就必须包含`movement`和`navigation`组件。 -BP/entities/ghost.se.json#minecraft:entity#components - -```json +::: code-group +```json [BP/entities/ghost.se.json#minecraft:entity#components] "minecraft:physics": {}, "minecraft:jump.static": {}, "minecraft:movement.basic": {}, @@ -144,51 +143,51 @@ You will always need a `movement` and `navigation` component if you want your en "can_open_doors": true } ``` +::: -`minecraft:physics` is used to apply gravity and collision to your entity. Note: you can not change this component via using a component group. -`minecraft:jump.static` allows your entity to jump up blocks for traversal. Both are used on almost every entity. +`minecraft:physics`用于给实体应用重力和碰撞。注意:你不能通过组件组来修改这个组件。 +`minecraft:jump.static`允许你的实体跳跃以跨越障碍。这两个组件几乎用于所有实体。 -There are few different types of movement components which allow different types of movement such as `minecraft:movement.swim` used by dolphins, `minecraft:movement.fly` used by parrots and `minecraft:movement.hover` used by bees. -The `minecraft:movement.basic` component allows our entity to walk by moving over blocks. To make it seem like our entity is actually floating, we will use our geometry . +有几种不同的移动组件允许不同类型的移动,例如海豚使用的`minecraft:movement.swim`、鹦鹉使用的`minecraft:movement.fly`和蜜蜂使用的`minecraft:movement.hover`。 +`minecraft:movement.basic`组件允许我们的实体通过在地面上行走来移动。为了让实体看起来像是在漂浮,我们将使用几何模型。 -The navigation component is a pathfinder which defines what paths we allow our entity to follow. For example skeletons will try not to walk in sunlight, so their pathing stops them from taking paths that would put them in sunlight. Additionally, parrots can fly so they can path into the air unlike walking mobs. +导航组件是一个路径寻找器,定义了允许实体遵循的路径。例如骷髅会尽量避免走在阳光下,所以它们的路径规划会阻止它们选择阳光下的路径。此外,鹦鹉可以飞行,所以它们可以在空中移动,这与行走的生物不同。 -These components have a lot of different settings which allow for interesting pathing. The settings we've chosen let our ghost walk along the ground, avoid stepping into sunlight, pass through doorways and open doors. +这些组件有许多不同的设置,可以实现有趣的路径规划。我们选择的设置让幽灵可以在地面上行走,避免阳光直射,穿过门道并开门。 -### Behavior Components +### 行为组件 -While we have defined _how_ our entity does things, we haven't yet defined _when_ or _what_ they do. This is where `.behavior` components come in. These components define the specific actions that our entity will do. -For example, villagers will try to breed so they have the `minecraft:behavior.breed` component and tamed wolves follow their owners so they have the `minecraft:behavior.follow_owner` component. +虽然我们已经定义了实体 _如何_ 做事情,但还没有定义 _何时_ 或 _做什么_ 。这就是`.behavior`组件的作用。这些组件定义了实体将执行的特定动作。 +例如,村民会尝试繁殖,所以他们有`minecraft:behavior.breed`组件,而被驯服的狼会跟随主人,所以他们有`minecraft:behavior.follow_owner`组件。 -We want our ghost to be able to idly walk and look around, target the player when nearby and then attack them. Here are the components that we use: +我们希望幽灵能够闲逛和环顾四周,在玩家靠近时锁定目标并攻击。以下是使用的组件: -BP/entities/ghost.se.json#minecraft:entity#components - -```json -// Allow for random movement and looking around +::: code-group +```json [BP/entities/ghost.se.json#minecraft:entity#components] +// 允许随机移动和环顾四周 "minecraft:behavior.random_stroll": {...}, "minecraft:behavior.random_look_around": {...}, "minecraft:behavior.look_at_player": {...}, -// Allow for targeting +// 允许锁定目标 "minecraft:behavior.hurt_by_target": {...}, "minecraft:behavior.nearest_attackable_target": {...}, -// Allow for attacking +// 允许攻击 "minecraft:behavior.delayed_attack": {...} ``` +::: -The first component, `minecraft:behavior.random_stroll` allows our entity to choose a random point nearby to path to periodically. This path is created with our `navigation` component and then the type of movement is defined by our `movement` component. +第一个组件`minecraft:behavior.random_stroll`允许我们的实体定期选择一个附近的随机点进行移动。这个路径由我们的`navigation`组件创建,然后移动类型由`movement`组件定义。 -The next two components allow our entity to randomly look around and to look at the player if they are within range. +接下来的两个组件允许实体随机环顾四周,并在玩家进入范围内时注视玩家。 -For attacking, in order for our entity to attack, it needs a `target`. The two behaviors `minecraft:behavior.hurt_by_target` and `minecraft:behavior.nearest_attackable_target` will cause the entity to target any entity that hurts it and target any the nearest enemy to it within range. +为了攻击,实体需要一个`target`。`minecraft:behavior.hurt_by_target`和`minecraft:behavior.nearest_attackable_target`行为会使实体锁定任何伤害它的目标,并在范围内锁定最近的敌人。 -Finally, the `minecraft:behavior.delayed_attack` is how our entity actually attacks it target. +最后,`minecraft:behavior.delayed_attack`是实体实际攻击目标的方式。 -Each of these behaviors have further settings to tweak the exact behavior we want. +每个行为都有更多设置可以调整具体行为。 -BP/entities/ghost.se.json#minecraft:entity#components - -```json +::: code-group +```json [BP/entities/ghost.se.json#minecraft:entity#components] "minecraft:behavior.random_stroll": { "priority": 6, "speed_multiplier": 1 @@ -235,24 +234,24 @@ Each of these behaviors have further settings to tweak the exact behavior we wan "hit_delay_pct": 0.5 } ``` +::: -For more details about what each of these options do, you can read about them on the official documentation, [bedrock.dev](https://bedrock.dev/docs/stable/Entities). +有关这些选项的更多详细信息,可以在官方文档[bedrock.dev](https://bedrock.dev/docs/stable/Entities)上阅读。 -#### Priority +#### 优先级 -All behaviors contain a `"priority"` field. This field is used to decide which behavior to run when many can. +所有行为都包含一个`"priority"`字段。这个字段用于决定当多个行为可以运行时选择哪一个。 -When the entity is picking something to do, it searches all its behaviors from lowest priority to the highest priority and picks the first one that it can do. For this reason, you need to make important behaviors like `minecraft:behavior.nearest_attackable_target` lower than behaviors like `minecraft:behavior.look_at_player`. If the `look_at_player` behavior is lower, it will always run this first when the player is close, and the entity will never attack. +当实体选择要执行的动作时,它会从最低优先级到最高优先级搜索所有行为,并选择第一个可以执行的行为。因此,你需要将重要的行为(如`minecraft:behavior.nearest_attackable_target`)设置为比`minecraft:behavior.look_at_player`等行为更低的优先级。如果`look_at_player`行为的优先级较低,当玩家靠近时,实体总是会先执行这个行为,而永远不会攻击。 -In general, important behaviors will have a priority of `0` or `1`. +一般来说,重要行为的优先级为`0`或`1`。 -### Full Entity Server File +### 完整实体服务端文件 - +::: details 完整的ghost.se.json -BP/entities/ghost.se.json - -```json +::: code-group +```json [BP/entities/ghost.se.json] { "format_version": "1.16.0", "minecraft:entity": { @@ -342,33 +341,30 @@ In general, important behaviors will have a priority of `0` or `1`. } } ``` +::: - +至此我们完成了实体行为文件。 -With that we have completed our entity behavior file. +更复杂的实体还可以有不同的_状态_,根据所处状态表现出不同行为。例如,野生的狼会自由走动,但被驯服后会跟随玩家。一个_事件_(被驯服)导致狼改变了_状态_。这个功能允许我们创建动态实体,在不同事件发生时执行不同动作。你可以在[本指南](/wiki/entities/entity-intro-bp)中了解更多。 -More complex entities can also have different _states_, where they will behave differently depending on what state they are in. For example, a wild wolf will walk around freely, but once it is tamed it will follow the player. An _event_ (being tamed) caused the wolf to change _states_. This feature allows us to create dynamic entities which can perform different actions when different events occurs. You can learn more about this in our guide [here](/wiki/entities/entity-intro-bp). +如果你现在打开世界并尝试用`/summon wiki:ghost`召唤实体,它的行为应该符合预期,但地面上只会显示一个影子。你可能还会看到它的名称显示为翻译键,就像我们的物品一样。 -If you open your world and try to summon in your entity using `/summon wiki:ghost`, it should behave like we expect but there will only be a shadow on the ground. You might also see its name as a translation key, similar to how it happened with our item. +接下来我们将学习如何创建资源(客户端)文件,以及如何分配纹理、几何模型和动画。 -Next we will learn how to create our resource or client file and how to assign our texture, geometry and animations. +## 实体资源 -## Entity Resource +为实体添加视觉效果与物品截然不同。由于涉及更多组成部分,我们需要一个专门的文件来定义资源。这个文件称为实体_客户端文件_,我们将其命名为`ghost.ce.json`,存放在`RP/entity/`文件夹中。 -Applying visuals to an entity is very different to an item. Since there are a lot more pieces, we have a separate file dedicated to defining the resources. -This is the called entity _client file_ which we will name `ghost.ce.json`. These files go in the folder `RP/entity/`. +本节将使用为幽灵实体创建的示例资源,演示如何将它们添加到实体中。在指南的下一节中,我们将介绍如何使用专业3D编辑器Blockbench创建自己的实体几何模型和动画。 -In this section, we will use the example resources created for our ghost entity to demonstrate how to add them to an entity. In the next section of the guide, we explain how to use Blockbench, a dedicated 3D editor, to create your own entity geometry and animations. +### 模型 -### Model +实体的"模型"即其形状,也称为"几何模型"。这描述了实体的外形,比如猪是由一个箱体和四条腿加头部组成,而鸡则有两条腿、一个头部和翅膀。几何模型以JSON格式存储在`RP/models/entity/`目录下,我们的文件将命名为`ghost.geo.json`。 -The 'model' for our entity is the shape of our entity, also called the 'geometry'. This describes the shape of our entity, like how a pig is a box with 4 legs and a head whereas a chicken has 2 legs, a head and wings. The geometry is stored as a JSON file in `RP/models/entity/` and ours will be named `ghost.geo.json`. +这个文件由Blockbench自动生成,因此无需手动学习其语法。所以我们不会深入分析文件细节。它存储了模型中每个方块的数据,包括大小、位置和旋转等。 -This file is automatically generated by Blockbench for us, so there is no need to learn its syntax by hand. As such, we won't go into full detail when looking at the file. It stores the data about each block in our model, such as size, position and rotation. - -RP/models/entity/ghost.geo.json - -```json +::: code-group +```json [RP/models/entity/ghost.geo.json] { "format_version": "1.12.0", "minecraft:geometry": [ @@ -436,32 +432,32 @@ This file is automatically generated by Blockbench for us, so there is no need t ] } ``` +::: -The important information that we need is the `identifier` which we will use to reference our geometry file, which here is `geometry.ghost`. +我们需要的关键信息是`identifier`,这里为`geometry.ghost`,这将用于引用我们的几何模型文件。 -### Texture +### 纹理 -Our entity now has its shape, but it also needs a texture. This texture can also be created in Blockbench and is simply a `.png` file. +现在实体有了形状,但还需要纹理。这个纹理也可以在Blockbench中创建,是一个简单的`.png`文件。 `RP/textures/entity/ghost.png` ![ectoplasm.png](https://raw.githubusercontent.com/Bedrock-OSS/wiki-addon/main/ma-guide/guide_RP/textures/entity/ghost.png) -Download texture here +点击下载纹理 -You may recall, when we made our item, we assigned a shortname to our texture to reference later. We will be doing something similar for our entity within our entity file, so make sure you keep the file path to the texture. +你可能记得,在制作物品时,我们为纹理分配了一个短名称以便后续引用。我们将在实体文件中为实体纹理做类似操作,所以请确保记住纹理的文件路径。 -### Animations +### 动画 -Animations allow our entity to have more life and move in different ways. We can have as many animations for an entity as we want and we can also trigger them at different types using an _animation controller_ which we will cover in the next section. +动画让我们的实体更具生命力,能够以不同方式移动。我们可以为实体创建任意数量的动画,还可以使用_动画控制器_在不同时间触发它们,这将在下一节介绍。 -Depending on your entity, you may want different animations. For our ghost we will have an `idle`, `attack` and `move` animation. These files are also created automatically in Blockbench, so we won't look into it in full detail. +根据你的实体需求,可能需要不同的动画。我们的幽灵将有`idle`(待机)、`attack`(攻击)和`move`(移动)动画。这些文件同样由Blockbench自动生成,所以我们不会深入细节。 -An animation file can contain one or multiple animations within it. Our animations will all be under one file called `ghost.a.json` under `RP/animations/`. +一个动画文件可以包含一个或多个动画。我们的所有动画将放在`RP/animations/`目录下的`ghost.a.json`文件中。 -RP/animations/ghost.a.json - -```json +::: code-group +```json [RP/animations/ghost.a.json] { "format_version": "1.8.0", "animations": { @@ -471,19 +467,19 @@ An animation file can contain one or multiple animations within it. Our animatio } } ``` - -Each animation is defined by the key, so here our three animation identifiers are `animation.ghost.idle`, `animation.ghost.attack` and `animation.ghost.move`. - -:::tip NOTE -If you have multiple animation files for one entity, consider moving them all into one file to keep your folders easy to read and navigate. -If not, ensure that when you are referencing the animation in your entity file, you use the animation identifier and _not_ the file name. ::: - +每个动画由键定义,所以这里我们的三个动画标识符是`animation.ghost.idle`、`animation.ghost.attack`和`animation.ghost.move`。 -RP/animations/ghost.a.json +:::tip 提示 +如果一个实体有多个动画文件,考虑将它们合并到一个文件中,以保持文件夹结构清晰易读。 +如果不合并,请确保在实体文件中引用动画时使用动画标识符,而不是文件名。 +::: -```json +::: details 完整动画文件 + +::: code-group +```json [RP/animations/ghost.a.json] { "format_version": "1.8.0", "animations": { @@ -596,21 +592,21 @@ If not, ensure that when you are referencing the animation in your entity file, } } ``` +::: - -### Animation Controller -We have our animations but our entity won't know when to play them. This is where animation controllers are used. These controllers at their core, _control_ how the animations are played. -An animation controller is made up of _states_ and _transitions_ between states. This allows us to play certain animations when the entity is in certain states, which we can transition between when certain conditions are met. +### 动画控制器 -For example, while an entity is moving, transition to the moving state which plays the `move` animation. Or while an entity is attacking, transition to the attack state which plays the `attack` animation. +有了动画,但实体还不知道何时播放它们。这时就需要动画控制器。这些控制器本质上_控制_动画的播放方式。 +动画控制器由_状态_和状态间的_过渡_组成。这让我们可以在实体处于特定状态时播放特定动画,并在满足条件时在不同状态间切换。 -Let us look at our animation controller for attacking. +例如,当实体移动时,切换到移动状态并播放`move`动画;或者当实体攻击时,切换到攻击状态播放`attack`动画。 -RP/animation_controllers/ghost.ac.json#animation_controllers +让我们看看攻击动画控制器: -```json +::: code-group +```json [RP/animation_controllers/ghost.ac.json#animation_controllers] "controller.animation.ghost.attack": { "states": { "default": { @@ -632,12 +628,11 @@ Let us look at our animation controller for attacking. } } ``` +::: -You can see we have two states, `default` and `attacking`. Our entity begins in the default state. +可以看到有两个状态:`default`和`attacking`。实体初始处于default状态。 -You can see under `transitions`, we have a condition, which when true will transfer the entity to a state. - - +在`transitions`下,有一个条件,当为真时将转换实体到另一个状态。 ```json { @@ -645,19 +640,18 @@ You can see under `transitions`, we have a condition, which when true will trans } ``` -Here, `attacking` is the state that will be transitioned to, and `q.is_delayed_attacking` is the condition that needs to be true for the transition to occur. -This condition is called a _query_. These queries can tell us things about the entity such as if it is attacking or moving. The query `q.is_delayed_attacking` will return `true` when the entity is performing the attack behavior. +这里,`attacking`是要转换到的目标状态,`q.is_delayed_attacking`是触发转换的条件。 +这个条件称为_查询_。这些查询可以告诉我们关于实体的信息,比如它是否正在攻击或移动。查询`q.is_delayed_attacking`会在实体执行攻击行为时返回`true`。 -When the entity is in the `attacking` state, it also has a transition back to the default state. Now the condition is `!q.is_delayed_attacking`. Here the `!` means _not_, so it will return the opposite result of `q.is_delayed_attacking` (If `q.is_delayed_attacking` returns `true` then `!q.is_delayed_attacking` returns false). +当实体处于`attacking`状态时,也有一个返回default状态的过渡。现在的条件是`!q.is_delayed_attacking`。这里的`!`表示_非_,所以它会返回`q.is_delayed_attacking`的相反结果(如果`q.is_delayed_attacking`返回`true`,那么`!q.is_delayed_attacking`返回false)。 -This state also has `animations`. These are the animations that will always play while in this state. Note that we are using the _shortname_ for our animation here, which we will reference in our entity file later. If you don't, the animations will not play. -There is also the `blend_transition` key, which allows the animations to slowly fade into each other. A higher number means a longer blending time. +这个状态还有`animations`。这些动画将在处于该状态时持续播放。注意这里我们使用的是动画的_短名称_,稍后将在实体文件中引用。如果不这样做,动画将不会播放。 +还有`blend_transition`键,允许动画之间缓慢过渡融合。数值越大,过渡时间越长。 -We can also make a similar controller for our `move` and `idle` animation. +我们也可以为`move`和`idle`动画创建类似的控制器。 -RP/animation_controllers/ghost.ac.json#animation_controllers - -```json +::: code-group +```json [RP/animation_controllers/ghost.ac.json#animation_controllers] "controller.animation.ghost.walk": { "initial_state": "standing", "states": { @@ -682,18 +676,18 @@ We can also make a similar controller for our `move` and `idle` animation. } } ``` +::: -This follows a similar pattern with some additions. -We now have `initial_state` which tells the controller which state to start on. If none is listed then it will start on the state `default`. -You'll also notice our queries look slightly different. Here the query `q.modified_move_speed` returns a value, so in order to return a boolean (i.e. true or false) we look at when the value is above or below `0.1`. For more in depth information on animation controllers, you can read [here](/animation-controllers/animation-controllers-intro). +这遵循类似的模式,但有一些新增内容。 +现在有了`initial_state`,告诉控制器从哪个状态开始。如果没有指定,则默认为`default`状态。 +你还会注意到我们的查询有些不同。这里的查询`q.modified_move_speed`返回一个值,所以为了返回布尔值(即真或假),我们检查该值是否大于或小于`0.1`。有关动画控制器的更多详细信息,可以阅读[这里](/animation-controllers/animation-controllers-intro)。 -Now that we have our animation controllers, we can add them to our animation controller file. Similarly to animations, the key is the identifier for our animation controller; `controller.animation.ghost.attack` and `controller.animation.ghost.walk`. +现在有了动画控制器,我们可以将它们添加到动画控制器文件中。与动画类似,键是我们的动画控制器标识符:`controller.animation.ghost.attack`和`controller.animation.ghost.walk`。 -Our file will be called `ghost.ac.json` and will be placed in `RP/animation_controllers/`. +我们的文件将命名为`ghost.ac.json`,放在`RP/animation_controllers/`目录下。 -RP/animation_controllers/ghost.ac.json - -```json +::: code-group +```json [RP/animation_controllers/ghost.ac.json] { "format_version": "1.12.0", "animation_controllers": { @@ -743,17 +737,17 @@ Our file will be called `ghost.ac.json` and will be placed in `RP/animation_cont } } ``` +::: -With that, we have created all the resources we need for our entity. We will now create our entity file. +至此,我们已经创建了实体所需的所有资源。现在我们将创建实体文件。 -### Entity Client File +### 实体客户端文件 -The client file contains all the references to the visual components of our entity. -Our client file will go in `RP/entity/` and we name this file `ghost.ce.json`. This file will have all our information under the `description` key. We begin with the familiar formatting: +客户端文件包含实体所有视觉组件的引用。 +我们的客户端文件将放在`RP/entity/`目录下,命名为`ghost.ce.json`。这个文件的所有信息都在`description`键下。我们从熟悉的格式开始: -RP/entity/ghost.ce.json - -```json +::: code-group +```json [RP/entity/ghost.ce.json] { "format_version": "1.10.0", "minecraft:client_entity": { @@ -763,22 +757,22 @@ Our client file will go in `RP/entity/` and we name this file `ghost.ce.json`. T } } ``` +::: -We use the same identifier as for our behavior file in order to point to the correct entity. +我们使用与行为文件相同的标识符,以指向正确的实体。 -To begin, we need to define the visuals of our entity in our file so we know which models and textures we are using. We also need to do the same for our animations and animation controllers. +首先,我们需要在文件中定义实体的视觉效果,这样游戏就知道使用哪些模型和纹理。我们还需要为动画和动画控制器做同样的事。 -#### Render Controller +#### 渲染控制器 -In order to display our entity it needs to be _rendered_. For this to happen, it needs a material, texture and geometry. We have already made a texture and geometry. A material defines how our texture will be displayed. For example, a skeleton uses a material to allow for transparency and an enderman uses a material to allow its eyes to glow. +为了显示实体,它需要被_渲染_。为此,它需要材质、纹理和几何模型。我们已经创建了纹理和几何模型。材质定义了纹理如何显示。例如,骷髅使用材质实现透明度,末影人使用材质让眼睛发光。 -Since our ghost has some transparency, we need a material which will render this correctly. Luckily, Minecraft has many pre-built materials for us to use such as `entity_alphatest` which will allow us to do this. You can create your own materials but be warned it is very advanced. If you are interested though, you can begin [here](/wiki/documentation/materials). +由于我们的幽灵有一定透明度,我们需要一个能正确渲染这一效果的材质。幸运的是,Minecraft有许多预置材质可供使用,比如`entity_alphatest`就能满足我们的需求。你可以创建自己的材质,但要注意这非常复杂。如果有兴趣,可以从[这里](/wiki/documentation/materials)开始学习。 -For us to now use these resources, we need to define a reference to them with a shortname. This is similar to how we did for items within the `item_texture.json` file, except here we do it in the entity client file. Here is the layout. +为了使用这些资源,我们需要用短名称定义对它们的引用。这与在`item_texture.json`文件中为物品所做的类似,只不过这里是在实体客户端文件中完成。以下是布局: -RP/entity/ghost.ce.json - -```json +::: code-group +```json [RP/entity/ghost.ce.json] { "format_version": "1.10.0", "minecraft:client_entity": { @@ -797,17 +791,17 @@ For us to now use these resources, we need to define a reference to them with a } } ``` +::: -Here for each category we have assigned the shortname `default` for each of our resources, ensuring to use the correct paths and identifiers. We are able to define multiple of these, though that is more advanced. Now we can use these shortnames to reference our resources. +这里我们为每个资源类别分配了短名称`default`,确保使用正确的路径和标识符。我们可以定义多个这样的资源,但这属于更高级的内容。现在我们可以使用这些短名称来引用我们的资源。 -In order for these resources to be rendered, we need to tell the game which resources to render in. This is controlled with a _render controller_. The controller tells the game which geometry, material and texture to render for the entity, allowing us to see it in game. +为了让这些资源被渲染,我们需要告诉游戏要渲染哪些资源。这是通过_渲染控制器_实现的。控制器告诉游戏要为实体渲染哪个几何模型、材质和纹理,让我们能在游戏中看到它。 -The render controller is defined in a separate file and uses the shortnames we defined in our entity file. -The file is called `ghost.rc.json` and is under `RP/render_controllers/`: +渲染控制器定义在单独的文件中,使用我们在实体文件中定义的短名称。 +文件名为`ghost.rc.json`,位于`RP/render_controllers/`目录下: -RP/render_controllers/entity/ghost.rc.json - -```json +::: code-group +```json [RP/render_controllers/entity/ghost.rc.json] { "format_version": "1.10.0", "render_controllers": { @@ -823,27 +817,27 @@ The file is called `ghost.rc.json` and is under `RP/render_controllers/`: } } ``` - -This follows a similar structure to the animation controller and animation file, with our render controller identifier being `controller.render.ghost`. -This tells the game that the resource rendered should be the resource with shortname `default`. Render controllers can also allow you to display different textures or apply different materials to different parts of our model. Under `materials`, we use `"*"` to mean that we apply this material to all _bones_ in our model (i.e. each cube in our model.) For more information on render controllers, you can check our page [here](/wiki/entities/render-controllers). - -:::tip -If you keep your shortnames consistent, you can actually reference the same render controller for multiple entities. ::: -Now to tell your entity to use this render controller, we add it to our entity file like so: +这与动画控制器和动画文件的结构类似,我们的渲染控制器标识符是`controller.render.ghost`。 +这告诉游戏渲染的资源应该是短名称为`default`的资源。渲染控制器还可以让你为模型的不同部分显示不同纹理或应用不同材质。在`materials`下,我们使用`"*"`表示将材质应用到模型中的所有_骨骼_(即模型中的每个方块)。有关渲染控制器的更多信息,可以查看[此页面](/wiki/entities/render-controllers)。 -RP/entity/ghost.ce.json#description +:::tip 提示 +如果保持短名称一致,你实际上可以为多个实体引用同一个渲染控制器。 +::: -```json +现在要让你的实体使用这个渲染控制器,我们像这样将其添加到实体文件中: + +::: code-group +```json [RP/entity/ghost.ce.json#description] "render_controllers": ["controller.render.ghost"] ``` +::: -With that our entity file should look like this. +这样我们的实体文件应该如下所示: -RP/entity/ghost.ce.json - -```json +::: code-group +```json [RP/entity/ghost.ce.json] { "format_version": "1.10.0", "minecraft:client_entity": { @@ -863,16 +857,16 @@ With that our entity file should look like this. } } ``` +::: -Now if we spawn our entity into a world, we should be able to see it. +现在如果我们将实体生成到世界中,应该能看到它了。 -#### Scripts +#### 脚本 -Now let us add our animations. Like with our other resources, we need to define shortnames for them. Keep in mind, we also need to define shortnames our animation controllers as well. +现在添加我们的动画。与其他资源一样,我们需要为它们定义短名称。注意,我们还需要为动画控制器定义短名称。 -RP/entity/ghost.ce.json#description - -```json +::: code-group +```json [RP/entity/ghost.ce.json#description] "animations": { "walk_controller": "controller.animation.ghost.walk", "attack_controller": "controller.animation.ghost.attack", @@ -881,14 +875,14 @@ Now let us add our animations. Like with our other resources, we need to define "move": "animation.ghost.move" } ``` +::: -You'll recall, these are the shortnames we used in our animation controllers; any animations we want to use in animation controllers, must be defined with a shortname in the entity client file. +你可能记得,这些是我们在动画控制器中使用的短名称;任何要在动画控制器中使用的动画,都必须在实体客户端文件中用短名称定义。 -Now that we have animations and animation controllers referenced, we need to decide when the entity will run them. This is done using `scripts`: +现在有了引用的动画和动画控制器,我们需要决定实体何时运行它们。这是通过`scripts`实现的: -RP/entity/ghost.ce.json#description - -```json +::: code-group +```json [RP/entity/ghost.ce.json#description] "scripts": { "animate": [ "walk_controller", @@ -896,25 +890,26 @@ Now that we have animations and animation controllers referenced, we need to dec ] } ``` +::: -Here, `scripts` tell the entity to perform certain actions at certain times. The `animate` key will run any animation or controller referenced every tick. This means that each tick our animation controller will check whether to transition to a new state and perform any animations in the state they are in. +这里,`scripts`告诉实体在特定时间执行特定动作。`animate`键会每tick运行任何引用的动画或控制器。这意味着每个tick我们的动画控制器都会检查是否要转换到新状态,并执行当前状态中的任何动画。 -With this our animations should be working correctly. +这样我们的动画应该能正确工作了。 -#### Spawn Egg +#### 刷怪蛋 -The final step to finalise our entity client file, is to create a spawn egg for our entity. Luckily, our file can generate one for us with the key `spawn_egg`. +完成实体客户端文件的最后一步是为我们的实体创建一个刷怪蛋。幸运的是,我们的文件可以通过`spawn_egg`键自动生成一个。 -RP/entity/ghost.ce.json#description - -```json +::: code-group +```json [RP/entity/ghost.ce.json#description] "spawn_egg": { "overlay_color": "#bdd1d1", "base_color": "#9fb3b3" } ``` +::: -This will generate a spawn egg which will summon our entity when used. It uses the hex codes in `base_color` and `overlay_color` to color the egg. If you want a custom icon for your spawn egg, instead use the key `texture` and put in the shortname to the texture you want. Follow the method in the item tutorial on how to define an texture shortname for an item. +这将生成一个使用时会召唤我们实体的刷怪蛋。它使用`base_color`和`overlay_color`中的十六进制代码为蛋着色。如果想要刷怪蛋有自定义图标,可以使用`texture`键并放入所需纹理的短名称。按照物品教程中的方法为物品定义纹理短名称。 ```json "spawn_egg": { @@ -922,13 +917,12 @@ This will generate a spawn egg which will summon our entity when used. It uses t } ``` -With that, we have completed our entity client file. +至此,我们已经完成了实体客户端文件。 - +::: details 完整的ghost.ce.json -RP/entity/ghost.ce.json - -```json +::: code-group +```json [RP/entity/ghost.ce.json] { "format_version": "1.10.0", "minecraft:client_entity": { @@ -962,25 +956,24 @@ With that, we have completed our entity client file. } } ``` +::: - +### 实体名称 -### Entity name +最后一步是将实体名称添加到语言文件中。你可能还注意到,如果创建了刷怪蛋,它也会有一个名称的翻译键;我们也要添加这个。在`en_US.lang`中,确保为实体和实体刷怪蛋物品都添加了名称。它们应该类似这样: -The final steps are to add our entity's name to the language files. You may have also noticed that if you created a spawn egg, it will also have a translation key for a name; we will also add this. Within `en_US.lang`, make sure you add names for both the entity and entity spawn egg item. They should look similar to this: - -RP/texts/en_US.lang - -```json -entity.wiki:ghost.name=Ghost -item.spawn_egg.entity.wiki:ghost.name=Ghost +::: code-group +```json [RP/texts/en_US.lang] +entity.wiki:ghost.name=幽灵 +item.spawn_egg.entity.wiki:ghost.name=幽灵 ``` +::: -## Overview +## 最终成果 -Done! Your entity should now show up in Minecraft, complete with all behaviors and visuals, including animations! You should be able to summon your entity using `/summon` or by finding the spawn egg in the creative menu. +完成!现在你的实体应该已经完整地出现在Minecraft中,包含所有行为和视觉效果,还有动画!你可以使用`/summon`命令召唤实体,或者在创造模式菜单中找到刷怪蛋。 -Your folder structure should look like this: +你的文件夹结构应该如下所示: - +::: details 完整的ghost.se.json -BP/entities/ghost.se.json - -```json +::: code-group +```json [BP/entities/ghost.se.json] { "format_version": "1.16.0", "minecraft:entity": { @@ -1097,14 +1089,14 @@ Your folder structure should look like this: } } ``` +::: - - -RP/entity/ghost.ce.json +::: details 完整的ghost.ce.json -```json +::: code-group +```json [RP/entity/ghost.ce.json] { "format_version": "1.10.0", "minecraft:client_entity": { @@ -1138,14 +1130,14 @@ Your folder structure should look like this: } } ``` +::: - - -RP/models/entity/ghost.geo.json +::: details 完整的ghost.geo.json -```json +::: code-group +```json [RP/models/entity/ghost.geo.json] { "format_version": "1.12.0", "minecraft:geometry": [ @@ -1213,14 +1205,14 @@ Your folder structure should look like this: ] } ``` +::: - - -RP/animations/ghost.a.json +::: details 完整的ghost.a.json -```json +::: code-group +```json [RP/animations/ghost.a.json] { "format_version": "1.8.0", "animations": { @@ -1333,14 +1325,14 @@ Your folder structure should look like this: } } ``` +::: - - -RP/animation_controllers/ghost.ac.json +::: details 完整的ghost.ac.json -```json +::: code-group +```json [RP/animation_controllers/ghost.ac.json] { "format_version": "1.12.0", "animation_controllers": { @@ -1390,14 +1382,14 @@ Your folder structure should look like this: } } ``` +::: - - -RP/render_controllers/entity/ghost.rc.json +::: details 完整的ghost.rc.json -```json +::: code-group +```json [RP/render_controllers/entity/ghost.rc.json] { "format_version": "1.10.0", "render_controllers": { @@ -1413,19 +1405,18 @@ Your folder structure should look like this: } } ``` +::: - - -## Your progress so far +## 当前进度 -- [x] Setup your pack -- [x] Create a custom item -- [x] Create a custom entity -- [x] - How to format the behavior- and resource files for an item -- [x] - How to set an entities texture -- [x] - How to use models, animations, and animation controllers to make your entity more exciting -- [ ] Create the entity's loot, spawn rules, and a custom recipe +- [x] 建立资源包 +- [x] 创建自定义物品 +- [x] 创建自定义实体 +- [x] - 如何格式化物品的行为和资源文件 +- [x] - 如何设置实体纹理 +- [x] - 如何使用模型、动画和动画控制器让实体更生动 +- [ ] 创建实体的战利品表、生成规则和自定义配方 - + \ No newline at end of file diff --git a/docs/wiki/items/custom-armor.md b/docs/wiki/items/custom-armor.md index 4fefab15..69907d87 100644 --- a/docs/wiki/items/custom-armor.md +++ b/docs/wiki/items/custom-armor.md @@ -88,6 +88,7 @@ mentions: } } ``` +::: 此时你只需在`RP/textures/item_texture.json`中添加名为`my_chest`的纹理即可。我们提供了默认纹理供参考: @@ -131,6 +132,7 @@ mentions: } } ``` +::: 下载配套纹理文件: @@ -190,6 +192,7 @@ mentions: } } ``` +::: 护腿纹理下载: @@ -224,6 +227,7 @@ mentions: } } ``` +::: ## 头盔部分 @@ -255,6 +259,7 @@ mentions: } } ``` +::: 头盔纹理下载: @@ -291,6 +296,7 @@ mentions: } } ``` +::: 靴子纹理下载: @@ -321,6 +327,7 @@ mentions: } } ``` +::: ```json [BP/entities/player.json#events] "wiki:armor_sets.my_custom.taken_damage": { @@ -347,6 +354,7 @@ mentions: ] } ``` +::: 完成效果展示: diff --git a/docs/wiki/items/custom-weapon.md b/docs/wiki/items/custom-weapon.md index e89e36fd..cc7dc082 100644 --- a/docs/wiki/items/custom-weapon.md +++ b/docs/wiki/items/custom-weapon.md @@ -71,7 +71,9 @@ mentions: } } ``` +::: +::: code-group ```json [RP/textures/item_texture.json] { "resource_pack_name": "vanilla", @@ -128,7 +130,9 @@ mentions: } } ``` +::: +::: code-group ```json [BP/items/my_sword.json] "events": { "wiki:my_sword.on_dig_damage": { @@ -160,7 +164,9 @@ mentions: } } ``` +::: +::: code-group ```json [BP/items/my_sword.json] "events": { "wiki:my_sword.hurt_entity": { diff --git a/docs/wiki/items/index.md b/docs/wiki/items/index.md index 9ce53bc7..bd2d6798 100644 --- a/docs/wiki/items/index.md +++ b/docs/wiki/items/index.md @@ -1,5 +1,6 @@ --- title: 物品 Items +nav_order: 4 categories: - title: 基础 color: blue diff --git a/docs/wiki/items/numerical-item-ids.md b/docs/wiki/items/numerical-item-ids.md index 3d796a9c..a8e8ed62 100644 --- a/docs/wiki/items/numerical-item-ids.md +++ b/docs/wiki/items/numerical-item-ids.md @@ -1,26 +1,30 @@ --- -title: Numerical Item IDs -category: Documentation +title: 数字物品ID +category: 文档 --- +# 数字物品ID + + + ::: tip -This page is a more up-to-date version of [this page](https://learn.microsoft.com/en-us/minecraft/creator/reference/content/addonsreference/examples/addonitems), and is current as of version 1.20.51. +本页面是[此微软文档](https://learn.microsoft.com/en-us/minecraft/creator/reference/content/addonsreference/examples/addonitems)的更新版本,内容基于1.20.51版本。 ::: -## Overview +## 概述 -Item IDs (not to be confused with type IDs) are an older system which are mainly used to render items with [JSON UI](/wiki/json-ui/json-ui-documentation#item-id-aux-item-id-aux) nowadays. All items & blocks (Even custom ones!) have their own unique ID. +物品ID(注意不要与类型ID混淆)是一个较旧的系统,目前主要用于通过[JSON UI](/wiki/json-ui/json-ui-documentation#item-id-aux-item-id-aux)渲染物品。所有物品和方块(包括自定义的!)都有自己唯一的ID。 -## ID Formatting -- Vanilla items & blocks have IDs from `-743` to `721`. -- All custom blocks have *increasingly negative* IDs, starting from an ID of `-744`. These do not interfere with vanilla IDs in any way. Note that custom blocks do not currently render with their IDs. It is unknown if this is a bug or not. -- All non-experimental items (1.10 format) have *increasingly positive* IDs, starting from an ID of `722`. These do not interfere with vanilla IDs in any way. -- All experimental items (1.16.100 format) have *increasingly positive* IDs, starting from an ID of 257. These **WILL SHIFT VANILLA IDs** that are higher than 256. For example, `'minecraft:apple'` (ID of `257`) will be moved up to an ID of `258` if you have one experimental item. +## ID格式规则 +- 原版物品和方块的ID范围是`-743`至`721` +- 所有自定义方块使用**递减的负数ID**,从`-744`开始。这些ID不会与原版ID产生冲突。注意:当前自定义方块不会显示其ID,尚不明确这是否是bug +- 所有非实验性物品(1.10格式)使用**递增的正数ID**,从`722`开始。这些ID不会与原版ID产生冲突 +- 所有实验性物品(1.16.100格式)使用**递增的正数ID**,从`257`开始。这些ID**会导致高于256的原版ID发生偏移**。例如,如果你添加了一个实验性物品,`'minecraft:apple'`(原ID为`257`)会被移动到`258` -## Vanilla ID List -Note for this list that a namespace of `minecraft:` is assumed for all items & blocks. +## 原版ID列表 +请注意,本列表中所有物品和方块都默认使用`minecraft:`命名空间。 -| Name | ID | +| 物品名称 | ID | | ----------------- | :--: | | dark_oak_planks | -743 | | acacia_planks | -742 | diff --git a/docs/wiki/items/troubleshooting-items.md b/docs/wiki/items/troubleshooting-items.md index 4af89d8a..ab62042b 100644 --- a/docs/wiki/items/troubleshooting-items.md +++ b/docs/wiki/items/troubleshooting-items.md @@ -18,17 +18,13 @@ mentions: :::tip -本文包含关于_物品_的故障排查信息。在继续阅读前,建议先查看[全局故障排查指南](/wiki/guide/troubleshooting)。 +本文包含关于 _物品_ 的故障排查信息。在继续阅读前,建议先查看[全局故障排查指南](/wiki/guide/troubleshooting)。 ::: ## 从这里开始 我按照教程制作了自定义物品,但出现了问题!请保持冷静。本指南将帮助您排查常见问题。根据按钮提示了解可能的问题原因及修复方法。 -继续 - ---- - ## 1.10 与 1.16 格式物品的区别? 首先需要确认您使用的是实验性物品格式还是稳定版物品格式。 @@ -47,12 +43,6 @@ mentions: 🔗 [实验性物品文档](https://bedrock.dev/docs/stable/Item) ::: -### 继续选择 - -1.10 格式(稳定版) 1.16.100 格式(实验性) - ---- - ## 稳定版物品 本部分针对稳定版物品的故障排查。请注意:使用 `1.10` 格式时,您需要同时存在 RP 和 BP 文件!如果只有 BP 文件,说明混淆了格式版本。请返回[此处](#_1-10-vs-1-16-items)重新确认。 @@ -125,8 +115,6 @@ mentions: 正确配置后物品将正常显示贴图。 ---- - ## 实验性物品 本部分针对实验性物品格式的故障排查。请注意:使用 `1.16` 格式时**不应存在 RP 物品文件**!如果同时存在 RP 和 BP 文件,说明混淆了格式版本。请返回[此处](#_1-10-vs-1-16-items)重新确认。 diff --git a/docs/wiki/json-ui/index.md b/docs/wiki/json-ui/index.md index a7443d8d..d701c661 100644 --- a/docs/wiki/json-ui/index.md +++ b/docs/wiki/json-ui/index.md @@ -1,5 +1,6 @@ --- title: JSON UI +nav_order: 10 categories: - title: 基础 color: blue diff --git a/docs/wiki/json-ui/json-ui-documentation.md b/docs/wiki/json-ui/json-ui-documentation.md index 7f60f557..8cc45e75 100644 --- a/docs/wiki/json-ui/json-ui-documentation.md +++ b/docs/wiki/json-ui/json-ui-documentation.md @@ -25,6 +25,8 @@ mentions: # JSON UI 完整文档 + + ## UI元素 ### 元素类型 @@ -920,9 +922,9 @@ $creative_layout_index - $items_index | $ignore_3rd_party_servers | | | $is_berwick | | -## Hardcoded Hyperlinks +## 硬编码超链接 -`#hyperlink` doesn't allow custom urls. These are the ones that will work: +`#hyperlink` 不允许自定义URL。以下是可用的预设链接: - `http://education.minecraft.net/eula` - `http://pocketbeta.minecraft.net/p/how-to-join-and-leave-beta.html` @@ -955,1117 +957,1116 @@ $creative_layout_index - $items_index - `https://aka.ms/switchcontent` - `https://social.xbox.com/changegamertag` -## Hardcoded Button IDs +## 硬编码按钮ID -Some of them only work in specific screens. +部分按钮仅在特定界面生效。 -### Buttons IDs: +### 通用按钮ID: -- `button.menu_exit` -- `button.menu_cancel` (`Escape` key or Controller `B`) -- `button.menu_inventory_cancel` (`Open Inventory` keybinding) -- `button.menu_ok` (`Enter` key) -- `button.menu_select` (Mouse click) -- `button.controller_select` (Controller `X`) -- `button.menu_secondary_select` -- `button.controller_secondary_select` -- `button.controller_secondary_select_left` -- `button.controller_secondary_select_right` (Controller `R3`) -- `button.controller_start` -- `button.menu_up` (`Arrow Up` key) -- `button.menu_down` (`Arrow Down` key) -- `button.menu_left` (`Arrow Left` key) -- `button.menu_right` (`Arrow Right` key) -- `button.menu_tab_left` (`Menu Tab Left` keybinding or Controller `Left Bumper`) -- `button.menu_tab_right` (`Menu Tab Right` keybinding or Controller `Right Bumper`) -- `button.menu_alternate_tab_left` -- `button.menu_alternate_tab_right` -- `button.menu_autocomplete` (Uses `Tab` key) -- `button.menu_autocomplete_back` -- `button.controller_autocomplete` -- `button.controller_autocomplete_back` -- `button.menu_textedit_up` (Uses `Arrow Up` key) -- `button.menu_textedit_down` (Uses `Arrow Down` key) -- `button.controller_textedit_up` -- `button.controller_textedit_down` -- `button.menu_auto_place` -- `button.menu_inventory_drop` (`Drop Item` keybinding) -- `button.menu_inventory_drop_all` (`Drop Item` + `Control` key) -- `button.menu_clear` -- `button.chat` (`Open Chat` keybinding) -- `button.mobeffects` (`Mob Effects` keybinding) -- `key.emote` (`Emote` keybinding) -- `button.slot1` (Emote Wheel) (`1` key) -- `button.slot2` (Emote Wheel) (`2` key) -- `button.slot3` (Emote Wheel) (`3` key) -- `button.slot4` (Emote Wheel) (`4` key) -- `button.slot5` (Emote Wheel) (`5` key) -- `button.slot6` (Emote Wheel) (`6` key) -- `button.inventory_right` (`Mouse Wheel Up`) -- `button.inventory_left` (`Mouse Wheel Down`) -- `button.scoreboard` -- `button.hide_gui` (`F1` key) -- `button.hide_tooltips` -- `button.hide_paperdoll` -- `button.slot0` -- `button.slot1` (`1` key) -- `button.slot2` (`2` key) -- `button.slot3` (`3` key) -- `button.slot4` (`4` key) -- `button.slot5` (`5` key) -- `button.slot6` (`6` key) -- `button.slot7` (`7` key) -- `button.slot8` (`8` key) -- `button.slot9` (`9` key) -- `button.menu_vr_realign` -- `any` (literally the name of it) +- `button.menu_exit` - 退出菜单 +- `button.menu_cancel` - 取消(对应键盘`ESC`或手柄`B`键) +- `button.menu_inventory_cancel` - 关闭背包(对应背包快捷键) +- `button.menu_ok` - 确认(对应键盘`Enter`键) +- `button.menu_select` - 选择(对应鼠标点击) +- `button.controller_select` - 手柄选择键(对应手柄`X`键) +- `button.menu_secondary_select` - 二级选择 +- `button.controller_secondary_select` - 手柄二级选择 +- `button.controller_secondary_select_left` - 手柄左二级选择 +- `button.controller_secondary_select_right` - 手柄右二级选择(对应手柄`R3`键) +- `button.controller_start` - 手柄开始键 +- `button.menu_up` - 上移(对应键盘`↑`键) +- `button.menu_down` - 下移(对应键盘`↓`键) +- `button.menu_left` - 左移(对应键盘`←`键) +- `button.menu_right` - 右移(对应键盘`→`键) +- `button.menu_tab_left` - 左标签页(对应标签页左键或手柄`左肩键`) +- `button.menu_tab_right` - 右标签页(对应标签页右键或手柄`右肩键`) +- `button.menu_alternate_tab_left` - 备用左标签页 +- `button.menu_alternate_tab_right` - 备用右标签页 +- `button.menu_autocomplete` - 自动补全(对应`Tab`键) +- `button.menu_autocomplete_back` - 返回自动补全 +- `button.controller_autocomplete` - 手柄自动补全 +- `button.controller_autocomplete_back` - 手柄返回自动补全 +- `button.menu_textedit_up` - 文本编辑上移(对应键盘`↑`键) +- `button.menu_textedit_down` - 文本编辑下移(对应键盘`↓`键) +- `button.controller_textedit_up` - 手柄文本编辑上移 +- `button.controller_textedit_down` - 手柄文本编辑下移 +- `button.menu_auto_place` - 自动放置 +- `button.menu_inventory_drop` - 丢弃物品(对应丢弃物品快捷键) +- `button.menu_inventory_drop_all` - 丢弃全部物品(对应丢弃物品+`Ctrl`键) +- `button.menu_clear` - 清除 +- `button.chat` - 打开聊天(对应聊天快捷键) +- `button.mobeffects` - 生物效果(对应生物效果快捷键) +- `key.emote` - 表情(对应表情快捷键) +- `button.slot1` - 表情轮盘槽位1(对应`1`键) +- `button.slot2` - 表情轮盘槽位2(对应`2`键) +- `button.slot3` - 表情轮盘槽位3(对应`3`键) +- `button.slot4` - 表情轮盘槽位4(对应`4`键) +- `button.slot5` - 表情轮盘槽位5(对应`5`键) +- `button.slot6` - 表情轮盘槽位6(对应`6`键) +- `button.inventory_right` - 背包右移(对应鼠标滚轮上滑) +- `button.inventory_left` - 背包左移(对应鼠标滚轮下滑) +- `button.scoreboard` - 记分板 +- `button.hide_gui` - 隐藏界面(对应`F1`键) +- `button.hide_tooltips` - 隐藏提示 +- `button.hide_paperdoll` - 隐藏纸娃娃 +- `button.slot0` - 槽位0 +- `button.slot1` - 槽位1(对应`1`键) +- `button.slot2` - 槽位2(对应`2`键) +- `button.slot3` - 槽位3(对应`3`键) +- `button.slot4` - 槽位4(对应`4`键) +- `button.slot5` - 槽位5(对应`5`键) +- `button.slot6` - 槽位6(对应`6`键) +- `button.slot7` - 槽位7(对应`7`键) +- `button.slot8` - 槽位8(对应`8`键) +- `button.slot9` - 槽位9(对应`9`键) +- `button.menu_vr_realign` - VR重定位 +- `any` - 字面意思,表示任意按钮 -### Specific Screen Button IDs: +### 特定界面按钮ID: -#### Settings (`ui/settings_screen.json`) +#### 设置界面 (`ui/settings_screen.json`) -- `button.open_content_log_history` -- `button.clear_content_log_files` -- `button.clear_msa_token_button` -- `button.terms_and_conditions_popup` -- `button.credits` -- `button.unlink_msa` -- `button.attribute_popup` -- `button.licensed_content` -- `button.font_license` -- `button.tos_hyperlink` -- `button.privpol_hyperlink` -- `button.tos_popup` -- `button.privpol_popup` -- `button.binding_button` -- `button.reset_binding` -- `button.reset_keyboard_bindings` -- `button.view_account_errors` +- `button.open_content_log_history` - 打开内容日志历史 +- `button.clear_content_log_files` - 清除内容日志文件 +- `button.clear_msa_token_button` - 清除MSA令牌 +- `button.terms_and_conditions_popup` - 条款与条件弹窗 +- `button.credits` - 制作人员 +- `button.unlink_msa` - 取消MSA关联 +- `button.attribute_popup` - 属性弹窗 +- `button.licensed_content` - 授权内容 +- `button.font_license` - 字体授权 +- `button.tos_hyperlink` - 服务条款超链接 +- `button.privpol_hyperlink` - 隐私政策超链接 +- `button.tos_popup` - 服务条款弹窗 +- `button.privpol_popup` - 隐私政策弹窗 +- `button.binding_button` - 绑定按钮 +- `button.reset_binding` - 重置绑定 +- `button.reset_keyboard_bindings` - 重置键盘绑定 +- `button.view_account_errors` - 查看账户错误 -#### Book (`ui/book_screen.json`) +#### 书本界面 (`ui/book_screen.json`) -- `button.prev_page` -- `button.next_page` -- `button.book_exit` +- `button.prev_page` - 上一页 +- `button.next_page` - 下一页 +- `button.book_exit` - 退出书本 -#### Chat (`ui/chat_screen.json`) +#### 聊天界面 (`ui/chat_screen.json`) -- `button.send` -- `button.chat_autocomplete` -- `button.chat_autocomplete_back` -- `button.chat_previous_message` -- `button.chat_next_message` -- `button.chat_menu_cancel` +- `button.send` - 发送 +- `button.chat_autocomplete` - 聊天自动补全 +- `button.chat_autocomplete_back` - 返回聊天自动补全 +- `button.chat_previous_message` - 上一条消息 +- `button.chat_next_message` - 下一条消息 +- `button.chat_menu_cancel` - 取消聊天菜单 -#### Command Block (`ui/command_block_screen.json`) +#### 命令方块界面 (`ui/command_block_screen.json`) -- `command_block.input_minimize` -- `button.chat_autocomplete` -- `button.chat_autocomplete_back` +- `command_block.input_minimize` - 最小化输入框 +- `button.chat_autocomplete` - 聊天自动补全 +- `button.chat_autocomplete_back` - 返回聊天自动补全 -#### Comment (`ui/comment_screen.json`) +#### 评论界面 (`ui/comment_screen.json`) -- `button.comment_options_close` -- `button.comment_feed_options_close` -- `button.close_comments` -- `button.comment_next_button` -- `button.comment_prev_button` +- `button.comment_options_close` - 关闭评论选项 +- `button.comment_feed_options_close` - 关闭评论反馈选项 +- `button.close_comments` - 关闭评论 +- `button.comment_next_button` - 下一条评论 +- `button.comment_prev_button` - 上一条评论 -#### Credits (`ui/credits_screen.json`) +#### 制作人员界面 (`ui/credits_screen.json`) -- `button.show_skip` +- `button.show_skip` - 显示跳过按钮 -#### Death Menu (`ui/death_screen.json`) +#### 死亡界面 (`ui/death_screen.json`) -- `button.respawn_button` -- `button.main_menu_button` +- `button.respawn_button` - 重生按钮 +- `button.main_menu_button` - 主菜单按钮 -#### Emote Wheel (`ui/emote_screen_wheel.json`) +#### 表情轮盘界面 (`ui/emote_screen_wheel.json`) -- `button.rebind_mode` -- `button.dressing_room` -- `button.emote_selected` -- `button.select_emote_slot_0` -- `button.select_emote_slot_1` -- `button.select_emote_slot_2` -- `button.select_emote_slot_3` -- `button.select_emote_slot_4` -- `button.select_emote_slot_5` -- `button.iterate_selection_left` -- `button.iterate_selection_right` +- `button.rebind_mode` - 重绑定模式 +- `button.dressing_room` - 更衣室 +- `button.emote_selected` - 已选表情 +- `button.select_emote_slot_0` - 选择表情槽位0 +- `button.select_emote_slot_1` - 选择表情槽位1 +- `button.select_emote_slot_2` - 选择表情槽位2 +- `button.select_emote_slot_3` - 选择表情槽位3 +- `button.select_emote_slot_4` - 选择表情槽位4 +- `button.select_emote_slot_5` - 选择表情槽位5 +- `button.iterate_selection_left` - 向左循环选择 +- `button.iterate_selection_right` - 向右循环选择 -#### Feed (`ui/feed_screen.json`) +#### 反馈界面 (`ui/feed_screen.json`) -- `button.feed_image` -- `button.newpost` -- `button.add_screenshot` -- `button.feed_comment` -- `button.feed_prev_button` -- `button.feed_next_button` -- `button.feed_new_post_close` -- `button.feed_options_close` -- `button.close_feed` +- `button.feed_image` - 反馈图片 +- `button.newpost` - 新帖子 +- `button.add_screenshot` - 添加截图 +- `button.feed_comment` - 反馈评论 +- `button.feed_prev_button` - 上一条反馈 +- `button.feed_next_button` - 下一条反馈 +- `button.feed_new_post_close` - 关闭新帖子 +- `button.feed_options_close` - 关闭反馈选项 +- `button.close_feed` - 关闭反馈 -#### Game Menu (`ui/pause_screen.json`) +#### 游戏菜单界面 (`ui/pause_screen.json`) -- `button.to_profile_or_skins_screen` -- `button.player_profile_card` -- `button.menu_continue` -- `button.menu_server_store` -- `button.screenshot` -- `button.menu_how_to_play` -- `button.menu_feedback` -- `button.menu_permission` -- `button.menu_invite_players` -- `button.menu_quit` -- `button.menu_feed` -- `button.pause_focus_filler` +- `button.to_profile_or_skins_screen` - 前往个人资料/皮肤界面 +- `button.player_profile_card` - 玩家资料卡片 +- `button.menu_continue` - 继续游戏 +- `button.menu_server_store` - 服务器商店 +- `button.screenshot` - 截图 +- `button.menu_how_to_play` - 玩法指南 +- `button.menu_feedback` - 反馈 +- `button.menu_permission` - 权限设置 +- `button.menu_invite_players` - 邀请玩家 +- `button.menu_quit` - 退出游戏 +- `button.menu_feed` - 反馈菜单 +- `button.pause_focus_filler` - 暂停焦点填充 -#### In Bed (`ui/in_bed_screen.json`) +#### 床上界面 (`ui/in_bed_screen.json`) -- `button.wake_up_button` +- `button.wake_up_button` - 起床按钮 -#### Invite (`ui/invite_screen.json`) +#### 邀请界面 (`ui/invite_screen.json`) -- `button.add_friend` -- `button.add_member` -- `button.send_invites` +- `button.add_friend` - 添加好友 +- `button.add_member` - 添加成员 +- `button.send_invites` - 发送邀请 -#### Manage Feed (`ui/manage_feed_screen.json`) +#### 管理反馈界面 (`ui/manage_feed_screen.json`) -- `button.manage_feed_prev_button` -- `button.manage_feed_next_button` -- `button.manage_feed_ignore` -- `button.manage_feed_delete` -- `button.close_manage_feed` +- `button.manage_feed_prev_button` - 上一条管理反馈 +- `button.manage_feed_next_button` - 下一条管理反馈 +- `button.manage_feed_ignore` - 忽略反馈 +- `button.manage_feed_delete` - 删除反馈 +- `button.close_manage_feed` - 关闭管理反馈 -#### Anvil (`ui/anvil_screen.json`) +#### 铁砧界面 (`ui/anvil_screen.json`) -- `button.anvil_take_all_place_all` -- `button.anvil_coalesce_stack` +- `button.anvil_take_all_place_all` - 全部取出/放入 +- `button.anvil_coalesce_stack` - 合并堆叠 -#### Cartography Table (`ui/cartography_screen.json`) +#### 制图台界面 (`ui/cartography_screen.json`) -- `button.cartography_result_take_all_place_all` +- `button.cartography_result_take_all_place_all` - 制图结果全部取出/放入 -#### Enchanting Table (`ui/enchanting_table_screen.json`) +#### 附魔台界面 (`ui/enchanting_table_screen.json`) -- `button.enchant` +- `button.enchant` - 附魔 -#### Grindstone (`ui/grindstone_screen.json`) +#### 砂轮界面 (`ui/grindstone_screen.json`) -- `button.grindstone_take_all_place_all` -- `button.grindstone_coalesce_stack` +- `button.grindstone_take_all_place_all` - 全部取出/放入 +- `button.grindstone_coalesce_stack` - 合并堆叠 -#### Loom (`ui/loom_screen.json`) +#### 织布机界面 (`ui/loom_screen.json`) -- `button.loom_result_take_all_place_all` -- `button.pattern_select` +- `button.loom_result_take_all_place_all` - 织布结果全部取出/放入 +- `button.pattern_select` - 图案选择 -#### Villager Trade (`ui/trade_screen.json`) +#### 村民交易界面 (`ui/trade_screen.json`) -- `button.cycle_recipe_left` -- `button.cycle_recipe_right` -- `button.trade_take_all_place_all` -- `button.trade_take_half_place_one` -- `button.trade_coalesce_stack` +- `button.cycle_recipe_left` - 向左循环配方 +- `button.cycle_recipe_right` - 向右循环配方 +- `button.trade_take_all_place_all` - 全部取出/放入 +- `button.trade_take_half_place_one` - 取半/放入单个 +- `button.trade_coalesce_stack` - 合并堆叠 -#### Play (`ui/play_screen.json`) +#### 游戏主界面 (`ui/play_screen.json`) -- `button.menu_sign_in_to_view_realms` -- `button.menu_realms_world_item_edit` -- `button.menu_realms_feed` -- `button.menu_realms_world_item_remove` -- `button.menu_network_world_item` -- `button.menu_network_server_world_edit` -- `button.connect_to_third_party_server` -- `button.view_third_party_server_offers` -- `button.description_read_toggle` -- `button.news_read_toggle` -- `button.local_world_upload` -- `button.menu_start_local_world` -- `button.convert_legacy_world` -- `button.menu_local_world_item_edit` -- `button.menu_legacy_world_item_delete` -- `button.import_beta_retail_local_world` -- `button.import_beta_retail_legacy_world` -- `button.menu_network_add_friend` -- `button.menu_network_join_by_code` -- `button.menu_quick_play` -- `button.new_world_upload` -- `button.menu_local_world_create` -- `button.create_on_realms_button` -- `button.archived_world_upload` -- `button.menu_import_level` -- `button.menu_sync_legacy_worlds` -- `button.realms_warning_more_info` -- `button.menu_realm_world_trial` -- `button.menu_realm_nintendo_first_realm_purchase_button` -- `button.no_local_worlds_launch_help` -- `button.menu_network_join_by_code_popup_join` -- `button.join_server_anyway` -- `button.cancel_join_server` +- `button.menu_sign_in_to_view_realms` - 登录查看Realms +- `button.menu_realms_world_item_edit` - 编辑Realms世界 +- `button.menu_realms_feed` - Realms反馈 +- `button.menu_realms_world_item_remove` - 移除Realms世界 +- `button.menu_network_world_item` - 网络世界项目 +- `button.menu_network_server_world_edit` - 编辑网络服务器世界 +- `button.connect_to_third_party_server` - 连接第三方服务器 +- `button.view_third_party_server_offers` - 查看第三方服务器优惠 +- `button.description_read_toggle` - 描述阅读切换 +- `button.news_read_toggle` - 新闻阅读切换 +- `button.local_world_upload` - 上传本地世界 +- `button.menu_start_local_world` - 开始本地世界 +- `button.convert_legacy_world` - 转换旧版世界 +- `button.menu_local_world_item_edit` - 编辑本地世界 +- `button.menu_legacy_world_item_delete` - 删除旧版世界 +- `button.import_beta_retail_local_world` - 导入Beta零售版本地世界 +- `button.import_beta_retail_legacy_world` - 导入Beta零售版旧版世界 +- `button.menu_network_add_friend` - 添加网络好友 +- `button.menu_network_join_by_code` - 通过代码加入网络 +- `button.menu_quick_play` - 快速游戏 +- `button.new_world_upload` - 上传新世界 +- `button.menu_local_world_create` - 创建本地世界 +- `button.create_on_realms_button` - 在Realms创建 +- `button.archived_world_upload` - 上传存档世界 +- `button.menu_import_level` - 导入关卡 +- `button.menu_sync_legacy_worlds` - 同步旧版世界 +- `button.realms_warning_more_info` - Realms警告更多信息 +- `button.menu_realm_world_trial` - Realms世界试用 +- `button.menu_realm_nintendo_first_realm_purchase_button` - Nintendo首次购买Realms按钮 +- `button.no_local_worlds_launch_help` - 无本地世界启动帮助 +- `button.menu_network_join_by_code_popup_join` - 通过代码加入网络弹窗 +- `button.join_server_anyway` - 仍然加入服务器 +- `button.cancel_join_server` - 取消加入服务器 -### Others +### 其他按钮 -- `button.try_menu_exit` -- `button.close_dialog` -- `button.menu_play` -- `$play_button_target` (**hardcoded**) -- `button.menu_store` -- `button.menu_achievements` -- `button.menu_settings` -- `button.signin` -- `button.menu_skins` -- `button.to_profile_screen` -- `button.menu_courses` -- `button.menu_tutorial` -- `button.featured_world` -- `button.switch_accounts` -- `button.launch_editions` -- `button.edu_feedback` -- `button.edu_resources` -- `button.menu_buy_game` -- `button.menu_invite_notification` -- `button.search` -- `button.hotbar_inventory_button` -- `button.select_offer` -- `button.action_button` -- `button.create_realm` -- `button.switch_accounts` -- `button.hotbar_select` -- `button.hotbar_ok` -- `button.slot_pressed` -- `button.hotbar_inventory_left` -- `button.hotbar_inventory_right` -- `button.hide_gui_all` -- `button.hide_tooltips_hud` -- `button.hide_paperdoll_hud` -- `button.slot_1` -- `button.slot_2` -- `button.slot_3` -- `button.slot_4` -- `button.slot_5` -- `button.slot_6` -- `button.slot_7` -- `button.slot_8` -- `button.slot_9` -- `button.slot_0` -- `button.chat` -- `button.menu_continue` -- `user_confirm_dialog.escape` -- `user_confirm_dialog.left_button` -- `user_confirm_dialog.middle_button` -- `user_confirm_dialog.rightcancel_button` -- `button.view_skin` -- `button.delete_action` -- `button.exit_student` -- `button.play_video` -- `button.menu_store_error` -- `button.left_panel_tab_increment` -- `button.left_panel_tab_decrement` -- `button.right_panel_tab_increment` -- `button.right_panel_tab_decrement` -- `button.layout_increment` -- `button.layout_decrement` -- `button.is_hovered` -- `button.container_take_all_place_all` -- `button.container_take_half_place_one` -- `button.container_auto_place` -- `button.coalesce_stack` -- `button.shape_drawing` -- `button.destroy_selection` -- `button.clear_selected_recipe` -- `button.clear_hotbar_or_remove_one` -- `button.clear_hotbar_or_drop` -- `button.container_reset_held` -- `button.container_auto_place` -- `button.container_slot_hovered` -- `button.button_hovered` -- `button.shift_pane_focus` -- `button.focus_left` -- `button.focus_right` -- `button.filter_toggle_hovered` -- `button.drop_one` -- `button.cursor_drop_one` -- `button.drop_all` -- `button.cursor_drop_all` -- `button.search_bar_clear` -- `button.search_bar_selected` -- `button.search_bar_deselected` -- `button.menu_leave_screen` -- `button.turn_doll` -- `button.select_skin` -- `button.skin_hovered` -- `button.skin_unhovered` -- `button.leave` -- `button.leave_on_device` -- `button.text_edit_box_selected` -- `button.text_edit_box_deselected` -- `button.text_edit_box_hovered` -- `button.text_edit_box_clear` -- `button.help` -- `button.menu_open_uri` -- `button.no_interaction` -- `button.copy_to_clipboard` +- `button.try_menu_exit` - 尝试退出菜单 +- `button.close_dialog` - 关闭对话框 +- `button.menu_play` - 游戏菜单 +- `$play_button_target` (**硬编码**) +- `button.menu_store` - 商店菜单 +- `button.menu_achievements` - 成就菜单 +- `button.menu_settings` - 设置菜单 +- `button.signin` - 登录 +- `button.menu_skins` - 皮肤菜单 +- `button.to_profile_screen` - 前往个人资料界面 +- `button.menu_courses` - 课程菜单 +- `button.menu_tutorial` - 教程菜单 +- `button.featured_world` - 精选世界 +- `button.switch_accounts` - 切换账户 +- `button.launch_editions` - 启动旧版 +- `button.edu_feedback` - 教育版反馈 +- `button.edu_resources` - 教育资源 +- `button.menu_buy_game` - 购买游戏菜单 +- `button.menu_invite_notification` - 邀请通知菜单 +- `button.search` - 搜索 +- `button.hotbar_inventory_button` - 快捷栏背包按钮 +- `button.select_offer` - 选择优惠 +- `button.action_button` - 操作按钮 +- `button.create_realm` - 创建Realm +- `button.switch_accounts` - 切换账户 +- `button.hotbar_select` - 快捷栏选择 +- `button.hotbar_ok` - 快捷栏确认 +- `button.slot_pressed` - 槽位按下 +- `button.hotbar_inventory_left` - 快捷栏背包左移 +- `button.hotbar_inventory_right` - 快捷栏背包右移 +- `button.hide_gui_all` - 隐藏所有界面 +- `button.hide_tooltips_hud` - 隐藏HUD提示 +- `button.hide_paperdoll_hud` - 隐藏HUD纸娃娃 +- `button.slot_1` - 槽位1 +- `button.slot_2` - 槽位2 +- `button.slot_3` - 槽位3 +- `button.slot_4` - 槽位4 +- `button.slot_5` - 槽位5 +- `button.slot_6` - 槽位6 +- `button.slot_7` - 槽位7 +- `button.slot_8` - 槽位8 +- `button.slot_9` - 槽位9 +- `button.slot_0` - 槽位0 +- `button.chat` - 聊天 +- `button.menu_continue` - 继续菜单 +- `user_confirm_dialog.escape` - 用户确认对话框退出 +- `user_confirm_dialog.left_button` - 用户确认对话框左按钮 +- `user_confirm_dialog.middle_button` - 用户确认对话框中按钮 +- `user_confirm_dialog.rightcancel_button` - 用户确认对话框右取消按钮 +- `button.view_skin` - 查看皮肤 +- `button.delete_action` - 删除操作 +- `button.exit_student` - 退出学生模式 +- `button.play_video` - 播放视频 +- `button.menu_store_error` - 商店菜单错误 +- `button.left_panel_tab_increment` - 左面板标签页增加 +- `button.left_panel_tab_decrement` - 左面板标签页减少 +- `button.right_panel_tab_increment` - 右面板标签页增加 +- `button.right_panel_tab_decrement` - 右面板标签页减少 +- `button.layout_increment` - 布局增加 +- `button.layout_decrement` - 布局减少 +- `button.is_hovered` - 悬停状态 +- `button.container_take_all_place_all` - 容器全部取出/放入 +- `button.container_take_half_place_one` - 容器取半/放入单个 +- `button.container_auto_place` - 容器自动放置 +- `button.coalesce_stack` - 合并堆叠 +- `button.shape_drawing` - 形状绘制 +- `button.destroy_selection` - 销毁选择 +- `button.clear_selected_recipe` - 清除选定配方 +- `button.clear_hotbar_or_remove_one` - 清除快捷栏或移除单个 +- `button.clear_hotbar_or_drop` - 清除快捷栏或丢弃 +- `button.container_reset_held` - 容器重置持有 +- `button.container_auto_place` - 容器自动放置 +- `button.container_slot_hovered` - 容器槽位悬停 +- `button.button_hovered` - 按钮悬停 +- `button.shift_pane_focus` - 切换面板焦点 +- `button.focus_left` - 焦点左移 +- `button.focus_right` - 焦点右移 +- `button.filter_toggle_hovered` - 筛选切换悬停 +- `button.drop_one` - 丢弃单个 +- `button.cursor_drop_one` - 光标丢弃单个 +- `button.drop_all` - 丢弃全部 +- `button.cursor_drop_all` - 光标丢弃全部 +- `button.search_bar_clear` - 搜索栏清除 +- `button.search_bar_selected` - 搜索栏选中 +- `button.search_bar_deselected` - 搜索栏取消选中 +- `button.menu_leave_screen` - 离开菜单界面 +- `button.turn_doll` - 旋转纸娃娃 +- `button.select_skin` - 选择皮肤 +- `button.skin_hovered` - 皮肤悬停 +- `button.skin_unhovered` - 皮肤取消悬停 +- `button.leave` - 离开 +- `button.leave_on_device` - 在设备上离开 +- `button.text_edit_box_selected` - 文本编辑框选中 +- `button.text_edit_box_deselected` - 文本编辑框取消选中 +- `button.text_edit_box_hovered` - 文本编辑框悬停 +- `button.text_edit_box_clear` - 文本编辑框清除 +- `button.help` - 帮助 +- `button.menu_open_uri` - 打开URI菜单 +- `button.no_interaction` - 无交互 +- `button.copy_to_clipboard` - 复制到剪贴板 - ... -## Hardcoded Collection Names +## 硬编码集合名称 -All of them only in specific screens. +以下集合仅在特定界面中生效。 -### Screen specific: +### 界面专属集合: -#### Book (`ui/book_screen.json`) +#### 书本界面 (`ui/book_screen.json`) -- `book_pages` -- `pick_collection` +- `book_pages` - 书页集合 +- `pick_collection` - 选取集合 -#### Bundle Purchase Warning (`ui/bundle_purchase_warning_screen.json`) +#### 捆绑包购买警告界面 (`ui/bundle_purchase_warning_screen.json`) -- `owned_list` -- `unowned_list` +- `owned_list` - 已拥有列表 +- `unowned_list` - 未拥有列表 -#### Chat (`ui/chat_screen.json`) +#### 聊天界面 (`ui/chat_screen.json`) -- `auto_complete` -- `font_colors` -- `host_main_collection` -- `players_collection` -- `host_teleport_collection` -- `host_time_collection` -- `host_weather_collection` +- `auto_complete` - 自动补全集合 +- `font_colors` - 字体颜色集合 +- `host_main_collection` - 主机主集合 +- `players_collection` - 玩家集合 +- `host_teleport_collection` - 主机传送集合 +- `host_time_collection` - 主机时间集合 +- `host_weather_collection` - 主机天气集合 -#### Choose Realm (`ui/choose_realm_screen.json`) +#### 选择 Realm 界面 (`ui/choose_realm_screen.json`) -- `realms_collection` +- `realms_collection` - Realms 集合 -#### Coin Purchase (`ui/coin_purchase_screen.json`) +#### 代币购买界面 (`ui/coin_purchase_screen.json`) -- `coin_purchase_grid` +- `coin_purchase_grid` - 代币购买网格 -#### Comment (`ui/comment_screen.json`) +#### 评论界面 (`ui/comment_screen.json`) -- `comment_collection` +- `comment_collection` - 评论集合 -#### Content Log History (`ui/content_log_history_screen.json`) +#### 内容日志历史界面 (`ui/content_log_history_screen.json`) -- `content_log_message` +- `content_log_message` - 内容日志消息 -#### Create World Upsell (`ui/create_world_upsell_screen.json`) +#### 创建世界促销界面 (`ui/create_world_upsell_screen.json`) -- `world_list` -- `realm_list` +- `world_list` - 世界列表 +- `realm_list` - Realm 列表 -#### Custom Templates (`ui/custom_templates_screen.json`) +#### 自定义模板界面 (`ui/custom_templates_screen.json`) -- `templates_collection` +- `templates_collection` - 模板集合 -#### Feed (`ui/feed_screen.json`) +#### 反馈界面 (`ui/feed_screen.json`) -- `feed_collection` +- `feed_collection` - 反馈集合 -#### HUD (`ui/hud_screen.json`) +#### HUD 界面 (`ui/hud_screen.json`) -- `boss_bars` -- `chat_text_grid` -- `hotbar_items` -- `scoreboard_players` -- `scoreboard_scores` -- `left_helper_collection` -- `right_helper_collection` +- `boss_bars` - Boss 血条 +- `chat_text_grid` - 聊天文本网格 +- `hotbar_items` - 快捷栏物品 +- `scoreboard_players` - 记分板玩家 +- `scoreboard_scores` - 记分板分数 +- `left_helper_collection` - 左侧帮助集合 +- `right_helper_collection` - 右侧帮助集合 -#### Invite (`ui/invite_screen.json`) +#### 邀请界面 (`ui/invite_screen.json`) -- `online_platform_friends` -- `online_linked_account_friends` -- `online_xbox_live_friends` -- `offline_platform_friends` -- `offline_linked_account_friends` -- `offline_xbox_live_friends` +- `online_platform_friends` - 在线平台好友 +- `online_linked_account_friends` - 在线关联账户好友 +- `online_xbox_live_friends` - 在线 Xbox Live 好友 +- `offline_platform_friends` - 离线平台好友 +- `offline_linked_account_friends` - 离线关联账户好友 +- `offline_xbox_live_friends` - 离线 Xbox Live 好友 -#### Manage Feed (`ui/manage_feed_screen.json`) +#### 管理反馈界面 (`ui/manage_feed_screen.json`) -- `manage_feed_collection` +- `manage_feed_collection` - 管理反馈集合 -#### Manifest Validation (`manifest_validation_screen.json`) +#### 清单验证界面 (`manifest_validation_screen.json`) -- `pack_errors` +- `pack_errors` - 包错误集合 -#### Mob Effects (`ui/mob_effects_screen.json`) +#### 生物效果界面 (`ui/mob_effects_screen.json`) -- `mob_effects_collection` +- `mob_effects_collection` - 生物效果集合 -#### Game Menu (`ui/pause_screen.json`) +#### 游戏菜单界面 (`ui/pause_screen.json`) -- `players_collection` +- `players_collection` - 玩家集合(也在 `pause_screen.json` 中使用) -#### PDP (`ui/pdp_screen.json`) +#### 产品详情界面 (`ui/pdp_screen.json`) -- `factory_collection` -- `ratings_star_collection` +- `factory_collection` - 厂商集合 +- `ratings_star_collection` - 评分星级集合 -#### Permissions (`ui/permissions_screen.json`) +#### 权限界面 (`ui/permissions_screen.json`) -- `players_collection` - it's also used in `pause_screen.json` -- `permissions_collection` +- `players_collection` - 玩家集合 +- `permissions_collection` - 权限集合 -#### Persona (`ui/persona_screen.json`) +#### 角色装扮界面 (`ui/persona_screen.json`) -- `color_collection` -- `skin_pack_in_grid_item` -- `persona_featured_skin_pack_collection` -- `body_size_collection` -- `arm_size_collection` -- `category_featured_collection` -- `main_featured_collection` -- `profile_featured_collection` -- `custom_section_collection` -- `featured_collection` -- `foobar_collection` -- `emote_collection` +- `color_collection` - 颜色集合 +- `skin_pack_in_grid_item` - 皮肤包网格项 +- `persona_featured_skin_pack_collection` - 精选皮肤包集合 +- `body_size_collection` - 体型集合 +- `arm_size_collection` - 手臂尺寸集合 +- `category_featured_collection` - 分类精选集合 +- `main_featured_collection` - 主精选集合 +- `profile_featured_collection` - 个人资料精选集合 +- `custom_section_collection` - 自定义部分集合 +- `featured_collection` - 精选集合 +- `foobar_collection` - 占位集合 +- `emote_collection` - 表情集合 -#### Play (`ui/play_screen.json`) +#### 游戏主界面 (`ui/play_screen.json`) -- `friends_network_worlds` -- `cross_platform_friends_network_worlds` -- `lan_network_worlds` -- `personal_realms` -- `friends_realms` -- `servers_network_worlds` -- `third_party_server_network_worlds` -- `server_screenshot_collection` -- `server_games_collection` -- `local_worlds` -- `legacy_worlds` -- `beta_retail_local_worlds` -- `personal_realms` -- `loading_personal_realms` -- `friends_realms` -- `loading_friends_realms` +- `friends_network_worlds` - 好友网络世界 +- `cross_platform_friends_network_worlds` - 跨平台好友网络世界 +- `lan_network_worlds` - 局域网网络世界 +- `personal_realms` - 个人 Realms +- `friends_realms` - 好友 Realms +- `servers_network_worlds` - 服务器网络世界 +- `third_party_server_network_worlds` - 第三方服务器网络世界 +- `server_screenshot_collection` - 服务器截图集合 +- `server_games_collection` - 服务器游戏集合 +- `local_worlds` - 本地世界 +- `legacy_worlds` - 旧版世界 +- `beta_retail_local_worlds` - Beta 零售版本地世界 +- `personal_realms` - 个人 Realms +- `loading_personal_realms` - 加载中的个人 Realms +- `friends_realms` - 好友 Realms +- `loading_friends_realms` - 加载中的好友 Realms -#### Portfolio (`ui/portfolio_screen.json`) +#### 作品集界面 (`ui/portfolio_screen.json`) -- `photos` +- `photos` - 照片集合 -#### Progress (`ui/progress_screen.json`) +#### 进度界面 (`ui/progress_screen.json`) -- `required_resourcepacks` -- `optional_resourcepacks` +- `required_resourcepacks` - 必需资源包 +- `optional_resourcepacks` - 可选资源包 -#### Realms Pending Invitations (`ui/realms_pending_invitations_screen.json`) +#### Realms 待处理邀请界面 (`ui/realms_pending_invitations_screen.json`) -- `pending_invites_collection` +- `pending_invites_collection` - 待处理邀请集合 -#### Realms Settings (`ui/realms_settings_screen.json`) +#### Realms 设置界面 (`ui/realms_settings_screen.json`) -- `additional_realms_subscriptions_collection` -- `realms_branch_collection` -- `realms_backup_collection` -- `members_collection` -- `invited_friends_collection` -- `uninvited_friends_collection` -- `blocked_players_collection` +- `additional_realms_subscriptions_collection` - 额外 Realms 订阅集合 +- `realms_branch_collection` - Realms 分支集合 +- `realms_backup_collection` - Realms 备份集合 +- `members_collection` - 成员集合 +- `invited_friends_collection` - 已邀请好友集合 +- `uninvited_friends_collection` - 未邀请好友集合 +- `blocked_players_collection` - 已屏蔽玩家集合 -#### Screenshot Picker (`ui/screenshot_picker_screen.json`) +#### 截图选择器界面 (`ui/screenshot_picker_screen.json`) -- `screenshotpicker_collection` +- `screenshotpicker_collection` - 截图选择器集合 -#### Server Form (`ui/server_form.json`) +#### 服务器表单界面 (`ui/server_form.json`) -- `custom_form` -- `form_buttons` -- `custom_dropdown` +- `custom_form` - 自定义表单 +- `form_buttons` - 表单按钮 +- `custom_dropdown` - 自定义下拉菜单 -#### Settings (`ui/settings_screen.json`) +#### 设置界面 (`ui/settings_screen.json`) -- `keyboard_standard_collection` -- `keyboard_full_collection` -- `gamepad_collection` -- `languages` -- `realms_plus_subscriptions_collection` -- `additional_realms_subscriptions_collection` -- `#selected_pack_items_global` -- `#available_pack_items_global` -- `#realms_pack_items_global` -- `#unowned_pack_items_global` -- `#invalid_pack_items_global` -- `#selected_pack_items_level` -- `#available_pack_items_level` -- `#realms_pack_items_level` -- `#unowned_pack_items_level` -- `#invalid_pack_items_level` -- `#selected_pack_items_addon` -- `#available_pack_items_addon` -- `#realms_pack_items_addon` -- `#unowned_pack_items_addon` -- `#invalid_pack_items_addon` -- `experimental_toggles` -- `world_panel` -- `world_template_panel` -- `resource_panel` -- `behavior_panel` -- `skin_panel` -- `cache_panel` -- `dependent_packs_panel` -- `dependency_panel` - -#### Structure Block (`ui/structure_editor_screen.json`) - -- `save_size_grid` -- `save_offset_grid` -- `load_offset_grid` -- `export_size_grid` -- `export_offset_grid` - -#### Seed Picker (`ui/ugc_viewer_screen.json`) - -- `ugc_items` - -#### World Templates (`ui/world_templates_screen.json`) +- `keyboard_standard_collection` - 标准键盘集合 +- `keyboard_full_collection` - 完整键盘集合 +- `gamepad_collection` - 游戏手柄集合 +- `languages` - 语言集合 +- `realms_plus_subscriptions_collection` - Realms Plus 订阅集合 +- `additional_realms_subscriptions_collection` - 额外 Realms 订阅集合 +- `#selected_pack_items_global` - 全局已选包项 +- `#available_pack_items_global` - 全局可用包项 +- `#realms_pack_items_global` - 全局 Realms 包项 +- `#unowned_pack_items_global` - 全局未拥有包项 +- `#invalid_pack_items_global` - 全局无效包项 +- `#selected_pack_items_level` - 关卡已选包项 +- `#available_pack_items_level` - 关卡可用包项 +- `#realms_pack_items_level` - 关卡 Realms 包项 +- `#unowned_pack_items_level` - 关卡未拥有包项 +- `#invalid_pack_items_level` - 关卡无效包项 +- `#selected_pack_items_addon` - 附加组件已选包项 +- `#available_pack_items_addon` - 附加组件可用包项 +- `#realms_pack_items_addon` - 附加组件 Realms 包项 +- `#unowned_pack_items_addon` - 附加组件未拥有包项 +- `#invalid_pack_items_addon` - 附加组件无效包项 +- `experimental_toggles` - 实验性开关 +- `world_panel` - 世界面板 +- `world_template_panel` - 世界模板面板 +- `resource_panel` - 资源面板 +- `behavior_panel` - 行为面板 +- `skin_panel` - 皮肤面板 +- `cache_panel` - 缓存面板 +- `dependent_packs_panel` - 依赖包面板 +- `dependency_panel` - 依赖关系面板 + +#### 结构方块界面 (`ui/structure_editor_screen.json`) + +- `save_size_grid` - 保存尺寸网格 +- `save_offset_grid` - 保存偏移网格 +- `load_offset_grid` - 加载偏移网格 +- `export_size_grid` - 导出尺寸网格 +- `export_offset_grid` - 导出偏移网格 + +#### 种子选择器界面 (`ui/ugc_viewer_screen.json`) + +- `ugc_items` - UGC 项目集合 + +#### 世界模板界面 (`ui/world_templates_screen.json`) -- `world_templates` -- `realms_plus_templates` -- `custom_world_templates` -- `#suggested_offers_collection` +- `world_templates` - 世界模板 +- `realms_plus_templates` - Realms Plus 模板 +- `custom_world_templates` - 自定义世界模板 +- `#suggested_offers_collection` - 推荐优惠集合 -#### Anvil (`ui/anvil_screen.json`) +#### 铁砧界面 (`ui/anvil_screen.json`) -- `anvil_input_items` -- `anvil_material_items` -- `anvil_result_items` +- `anvil_input_items` - 铁砧输入物品 +- `anvil_material_items` - 铁砧材料物品 +- `anvil_result_items` - 铁砧结果物品 -#### Beacon (`ui/beacon_screen.json`) +#### 信标界面 (`ui/beacon_screen.json`) -- `beacon_payment_items` -- `speed` -- `haste` -- `resist` -- `jump` -- `strength` -- `regen` -- `extra` -- `confirm` -- `cancel` +- `beacon_payment_items` - 信标支付物品 +- `speed` - 速度效果 +- `haste` - 急迫效果 +- `resist` - 抗性效果 +- `jump` - 跳跃提升效果 +- `strength` - 力量效果 +- `regen` - 生命恢复效果 +- `extra` - 额外效果 +- `confirm` - 确认按钮 +- `cancel` - 取消按钮 -#### Brewing Stand (`ui/brewing_stand_screen.json`) +#### 酿造台界面 (`ui/brewing_stand_screen.json`) -- `brewing_fuel_item` -- `brewing_input_item` -- `brewing_result_items` +- `brewing_fuel_item` - 酿造燃料物品 +- `brewing_input_item` - 酿造输入物品 +- `brewing_result_items` - 酿造结果物品 -#### Cartography Table (`ui/cartography_screen.json`) +#### 制图台界面 (`ui/cartography_screen.json`) -- `cartography_input_items` -- `cartography_additional_items` -- `cartography_result_items` - -#### Enchanting Table (`ui/enchanting_table_screen.json`) - -- `enchanting_input_items` -- `enchanting_lapis_items` -- `#enchant_buttons` - -#### Furnace (`ui/furnace_screen.json`) - -- `furnace_ingredient_items` -- `furnace_fuel_items` -- `furnace_output_items` - -#### Gridstone (`ui/grindstone_screen.json`) - -- `grindstone_input_items` -- `grindstone_additional_items` -- `grindstone_result_items` - -#### Horse (`ui/horse_screen.json`) - -- `horse_equip_items` - -#### Inventory (`ui/inventory_screen.json` and `ui/inventory_screen_pocket.json`) - -- `armor_items` -- `offhand_items` -- `crafting_input_items` -- `crafting_output_items` -- `recipe_book` - -#### Loom (`ui/loom_screen.json`) - -- `loom_input_items` -- `loom_dye_items` -- `loom_material_items` -- `loom_result_items` -- `patterns` - -#### Smithing Table (`ui/smithing_table_screen.json`) +- `cartography_input_items` - 制图输入物品 +- `cartography_additional_items` - 制图附加物品 +- `cartography_result_items` - 制图结果物品 + +#### 附魔台界面 (`ui/enchanting_table_screen.json`) + +- `enchanting_input_items` - 附魔输入物品 +- `enchanting_lapis_items` - 附魔青金石物品 +- `#enchant_buttons` - 附魔按钮集合 + +#### 熔炉界面 (`ui/furnace_screen.json`) + +- `furnace_ingredient_items` - 熔炉原料物品 +- `furnace_fuel_items` - 熔炉燃料物品 +- `furnace_output_items` - 熔炉输出物品 + +#### 砂轮界面 (`ui/grindstone_screen.json`) + +- `grindstone_input_items` - 砂轮输入物品 +- `grindstone_additional_items` - 砂轮附加物品 +- `grindstone_result_items` - 砂轮结果物品 + +#### 马匹界面 (`ui/horse_screen.json`) + +- `horse_equip_items` - 马匹装备物品 + +#### 背包界面 (`ui/inventory_screen.json` 和 `ui/inventory_screen_pocket.json`) + +- `armor_items` - 盔甲物品 +- `offhand_items` - 副手物品 +- `crafting_input_items` - 合成输入物品 +- `crafting_output_items` - 合成输出物品 +- `recipe_book` - 配方书 + +#### 织布机界面 (`ui/loom_screen.json`) + +- `loom_input_items` - 织布机输入物品 +- `loom_dye_items` - 织布机染料物品 +- `loom_material_items` - 织布机材料物品 +- `loom_result_items` - 织布机结果物品 +- `patterns` - 图案集合 + +#### 锻造台界面 (`ui/smithing_table_screen.json`) -- `smithing_table_input_items` -- `smithing_table_material_items` -- `smithing_table_result_items` +- `smithing_table_input_items` - 锻造台输入物品 +- `smithing_table_material_items` - 锻造台材料物品 +- `smithing_table_result_items` - 锻造台结果物品 -#### Stonecutter (`ui/stonecutter_screen.json`) +#### 切石机界面 (`ui/stonecutter_screen.json`) -- `stonecutter_input_items` -- `stonecutter_result_items` -- `stones` +- `stonecutter_input_items` - 切石机输入物品 +- `stonecutter_result_items` - 切石机结果物品 +- `stones` - 石头集合 -#### Villager Trade 2 (`ui/trade_2_screen.json`) +#### 村民交易界面2 (`ui/trade_2_screen.json`) -- `trade2_ingredient1_item` -- `trade2_ingredient2_item` -- `trade2_result_item` -- `trade_item_1` -- `trade_item_2` -- `sell_item` -- `trades` -- `trade_tiers` - -## Hardcoded Binding Names - -Some of them only work in specific screens. - -### Screen specific: - -#### Account Transfer Error (`ui/account_transfer_error_screen.json`) - -- `#error_title_text` -- `#error_number_label` -- `#error_number` -- `#correlation_id_label` -- `#correlation_id` - -#### Add External Server (`ui/add_external_server_screen.json`) - -- `#play_button_enabled` -- `#play_button_disabled` -- `#save_button_enabled` -- `#save_button_disabled` - -#### Adhoc In Progress (`ui/adhoc_in_progress_screen.json`) - -- `#adhoc_title` - -#### Authentication (`ui/authentication_screen.json`) - -- `#sign_in_visible` -- `#sign_in_ios_visible` -- `#sign_in_button_visible` -- `#sign_in_ios_buttons_visible` -- `#authentication_message` -- `#confirm_button_enabled` -- `#edu_store_visible` -- `#edu_store_purchase_info` -- `#asking_to_buy_visible` -- `#confirming_purchase_visible` -- `#demo_choice_visible` -- `#eula_visible` -- `#popup_text` -- `#popup_message_student_text` -- `#popup_message_student_visible` -- `#generic_popup_link_visible` -- `#trial_purchase_link_visible` -- `#show_popup_dismiss_button` - -#### Book (`ui/book_screen.json`) - -- `#screenshot_path` -- `#is_photo_page` -- `#is_text_page` -- `#pick_grid_dimensions` -- `#page_number` -- `#title_text_box_item_name` -- `#author_editable` -- `#author_text_box_item_name` -- `#editable` -- `#viewing` -- `#signing` -- `#picking` -- `#exporting` -- `#page_visible` -- `#pick_item_visible` -- `#close_button_visible` -- `#edit_controls_active` -- `#finalize_button_enabled` - -#### Braze (`ui/braze_screen.json`) - -- `#image_texture` - -#### Bundle Purchase Warning (`ui/bundle_purchase_warning_screen.json`) - -- `#banner_visible` -- `#offer_title` -- `#keyart_path` -- `#keyart_texture_file_system` - -#### Chat (`ui/chat_screen.json`) - -- `#keyboard_being_use` -- `#keyboard_button_focus_override_up` -- `#keyboard_button_focus_override_down` -- `#keyboard_button_visible` -- `#send_button_visible` -- `#send_button_accessibility_text` -- `#chat_visible` -- `#message_text_box_content` -- `#text_edit_box_focus_override_up` -- `#text_edit_box_focus_override_down` -- `#auto_complete_item` -- `#auto_complete_text` -- `#get_grid_size` -- `#chat_title_text` -- `#chat_typeface_visible` - -#### Choose Realm (`ui/choose_realm_screen.json`) - -- `#realms_grid_dimension` -- `#world_button_focus_identifier` -- `#ten_player_button_visible` -- `#two_player_button_visible` -- `#realms_world_player_count` -- `#realms_game_online` -- `#realms_game_unavailable` -- `#realms_game_offline` - -#### Coin Purchase (`ui/coin_purchase_screen.json`) - -- `#bonus_coins` -- `#coins_without_bonus` -- `#coin_offer_texture_name` -- `#coin_offer_texture_file_system` -- `#bonus_coins_visible` -- `#price_text` -- `#coins_required_for_purchase` -- `#show_missing_coins` -- `#coin_offer_size` -- `#has_coin_offers` -- `#coin_loading_visible` - -#### Command Block (`ui/command_block_screen.json`) - -- `#maximized_input_visible` -- `#block_type_icon_texture` -- `#close_button_visible_binding_name` -- `#command_impulse_mode` -- `#command_chain_mode` -- `#command_repeat_mode` -- `#block_type_dropdown_toggle_label` -- `#block_type_dropdown_label_color_binding` -- `#block_type_dropdown_enabled` -- `#command_conditional_mode` -- `#command_unconditional_mode` -- `#condition_dropdown_toggle_label` -- `#condition_dropdown_enabled` -- `#command_always_on_mode` -- `#command_needs_redstone_mode` -- `#redstone_dropdown_enabled` -- `#command_hover_note` -- `#execute_on_first_tick_enabled` -- `#command_tick_delay` -- `#command_text_edit` -- `#command_output_text` -- `#previous_block_type_text` -- `#previous_block_type_text_color` -- `#previous_condition_mode_text` -- `#previous_redstone_mode_text` -- `#minimize_button_visible_binding_name` - -#### Comment (`ui/comment_screen.json`) - -- `#report_to_club_button_visible_feeditem` -- `#report_to_enforcement_button_visible_feeditem` -- `#delete_button_visible_feeditem` -- `#report_to_club_button_visible_comment` -- `#report_to_enforcement_button_visible_comment` -- `#delete_button_visible_comment` -- `#comment_buttons_visible` -- `#feed_comment_page_collection_length` -- `#comment_content` -- `#is_author_linked_account` -- `#content` -- `#text_visible` -- `#likes_and_comments` -- `#screenshot_texture` -- `#screenshot_texture_source` -- `#textpost_content` -- `#textpost_visible` -- `#comment_text_box` -- `#comment_platform_tag` -- `#comment_gamertag` -- `#likes_and_time_since_comment_post` -- `#author_gamertag` -- `#time_since_feed_post` -- `#author_platform_tag` -- `#author_gamertag` - -#### Confirm MSA Unlink (`ui/confirm_msa_unlink_screen.json`) - -- `#unlink_warning_text` -- `#unlink_consequences_acknowledged` -- `#confirm_0` -- `#confirm_0_enabled` -- `#confirm_1` -- `#confirm_1_enabled` -- `#confirm_2` -- `#confirm_2_enabled` -- `#confirm_3` -- `#confirm_3_enabled` - -#### Content Log History (`ui/content_log_history_screen.json`) - -- `#content_log_text` -- `#messages_size` - -#### Create World Upsell (`ui/create_world_upsell.json`) - -- `#realm_button_text` -- `#realm_trial_available` - -#### Anvil (`ui/anvil_screen.json`) - -- `#cost_text` -- `#cost_text_green` -- `#cost_text_red` - -#### Beacon (`ui/beacon_screen.json`) - -- `#supports_netherite` -- `#extra_image_selection` - -#### Brewing Stand (`ui/brewing_stand_screen.json`) - -- `#empty_bottle_image_visible` -- `#empty_fuel_image_visible` -- `#brewing_bubbles_ratio` -- `#brewing_fuel_ratio` -- `#brewing_arrow_ratio` - -#### Cartography Table (`ui/cartography_screen.json`) - -- `#is_none_mode` -- `#is_clone_mode` -- `#is_rename_mode` -- `#is_basic_map_mode` -- `#is_locator_map_mode` -- `#is_extend_mode` -- `#is_locked_mode` -- `#output_description` - -#### Enchanting Table (`ui/enchanting_table_screen.json`) - -- `#selectable_dust_is_visible` -- `#unselectable_dust_is_visible` -- `#runes` -- `#cost` -- `#unselectable_button_visibility` -- `#selectable_button_visibility` -- `#show_selected_button_highlight` -- `#active_enchant` -- `#inactive_enchant` -- `#input_item_id` -- `#output_item_id` -- `#enchant_hint` -- `#player_level_color` -- `#player_level_info` -- `#enchant_error` - -#### Furnace (`ui/furnace_screen.json`) - -- `#furnace_arrow_ratio` -- `#furnace_flame_ratio` -- `#output_name` - -#### Horse (`ui/horse_screen.json`) - -- `#entity_id` -- `#equip_grid_dimensions` -- `#inv_grid_dimensions` -- `#sadle_slot_centered` -- `#has_saddle_slot` -- `#has_armor_slot` -- `#has_only_armor_slot` -- `#has_only_carpet_slot` -- `#has_armor_and_saddle_slot` -- `#has_carpet_and_saddle_slot` -- `#is_chested` -- `#renderer_tab_toggle` -- `#chest_tab_toggle` - -#### Loom (`ui/loom_screen.json`) - -- `#pattern_cell_background_texture` -- `#container_cell_background_texture` -- `#empty_image_visible` -- `#banner_patterns` -- `#banner_colors` -- `#pattern_selector_total_items` -- `#result_patterns` -- `#result_colors` -- `#is_right_tab_loom` -- `#is_left_tab_patterns` - -#### Stonecutter (`ui/stonecutter_screen.json`) - -- `#stone_cell_background_texture` -- `#container_cell_background_texture` -- `#item_stack_count` -- `#stone_selector_total_items` -- `#has_input_item` -- `#is_right_tab_stonecutter` -- `#is_left_tab_stones` - -#### Death (`ui/death_screen.json`) - -- `#death_reason_text` -- `#respawn_visible` -- `#quit_enabled` -- `#quit_visible` -- `#buttons_and_deathmessage_visible` - -#### Villager Trade2 (`ui/trade2_screen.json`) - -- `#name_label` -- `#trade_cell_background_texture` -- `#trade_item_count` -- `#single_slash_visible` -- `#double_slash_visible` -- `#second_trade_item_count` -- `#trade_price_different` -- `#trade_cross_out_visible` -- `#padding_around_sell_item` -- `#trade_possible` -- `#trade_toggle_state` -- `#trade_toggle_enabled` -- `#trade_tier_total` -- `#tier_name` -- `#is_tier_unlocked` -- `#is_left_tab_trade` -- `#show_level` -- `#tier_visible` -- `#trade_selector_total` -- `#has_second_buy_item` -- `#exp_bar_visible` -- `#exp_progress` -- `#exp_possible_progress` -- `#trade_details_button_1_visible` -- `#trade_details_button_2_visible` -- `#enchantment_details_button_visible` -- `#item_valid` - -### Value depends on the screen it is in: - -- `#title_text` -- `#body_text` -- `#hover_text` -- `#cross_out_icon` -- `#is_left_tab_inventory` -- `#selected_hover_text` - -### Others: - -- `#tts_dialog_body` -- `#button_enabled` -- `#using_touch` -- `#close_button_visible` - -## Settings - -### Sliders - -| Name | Slider Name | Value Binding Name | TTS Value (`tts_value_changed`) | Slider Text | Enabled Binding Name | -| ------------------------- | ------------------------------- | -------------------------------- | ------------------------------- | --------------------------------------------- | ---------------------------------------- | -| Brightness | `gamma` | `#gamma` | `#gamma_text_value` | `#gamma_slider_label` | `#gamma_enabled` | -| Brightness (VR) | `vr_gamma` | `#vr_gamma` | `#vr_gamma_text_value` | `#vr_gamma_slider_label` | `#vr_gamma_enabled` | -| HUD Opacity | `interface_opacity` | `#interface_opacity` | `#interface_opacity_text_value` | `#interface_opacity_slider_label` | `#interface_opacity_enabled` | -| HUD Opacity (Splitscreen) | `splitscreen_interface_opacity` | `#splitscreen_interface_opacity` | `#interface_opacity_text_value` | `#splitscreen_interface_opacity_slider_label` | `#splitscreen_interface_opacity_enabled` | -| Field Of View | `field_of_view` | `#field_of_view` | `#field_of_view_text_value` | `#field_of_view_slider_label` | `#field_of_view_enabled` | - -### Toggles - -| Name | Toggle Name | State Binding Name | Enabled Binding Name | -| --------------------------------------- | ------------------------------------- | -------------------------------------- | ---------------------------------------------- | -| Invert Y Axis (Mouse) | `keyboard_mouse_invert_y_axis` | `#keyboard_mouse_invert_y_axis` | `#keyboard_mouse_invert_y_axis_enabled` | -| Auto Jump (Mouse) | `keyboard_mouse_autojump` | `#keyboard_mouse_autojump` | `#keyboard_mouse_autojump_enabled` | -| Show Full Keyboard Options | `keyboard_show_full_keyboard_options` | `#keyboard_show_full_keyboard_options` | `#keyboard_show_full_keyboard_options_enabled` | -| Hide Keyboard Tooltips | `hide_keyboard_tooltips` | `#hide_keyboard_tooltips` | `#hide_keyboard_tooltips_enabled` | -| Content File Log | `content_log_file` | `#content_log_file` | `#content_log_file_enabled` | -| Content Gui Log | `content_log_gui` | `#content_log_gui` | `#content_log_gui_enabled` | -| Use SSO | `ad_use_single_sign_on` | `#ad_use_single_sign_on` | | -| Auto Update OFF | `#auto_update_mode_off` | `#auto_update_mode_off` | | -| Auto Update ON with Cellular | `#auto_update_mode_on_with_cellular` | `#auto_update_mode_on_with_cellular` | | -| Auto Update on WiFi Only | `#auto_update_mode_on_wifi_only` | `#auto_update_mode_on_wifi_only` | | -| Auto Update Enabled | `auto_update_enabled` | `#auto_update_enabled` | | -| Cross Platform Enabled | `crossplatform_toggle` | `#crossplatform_toggle` | `#crossplatform_toggle_enabled` | -| Allow Cellular Data | `allow_cellular_data` | `#allow_cellular_data` | `#allow_cellular_data_enabled` | -| Websocket Encryption | `websocket_encryption` | `#websocket_encryption` | `#websocket_encryption_enabled` | -| Only Trusted Skins Allowed | `only_trusted_skins_allowed` | `#only_trusted_skins_allowed` | `#only_trusted_skins_allowed_enabled` | -| Storage Location External | `#storage_location_radio_external` | `#storage_location_radio_external` | `#file_storage_location_enabled` | -| Storage Location App | `#storage_location_radio_package` | `#storage_location_radio_package` | `#file_storage_location_enabled` | -| First Person Perspective | `#thirdperson_radio_first` | `#thirdperson_radio_first` | `#third_person_dropdown_enabled` | -| Third Person Back Perspective | `#thirdperson_radio_third_back` | `#thirdperson_radio_third_back` | `#third_person_dropdown_enabled` | -| Third Person Front Perspective | `#thirdperson_radio_third_front` | `#thirdperson_radio_third_front` | `#third_person_dropdown_enabled` | -| Fullscreen | `full_screen` | `#full_screen` | `#full_screen_enabled` | -| Hide Hand | `hide_hand` | `#hide_hand` | `#hide_hand_enabled` | -| Hide Hand (VR) | `vr_hide_hand` | `#vr_hide_hand` | `#vr_hide_hand_enabled` | -| Hide Paperdoll | `hide_paperdoll` | `#hide_paperdoll` | `#hide_paperdoll_enabled` | -| Hide HUD | `hide_hud` | `#hide_hud` | `#hide_hud_enabled` | -| Hide HUD (VR) | `vr_hide_hud` | `#vr_hide_hud` | `#vr_hide_hud_enabled` | -| Screen Animations | `screen_animations` | `#screen_animations` | `#screen_animations_enabled` | -| Split Screen Horizontally | `#split_screen_radio_horizontal` | `#split_screen_radio_horizontal` | `#split_screen_dropdown_enabled` | -| Split Screen Vertically | `#split_screen_radio_vertical` | `#split_screen_radio_vertical` | `#split_screen_dropdown_enabled` | -| Show Auto Save Icon | `show_auto_save_icon` | `#show_auto_save_icon` | `#show_auto_save_icon_enabled` | -| Outline Selection | `classic_box_selection` | `#classic_box_selection` | `#classic_box_selection_enabled` | -| Outline Selection (VR) | `vr_classic_box_selection` | `#vr_classic_box_selection` | `#vr_classic_box_selection_enabled` | -| Show Players Names Ingame | `ingame_player_names` | `#ingame_player_names` | `#ingame_player_names_enabled` | -| Show Players Names Ingame (Splitscreen) | `splitscreen_ingame_player_names` | `#splitscreen_ingame_player_names` | `#splitscreen_ingame_player_names_enabled` | -| View Bobbing | `view_bobbing` | `#view_bobbing` | `#view_bobbing_enabled` | -| Camera Shake | `camera_shake` | `#camera_shake` | `#camera_shake_enabled` | -| Fancy Leaves | `transparent_leaves` | `#transparent_leaves` | `#transparent_leaves_enabled` | -| Fancy Leaves (VR) | `vr_transparent_leaves` | `#vr_transparent_leaves` | `#vr_transparent_leaves_enabled` | -| Fancy Bubbles | `bubble_particles` | `#bubble_particles` | `#bubble_particles_enabled` | -| Render Clouds | `render_clouds` | `#render_clouds` | `#render_clouds_enabled` | -| Fancy Clouds | `fancy_skies` | `#fancy_skies` | `#fancy_skies_enabled` | -| Smooth Lighting | `smooth_lighting` | `#smooth_lighting` | `#smooth_lighting_enabled` | -| Smooth Lighting (VR) | `graphics_toggle` | `#graphics_toggle` | `#graphics_toggle_enabled` | -| Graphics | `graphics_toggle` | `#graphics_toggle` | `#graphics_toggle_enabled` | -| Field of View | `field_of_view_toggle` | `#field_of_view_toggle` | `#field_of_view_toggle_enabled` | -| Classic UI Profile | `#ui_profile_radio_classic` | `#ui_profile_radio_classic` | `#ui_profile_dropdown_enabled` | -| Pocket UI Profile | `#ui_profile_radio_pocket` | `#ui_profile_radio_pocket` | `#ui_profile_dropdown_enabled` | -| Texel Anti-Aliasing | `texel_aa` | `#texel_aa` | `#texel_aa_enabled` | -| 3D Rendering (VR) | `vr_3d_rendering` | `#vr_3d_rendering` | `#vr_3d_rendering_enabled` | -| Mirror Texture (VR) | `vr_mirror_texture` | `#vr_mirror_texture` | `#vr_mirror_texture_enabled` | -| Hand Pointer Visible (VR) | `vr_hand_pointer` | `#vr_hand_pointer` | `#vr_hand_pointer_enabled` | -| Hands Visible (VR) | `vr_hands_visible` | `#vr_hands_visible` | `#vr_hands_visible_enabled` | -| Enable Auto TTS | `enable_auto_text_to_speech` | `#enable_auto_text_to_speech` | `#enable_auto_text_to_speech_enabled` | -| Enable UI TTS | `enable_ui_text_to_speech` | `#enable_ui_text_to_speech` | `#enable_ui_text_to_speech_enabled` | -| Enable Chat TTS | `enable_chat_text_to_speech` | `#enable_chat_text_to_speech` | `#enable_chat_text_to_speech_enabled` | -| Enable Open Chat Message | `enable_open_chat_message` | `#enable_open_chat_message` | `#enable_open_chat_message_enabled` | -| Camera Shake | `camera_shake` | `#camera_shake` | `#camera_shake_enabled` | -| Languages (Collection) | `languages` | `#language_initial_selected` | | - -## Item ID Aux (`#item_id_aux`) - -| Name | ID | Aux Values | -| ----------------- | :--: | :--------: | -| diamond | 306 | 20054016 | -| emerald | 519 | 34013184 | -| gold_ingot | 308 | 20185088 | -| iron_ingot | 307 | 20119552 | -| netherite_ingot | 616 | 40370176 | -| banner | 574 | 37617664 | -| saddle | 373 | 24444928 | -| cartography_table | -200 | -13107200 | -| chest | 54 | 3538944 | -| crafting_table | 58 | 3801088 | -| loom | -204 | -13369344 | -| stonecutter_block | -197 | -12910592 | - -#### How to calculate block item aux value: - -Aux = ID \* 65536 - -ID = Aux / 65536 -65536 = Aux / ID - -Get all Item IDs [here](https://docs.microsoft.com/en-us/minecraft/creator/reference/content/addonsreference/examples/addonitems). +- `trade2_ingredient1_item` - 交易原料1物品 +- `trade2_ingredient2_item` - 交易原料2物品 +- `trade2_result_item` - 交易结果物品 +- `trade_item_1` - 交易物品1 +- `trade_item_2` - 交易物品2 +- `sell_item` - 出售物品 +- `trades` - 交易集合 +- `trade_tiers` - 交易等级 + +## 硬编码绑定名称 + +部分绑定仅在特定界面中生效。 + +### 界面专属绑定: + +#### 账户转移错误界面 (`ui/account_transfer_error_screen.json`) + +- `#error_title_text` - 错误标题文本 +- `#error_number_label` - 错误编号标签 +- `#error_number` - 错误编号 +- `#correlation_id_label` - 关联ID标签 +- `#correlation_id` - 关联ID + +#### 添加外部服务器界面 (`ui/add_external_server_screen.json`) + +- `#play_button_enabled` - 启用播放按钮 +- `#play_button_disabled` - 禁用播放按钮 +- `#save_button_enabled` - 启用保存按钮 +- `#save_button_disabled` - 禁用保存按钮 + +#### 临时处理中界面 (`ui/adhoc_in_progress_screen.json`) + +- `#adhoc_title` - 临时处理标题 + +#### 认证界面 (`ui/authentication_screen.json`) + +- `#sign_in_visible` - 登录可见 +- `#sign_in_ios_visible` - iOS登录可见 +- `#sign_in_button_visible` - 登录按钮可见 +- `#sign_in_ios_buttons_visible` - iOS登录按钮可见 +- `#authentication_message` - 认证消息 +- `#confirm_button_enabled` - 确认按钮启用 +- `#edu_store_visible` - 教育版商店可见 +- `#edu_store_purchase_info` - 教育版商店购买信息 +- `#asking_to_buy_visible` - 购买询问可见 +- `#confirming_purchase_visible` - 确认购买可见 +- `#demo_choice_visible` - 演示选择可见 +- `#eula_visible` - 用户协议可见 +- `#popup_text` - 弹窗文本 +- `#popup_message_student_text` - 学生弹窗消息文本 +- `#popup_message_student_visible` - 学生弹窗消息可见 +- `#generic_popup_link_visible` - 通用弹窗链接可见 +- `#trial_purchase_link_visible` - 试用购买链接可见 +- `#show_popup_dismiss_button` - 显示弹窗关闭按钮 + +#### 书本界面 (`ui/book_screen.json`) + +- `#screenshot_path` - 截图路径 +- `#is_photo_page` - 是否为照片页 +- `#is_text_page` - 是否为文本页 +- `#pick_grid_dimensions` - 选择网格尺寸 +- `#page_number` - 页码 +- `#title_text_box_item_name` - 标题文本框项目名称 +- `#author_editable` - 作者可编辑 +- `#author_text_box_item_name` - 作者文本框项目名称 +- `#editable` - 可编辑状态 +- `#viewing` - 查看状态 +- `#signing` - 签名状态 +- `#picking` - 选择状态 +- `#exporting` - 导出状态 +- `#page_visible` - 页面可见 +- `#pick_item_visible` - 选择项目可见 +- `#close_button_visible` - 关闭按钮可见 +- `#edit_controls_active` - 编辑控件激活 +- `#finalize_button_enabled` - 完成按钮启用 + +#### Braze界面 (`ui/braze_screen.json`) + +- `#image_texture` - 图像纹理 + +#### 捆绑包购买警告界面 (`ui/bundle_purchase_warning_screen.json`) + +- `#banner_visible` - 横幅可见 +- `#offer_title` - 优惠标题 +- `#keyart_path` - 主视觉图路径 +- `#keyart_texture_file_system` - 主视觉图文件系统纹理 + +#### 聊天界面 (`ui/chat_screen.json`) + +- `#keyboard_being_use` - 正在使用键盘 +- `#keyboard_button_focus_override_up` - 键盘按钮焦点覆盖上 +- `#keyboard_button_focus_override_down` - 键盘按钮焦点覆盖下 +- `#keyboard_button_visible` - 键盘按钮可见 +- `#send_button_visible` - 发送按钮可见 +- `#send_button_accessibility_text` - 发送按钮无障碍文本 +- `#chat_visible` - 聊天可见 +- `#message_text_box_content` - 消息文本框内容 +- `#text_edit_box_focus_override_up` - 文本编辑框焦点覆盖上 +- `#text_edit_box_focus_override_down` - 文本编辑框焦点覆盖下 +- `#auto_complete_item` - 自动补全项目 +- `#auto_complete_text` - 自动补全文本 +- `#get_grid_size` - 获取网格尺寸 +- `#chat_title_text` - 聊天标题文本 +- `#chat_typeface_visible` - 聊天字体可见 + +#### 选择Realm界面 (`ui/choose_realm_screen.json`) + +- `#realms_grid_dimension` - Realms网格尺寸 +- `#world_button_focus_identifier` - 世界按钮焦点标识 +- `#ten_player_button_visible` - 十人游戏按钮可见 +- `#two_player_button_visible` - 双人游戏按钮可见 +- `#realms_world_player_count` - Realms世界玩家数量 +- `#realms_game_online` - Realms游戏在线状态 +- `#realms_game_unavailable` - Realms游戏不可用状态 +- `#realms_game_offline` - Realms游戏离线状态 + +#### 代币购买界面 (`ui/coin_purchase_screen.json`) + +- `#bonus_coins` - 奖励代币 +- `#coins_without_bonus` - 无奖励代币 +- `#coin_offer_texture_name` - 代币优惠纹理名称 +- `#coin_offer_texture_file_system` - 代币优惠文件系统纹理 +- `#bonus_coins_visible` - 奖励代币可见 +- `#price_text` - 价格文本 +- `#coins_required_for_purchase` - 购买所需代币 +- `#show_missing_coins` - 显示缺少的代币 +- `#coin_offer_size` - 代币优惠尺寸 +- `#has_coin_offers` - 是否有代币优惠 +- `#coin_loading_visible` - 代币加载可见 + +#### 命令方块界面 (`ui/command_block_screen.json`) + +- `#maximized_input_visible` - 最大化输入可见 +- `#block_type_icon_texture` - 方块类型图标纹理 +- `#close_button_visible_binding_name` - 关闭按钮可见绑定名称 +- `#command_impulse_mode` - 命令脉冲模式 +- `#command_chain_mode` - 命令连锁模式 +- `#command_repeat_mode` - 命令循环模式 +- `#block_type_dropdown_toggle_label` - 方块类型下拉菜单切换标签 +- `#block_type_dropdown_label_color_binding` - 方块类型下拉菜单标签颜色绑定 +- `#block_type_dropdown_enabled` - 方块类型下拉菜单启用 +- `#command_conditional_mode` - 命令条件模式 +- `#command_unconditional_mode` - 命令无条件模式 +- `#condition_dropdown_toggle_label` - 条件下拉菜单切换标签 +- `#condition_dropdown_enabled` - 条件下拉菜单启用 +- `#command_always_on_mode` - 命令常开模式 +- `#command_needs_redstone_mode` - 命令需要红石模式 +- `#redstone_dropdown_enabled` - 红石下拉菜单启用 +- `#command_hover_note` - 命令悬停说明 +- `#execute_on_first_tick_enabled` - 首次执行启用 +- `#command_tick_delay` - 命令延迟刻数 +- `#command_text_edit` - 命令文本编辑 +- `#command_output_text` - 命令输出文本 +- `#previous_block_type_text` - 先前方块类型文本 +- `#previous_block_type_text_color` - 先前方块类型文本颜色 +- `#previous_condition_mode_text` - 先前条件模式文本 +- `#previous_redstone_mode_text` - 先前红石模式文本 +- `#minimize_button_visible_binding_name` - 最小化按钮可见绑定名称 + +#### 评论界面 (`ui/comment_screen.json`) + +- `#report_to_club_button_visible_feeditem` - 反馈给俱乐部按钮可见(动态项) +- `#report_to_enforcement_button_visible_feeditem` - 反馈给执行按钮可见(动态项) +- `#delete_button_visible_feeditem` - 删除按钮可见(动态项) +- `#report_to_club_button_visible_comment` - 反馈给俱乐部按钮可见(评论) +- `#report_to_enforcement_button_visible_comment` - 反馈给执行按钮可见(评论) +- `#delete_button_visible_comment` - 删除按钮可见(评论) +- `#comment_buttons_visible` - 评论按钮可见 +- `#feed_comment_page_collection_length` - 动态评论页集合长度 +- `#comment_content` - 评论内容 +- `#is_author_linked_account` - 是否为作者关联账户 +- `#content` - 内容 +- `#text_visible` - 文本可见 +- `#likes_and_comments` - 点赞和评论 +- `#screenshot_texture` - 截图纹理 +- `#screenshot_texture_source` - 截图纹理来源 +- `#textpost_content` - 文本发布内容 +- `#textpost_visible` - 文本发布可见 +- `#comment_text_box` - 评论文本框 +- `#comment_platform_tag` - 评论平台标签 +- `#comment_gamertag` - 评论玩家标签 +- `#likes_and_time_since_comment_post` - 点赞和评论发布时间 +- `#author_gamertag` - 作者玩家标签 +- `#time_since_feed_post` - 动态发布时间 +- `#author_platform_tag` - 作者平台标签 + +#### 确认MSA解绑界面 (`ui/confirm_msa_unlink_screen.json`) + +- `#unlink_warning_text` - 解绑警告文本 +- `#unlink_consequences_acknowledged` - 已确认解绑后果 +- `#confirm_0` - 确认0 +- `#confirm_0_enabled` - 确认0启用 +- `#confirm_1` - 确认1 +- `#confirm_1_enabled` - 确认1启用 +- `#confirm_2` - 确认2 +- `#confirm_2_enabled` - 确认2启用 +- `#confirm_3` - 确认3 +- `#confirm_3_enabled` - 确认3启用 + +#### 内容日志历史界面 (`ui/content_log_history_screen.json`) + +- `#content_log_text` - 内容日志文本 +- `#messages_size` - 消息大小 + +#### 创建世界促销界面 (`ui/create_world_upsell.json`) + +- `#realm_button_text` - Realm按钮文本 +- `#realm_trial_available` - Realm试用可用 + +#### 铁砧界面 (`ui/anvil_screen.json`) + +- `#cost_text` - 花费文本 +- `#cost_text_green` - 绿色花费文本 +- `#cost_text_red` - 红色花费文本 + +#### 信标界面 (`ui/beacon_screen.json`) + +- `#supports_netherite` - 支持下界合金 +- `#extra_image_selection` - 额外图像选择 + +#### 酿造台界面 (`ui/brewing_stand_screen.json`) + +- `#empty_bottle_image_visible` - 空瓶图像可见 +- `#empty_fuel_image_visible` - 空燃料图像可见 +- `#brewing_bubbles_ratio` - 酿造气泡比例 +- `#brewing_fuel_ratio` - 酿造燃料比例 +- `#brewing_arrow_ratio` - 酿造箭头比例 + +#### 制图台界面 (`ui/cartography_screen.json`) + +- `#is_none_mode` - 是否为无模式 +- `#is_clone_mode` - 是否为克隆模式 +- `#is_rename_mode` - 是否为重命名模式 +- `#is_basic_map_mode` - 是否为基本地图模式 +- `#is_locator_map_mode` - 是否为定位器地图模式 +- `#is_extend_mode` - 是否为扩展模式 +- `#is_locked_mode` - 是否为锁定模式 +- `#output_description` - 输出描述 + +#### 附魔台界面 (`ui/enchanting_table_screen.json`) + +- `#selectable_dust_is_visible` - 可选粉尘可见 +- `#unselectable_dust_is_visible` - 不可选粉尘可见 +- `#runes` - 符文 +- `#cost` - 花费 +- `#unselectable_button_visibility` - 不可选按钮可见性 +- `#selectable_button_visibility` - 可选按钮可见性 +- `#show_selected_button_highlight` - 显示选中按钮高亮 +- `#active_enchant` - 激活附魔 +- `#inactive_enchant` - 未激活附魔 +- `#input_item_id` - 输入物品ID +- `#output_item_id` - 输出物品ID +- `#enchant_hint` - 附魔提示 +- `#player_level_color` - 玩家等级颜色 +- `#player_level_info` - 玩家等级信息 +- `#enchant_error` - 附魔错误 + +#### 熔炉界面 (`ui/furnace_screen.json`) + +- `#furnace_arrow_ratio` - 熔炉箭头比例 +- `#furnace_flame_ratio` - 熔炉火焰比例 +- `#output_name` - 输出名称 + +#### 马匹界面 (`ui/horse_screen.json`) + +- `#entity_id` - 实体ID +- `#equip_grid_dimensions` - 装备网格尺寸 +- `#inv_grid_dimensions` - 物品栏网格尺寸 +- `#sadle_slot_centered` - 鞍槽居中 +- `#has_saddle_slot` - 有鞍槽 +- `#has_armor_slot` - 有护甲槽 +- `#has_only_armor_slot` - 仅有护甲槽 +- `#has_only_carpet_slot` - 仅有地毯槽 +- `#has_armor_and_saddle_slot` - 有护甲和鞍槽 +- `#has_carpet_and_saddle_slot` - 有地毯和鞍槽 +- `#is_chested` - 是否有箱子 +- `#renderer_tab_toggle` - 渲染器标签切换 +- `#chest_tab_toggle` - 箱子标签切换 + +#### 织布机界面 (`ui/loom_screen.json`) + +- `#pattern_cell_background_texture` - 图案单元格背景纹理 +- `#container_cell_background_texture` - 容器单元格背景纹理 +- `#empty_image_visible` - 空图像可见 +- `#banner_patterns` - 旗帜图案 +- `#banner_colors` - 旗帜颜色 +- `#pattern_selector_total_items` - 图案选择器总项目数 +- `#result_patterns` - 结果图案 +- `#result_colors` - 结果颜色 +- `#is_right_tab_loom` - 是否为右侧织布机标签 +- `#is_left_tab_patterns` - 是否为左侧图案标签 + +#### 切石机界面 (`ui/stonecutter_screen.json`) + +- `#stone_cell_background_texture` - 石头单元格背景纹理 +- `#container_cell_background_texture` - 容器单元格背景纹理 +- `#item_stack_count` - 物品堆叠数量 +- `#stone_selector_total_items` - 石头选择器总项目数 +- `#has_input_item` - 是否有输入物品 +- `#is_right_tab_stonecutter` - 是否为右侧切石机标签 +- `#is_left_tab_stones` - 是否为左侧石头标签 + +#### 死亡界面 (`ui/death_screen.json`) + +- `#death_reason_text` - 死亡原因文本 +- `#respawn_visible` - 重生可见 +- `#quit_enabled` - 退出启用 +- `#quit_visible` - 退出可见 +- `#buttons_and_deathmessage_visible` - 按钮和死亡消息可见 + +#### 村民交易2界面 (`ui/trade2_screen.json`) + +- `#name_label` - 名称标签 +- `#trade_cell_background_texture` - 交易单元格背景纹理 +- `#trade_item_count` - 交易物品数量 +- `#single_slash_visible` - 单斜杠可见 +- `#double_slash_visible` - 双斜杠可见 +- `#second_trade_item_count` - 第二交易物品数量 +- `#trade_price_different` - 交易价格不同 +- `#trade_cross_out_visible` - 交易划掉可见 +- `#padding_around_sell_item` - 出售物品周围填充 +- `#trade_possible` - 交易可能 +- `#trade_toggle_state` - 交易切换状态 +- `#trade_toggle_enabled` - 交易切换启用 +- `#trade_tier_total` - 交易等级总数 +- `#tier_name` - 等级名称 +- `#is_tier_unlocked` - 等级是否解锁 +- `#is_left_tab_trade` - 是否为左侧交易标签 +- `#show_level` - 显示等级 +- `#tier_visible` - 等级可见 +- `#trade_selector_total` - 交易选择器总数 +- `#has_second_buy_item` - 是否有第二购买物品 +- `#exp_bar_visible` - 经验条可见 +- `#exp_progress` - 经验进度 +- `#exp_possible_progress` - 可能经验进度 +- `#trade_details_button_1_visible` - 交易详情按钮1可见 +- `#trade_details_button_2_visible` - 交易详情按钮2可见 +- `#enchantment_details_button_visible` - 附魔详情按钮可见 +- `#item_valid` - 物品有效 + +### 值取决于所在界面的绑定: + +- `#title_text` - 标题文本 +- `#body_text` - 正文文本 +- `#hover_text` - 悬停文本 +- `#cross_out_icon` - 划掉图标 +- `#is_left_tab_inventory` - 是否为左侧物品栏标签 +- `#selected_hover_text` - 选中悬停文本 + +### 其他绑定: + +- `#tts_dialog_body` - 文本转语音对话框正文 +- `#button_enabled` - 按钮启用 +- `#using_touch` - 使用触摸 +- `#close_button_visible` - 关闭按钮可见 + +## 设置选项 + +### 滑动条设置 + +| 设置名称 | 滑动条ID | 数值绑定名称 | 语音播报值 | 文本标签绑定名称 | 启用状态绑定名称 | +|------------------------|--------------------------|--------------------------|--------------------------|------------------------------|------------------------------| +| 亮度调节 | `gamma` | `#gamma` | `#gamma_text_value` | `#gamma_slider_label` | `#gamma_enabled` | +| VR亮度调节 | `vr_gamma` | `#vr_gamma` | `#vr_gamma_text_value` | `#vr_gamma_slider_label` | `#vr_gamma_enabled` | +| HUD透明度 | `interface_opacity` | `#interface_opacity` | `#interface_opacity_text_value` | `#interface_opacity_slider_label` | `#interface_opacity_enabled` | +| 分屏HUD透明度 | `splitscreen_interface_opacity` | `#splitscreen_interface_opacity` | `#interface_opacity_text_value` | `#splitscreen_interface_opacity_slider_label` | `#splitscreen_interface_opacity_enabled` | +| 视野范围(FOV) | `field_of_view` | `#field_of_view` | `#field_of_view_text_value` | `#field_of_view_slider_label` | `#field_of_view_enabled` | + +### 开关选项 + +| 设置名称 | 开关ID | 状态绑定名称 | 启用状态绑定名称 | +|------------------------------|--------------------------------|--------------------------------|----------------------------------| +| 反转Y轴(鼠标) | `keyboard_mouse_invert_y_axis` | `#keyboard_mouse_invert_y_axis` | `#keyboard_mouse_invert_y_axis_enabled` | +| 自动跳跃(鼠标) | `keyboard_mouse_autojump` | `#keyboard_mouse_autojump` | `#keyboard_mouse_autojump_enabled` | +| 显示完整键盘选项 | `keyboard_show_full_keyboard_options` | `#keyboard_show_full_keyboard_options` | `#keyboard_show_full_keyboard_options_enabled` | +| 隐藏键盘提示 | `hide_keyboard_tooltips` | `#hide_keyboard_tooltips` | `#hide_keyboard_tooltips_enabled` | +| 内容文件日志 | `content_log_file` | `#content_log_file` | `#content_log_file_enabled` | +| 内容GUI日志 | `content_log_gui` | `#content_log_gui` | `#content_log_gui_enabled` | +| 使用单点登录(SSO) | `ad_use_single_sign_on` | `#ad_use_single_sign_on` | | +| 关闭自动更新 | `#auto_update_mode_off` | `#auto_update_mode_off` | | +| 启用自动更新(包括移动数据) | `#auto_update_mode_on_with_cellular` | `#auto_update_mode_on_with_cellular` | | +| 仅WiFi自动更新 | `#auto_update_mode_on_wifi_only` | `#auto_update_mode_on_wifi_only` | | +| 启用自动更新 | `auto_update_enabled` | `#auto_update_enabled` | | +| 跨平台游戏 | `crossplatform_toggle` | `#crossplatform_toggle` | `#crossplatform_toggle_enabled` | +| 允许使用移动数据 | `allow_cellular_data` | `#allow_cellular_data` | `#allow_cellular_data_enabled` | +| WebSocket加密 | `websocket_encryption` | `#websocket_encryption` | `#websocket_encryption_enabled` | +| 仅允许可信皮肤 | `only_trusted_skins_allowed` | `#only_trusted_skins_allowed` | `#only_trusted_skins_allowed_enabled` | +| 外部存储位置 | `#storage_location_radio_external` | `#storage_location_radio_external` | `#file_storage_location_enabled` | +| 应用内存储位置 | `#storage_location_radio_package` | `#storage_location_radio_package` | `#file_storage_location_enabled` | +| 第一人称视角 | `#thirdperson_radio_first` | `#thirdperson_radio_first` | `#third_person_dropdown_enabled` | +| 第三人称背后视角 | `#thirdperson_radio_third_back` | `#thirdperson_radio_third_back` | `#third_person_dropdown_enabled` | +| 第三人称正面视角 | `#thirdperson_radio_third_front` | `#thirdperson_radio_third_front` | `#third_person_dropdown_enabled` | +| 全屏模式 | `full_screen` | `#full_screen` | `#full_screen_enabled` | +| 隐藏手持物品 | `hide_hand` | `#hide_hand` | `#hide_hand_enabled` | +| VR模式隐藏手持物品 | `vr_hide_hand` | `#vr_hide_hand` | `#vr_hide_hand_enabled` | +| 隐藏纸娃娃 | `hide_paperdoll` | `#hide_paperdoll` | `#hide_paperdoll_enabled` | +| 隐藏HUD | `hide_hud` | `#hide_hud` | `#hide_hud_enabled` | +| VR模式隐藏HUD | `vr_hide_hud` | `#vr_hide_hud` | `#vr_hide_hud_enabled` | +| 屏幕动画效果 | `screen_animations` | `#screen_animations` | `#screen_animations_enabled` | +| 水平分屏 | `#split_screen_radio_horizontal` | `#split_screen_radio_horizontal` | `#split_screen_dropdown_enabled` | +| 垂直分屏 | `#split_screen_radio_vertical` | `#split_screen_radio_vertical` | `#split_screen_dropdown_enabled` | +| 显示自动保存图标 | `show_auto_save_icon` | `#show_auto_save_icon` | `#show_auto_save_icon_enabled` | +| 经典选择框 | `classic_box_selection` | `#classic_box_selection` | `#classic_box_selection_enabled` | +| VR经典选择框 | `vr_classic_box_selection` | `#vr_classic_box_selection` | `#vr_classic_box_selection_enabled` | +| 显示玩家名称 | `ingame_player_names` | `#ingame_player_names` | `#ingame_player_names_enabled` | +| 分屏显示玩家名称 | `splitscreen_ingame_player_names` | `#splitscreen_ingame_player_names` | `#splitscreen_ingame_player_names_enabled` | +| 视角晃动效果 | `view_bobbing` | `#view_bobbing` | `#view_bobbing_enabled` | +| 相机抖动效果 | `camera_shake` | `#camera_shake` | `#camera_shake_enabled` | +| 透明树叶 | `transparent_leaves` | `#transparent_leaves` | `#transparent_leaves_enabled` | +| VR透明树叶 | `vr_transparent_leaves` | `#vr_transparent_leaves` | `#vr_transparent_leaves_enabled` | +| 气泡粒子效果 | `bubble_particles` | `#bubble_particles` | `#bubble_particles_enabled` | +| 渲染云朵 | `render_clouds` | `#render_clouds` | `#render_clouds_enabled` | +| 精美天空 | `fancy_skies` | `#fancy_skies` | `#fancy_skies_enabled` | +| 平滑光照 | `smooth_lighting` | `#smooth_lighting` | `#smooth_lighting_enabled` | +| VR平滑光照 | `graphics_toggle` | `#graphics_toggle` | `#graphics_toggle_enabled` | +| 图形质量 | `graphics_toggle` | `#graphics_toggle` | `#graphics_toggle_enabled` | +| 视野范围切换 | `field_of_view_toggle` | `#field_of_view_toggle` | `#field_of_view_toggle_enabled` | +| 经典UI风格 | `#ui_profile_radio_classic` | `#ui_profile_radio_classic` | `#ui_profile_dropdown_enabled` | +| 便携版UI风格 | `#ui_profile_radio_pocket` | `#ui_profile_radio_pocket` | `#ui_profile_dropdown_enabled` | +| 像素抗锯齿 | `texel_aa` | `#texel_aa` | `#texel_aa_enabled` | +| VR 3D渲染 | `vr_3d_rendering` | `#vr_3d_rendering` | `#vr_3d_rendering_enabled` | +| VR镜像纹理 | `vr_mirror_texture` | `#vr_mirror_texture` | `#vr_mirror_texture_enabled` | +| VR手部指针可见 | `vr_hand_pointer` | `#vr_hand_pointer` | `#vr_hand_pointer_enabled` | +| VR手部可见 | `vr_hands_visible` | `#vr_hands_visible` | `#vr_hands_visible_enabled` | +| 启用自动文本转语音 | `enable_auto_text_to_speech` | `#enable_auto_text_to_speech` | `#enable_auto_text_to_speech_enabled` | +| 启用UI文本转语音 | `enable_ui_text_to_speech` | `#enable_ui_text_to_speech` | `#enable_ui_text_to_speech_enabled` | +| 启用聊天文本转语音 | `enable_chat_text_to_speech` | `#enable_chat_text_to_speech` | `#enable_chat_text_to_speech_enabled` | +| 启用打开聊天消息 | `enable_open_chat_message` | `#enable_open_chat_message` | `#enable_open_chat_message_enabled` | +| 相机抖动 | `camera_shake` | `#camera_shake` | `#camera_shake_enabled` | +| 语言选择(集合) | `languages` | `#language_initial_selected` | | + +## 物品ID与附加值(`#item_id_aux`) + +| 物品名称 | ID | 附加值 | +|------------------|-------|------------| +| 钻石 | 306 | 20054016 | +| 绿宝石 | 519 | 34013184 | +| 金锭 | 308 | 20185088 | +| 铁锭 | 307 | 20119552 | +| 下界合金锭 | 616 | 40370176 | +| 旗帜 | 574 | 37617664 | +| 鞍 | 373 | 24444928 | +| 制图台 | -200 | -13107200 | +| 箱子 | 54 | 3538944 | +| 工作台 | 58 | 3801088 | +| 织布机 | -204 | -13369344 | +| 切石机 | -197 | -12910592 | + +#### 如何计算方块物品的附加值: + +附加值 = ID × 65536 + +ID = 附加值 ÷ 65536 +65536 = 附加值 ÷ ID + +获取所有物品ID请参考[官方文档](https://docs.microsoft.com/en-us/minecraft/creator/reference/content/addonsreference/examples/addonitems)。 diff --git a/docs/wiki/loot/index.md b/docs/wiki/loot/index.md index 8a06da0d..7d078285 100644 --- a/docs/wiki/loot/index.md +++ b/docs/wiki/loot/index.md @@ -1,5 +1,6 @@ --- title: 战利品、配方、交易 +nav_order: 11 categories: - title: 基础 color: blue diff --git a/docs/wiki/loot/item-functions.md b/docs/wiki/loot/item-functions.md index c7597f81..272d523e 100644 --- a/docs/wiki/loot/item-functions.md +++ b/docs/wiki/loot/item-functions.md @@ -1,10 +1,10 @@ --- -title: Item Functions -category: Documentation +title: 物品功能函数 +category: 文档 nav_order: 4 tags: - - Stable - - Last updated for Version 1.18.10 + - 稳定版 + - 最后更新于版本1.18.10 mentions: - Ciosciaa - MedicalJewel105 @@ -12,52 +12,55 @@ mentions: toc_max_level: 1 --- -Item functions modify the nature of an item in [loot tables](/wiki/loot/loot-tables) and [trade tables](/wiki/loot/trade-tables). +# 物品功能函数 + + + +物品功能函数用于修改[战利品表](/wiki/loot/loot-tables)和[交易表](/wiki/loot/trade-tables)中物品的属性。 TODO -can enchantments be prefixed with minecraft:/whatever? +附魔前缀是否可以使用minecraft:/whatever格式? -Functions -Note that every single thing tested here was in trade tables only -Usable in loot tables and trade tables only -Are objects with `function` and other props… -None accept Molang -No Java additional functions or properties were successful -All may be prefixed with any sequence of text followed by a colon, like `minecraft:exploration_map` or `d1245436576u:fio2ejfoijfiowejf::::::exploration_map` +## 功能函数说明 +以下测试仅在交易表中进行 +仅适用于战利品表和交易表 +是以`function`和其他属性构成的对象... +均不支持Molang表达式 +Java版特有的附加函数或属性均无效 +所有函数名前都可以添加任意文本前缀和冒号,例如`minecraft:exploration_map`或`d1245436576u:fio2ejfoijfiowejf::::::exploration_map` -## General -A handful of functions are available for basic item properties. These functions are usable on any item. +## 通用功能 +以下基础功能适用于所有物品。 -| Function | Container Loot | Block Drops | Fishing | Entity Drops | Entity Equipment | Trade Tables | -| -------------------- | -------------- | ----------- | ------- | ------------ | ---------------- | ------------ | -| `set_count` | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | -| `set_name` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `set_lore` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `set_data` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `random_block_state` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `random_aux_value` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `set_damage` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| 函数名 | 容器战利品 | 方块掉落 | 钓鱼 | 实体掉落 | 实体装备 | 交易表 | +| -------------------- | ---------- | -------- | ------ | -------- | -------- | -------- | +| `set_count` | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | +| `set_name` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `set_lore` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `set_data` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `random_block_state` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `random_aux_value` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `set_damage` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -### Count +### 数量设置 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ❌ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ❌ | -::: tip NOTE -Trade tables use the [`"quantity"` property](/wiki/loot/trade-tables#quantity) to set their count. +::: tip 注意 +交易表使用[`"quantity"`属性](/wiki/loot/trade-tables#quantity)来设置物品数量。 ::: -The `set_count` function sets the count for that item entry. +`set_count`函数用于设置物品数量。 -Count Function - -```json +::: code-group +```json [数量函数] { "function": "set_count", @@ -67,93 +70,94 @@ The `set_count` function sets the count for that item entry. } } ``` +::: -The `"count"` property determines how many of that item should be yielded; it can either be provided as an integer or a [range object](#). Provided counts values may be larger than the stack size for that item. When this happens, the item will leak into other slots if in a container or separate into multiple different item stacks if dropped into the world. The count property actually defaults to `0`, so it should always be included. +`"count"`属性决定物品的产出数量,可以是整数或[范围对象](#)。设置的数量可以超过物品的堆叠上限,此时在容器中会占用多个槽位,掉落在地面时会分成多个物品堆。该属性默认值为`0`,因此必须显式设置。 -### Name +### 名称设置 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | -The name of an item can be set using the `set_name` function. Names are visible in the user interface when hovering over an item. Names can be changed by players using anvils. +`set_name`函数用于设置物品名称。名称会显示在物品悬停提示中,玩家可以使用铁砧修改。 -Name Function - -```json +::: code-group +```json [名称函数] { "function": "set_name", - "name": "Cursed Bow" + "name": "诅咒之弓" } ``` +::: -The name to give the item is given with the string `"name"` property. By default, name text appears italicized. However, item names support format codes, and `§r` can be inserted at the start of the text to reset it to non-italics. Raw text is unsupported in item names. `\n` can be used for newlines. +`"name"`属性设置物品名称。默认显示为斜体,但支持格式代码,可以在开头添加`§r`重置为非斜体。不支持原始文本,可使用`\n`换行。 -### Lore +### 描述文本 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | -The `set_lore` function sets the lore for an item. +`set_lore`函数设置物品的描述文本。 -Lore Function - -```json +::: code-group +```json [描述函数] { "function": "set_lore", "lore": [ - "", - "" + "第一行描述", + "第二行描述" ] } ``` +::: -The `"lore"` property configures the lore. It can be represented as either a string or an array of strings. All lore strings support format codes but do not support localization. In the array form, each string represents a new line of lore. Each such string's formatting context is independent, meaning formatting will reset with each string. By default, purple and italicized text is used for lore; this can be reset by prepending the reset format code (`§r`) to each string as necessary. `\n` can be used within any lore string to form a newline while preserving the current formatting context. +`"lore"`属性可以是字符串或字符串数组。每行支持格式代码但不支持本地化,每行的格式上下文独立。默认显示紫色斜体,可用`§r`重置。`\n`可在单行内换行并保持格式。 -### Data +### 数据值设置 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | -`set_data` establishes the data for the given item, similar to the argument in the `/give` command. If used on a block, it will set the block's data value. If used on an item, it will set it's aux value. Unlike the command, however, `set_data` cannot set the durability of an item. For that, use [`durability`](#durability). +`set_data`设置物品的数据值,类似于`/give`命令的参数。对方块设置其数据值,对物品设置辅助值。注意不能设置物品耐久度,需使用[`durability`](#durability)。 -Data Function - -```json +::: code-group +```json [数据函数] { "function": "set_data", "data": 2 } ``` +::: -The `"data"` property sets the item's data. If not provided, it will default to `0`. `"data"` can either be provided as an integer or a range object. +`"data"`属性可以是整数或范围对象,默认`0`。 -As an integer: +整数形式: ```json "data": 1 ``` -As a range object: +范围对象形式: ```json "data": { "min": 0, @@ -161,24 +165,21 @@ As a range object: } ``` -The object form will randomly select a data value inclusively between the provided minimum and maximum each instance this function's item entry is selected. +### 方块状态 -### Block State +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +`random_block_state`设置方块的单个状态值。 -`random_block_state` sets an individual block state for a block. - -Block State Function - -```json +::: code-group +```json [方块状态函数] { "function": "random_block_state", @@ -186,30 +187,30 @@ The object form will randomly select a data value inclusively between the provid "values": 3 } ``` +::: -Sets a block state for a block +设置方块的某个状态值 block_state -Required string name of block state +必需,方块状态名称字符串 values -Can be number or min/max object -Defaults to 0… kinda required otherwise pointless? IDK… +可以是数字或min/max对象 +默认为0... 否则无意义? -### Aux Value +### 辅助值 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `random_aux_value` -Aux Value Function - -```json +::: code-group +```json [辅助值函数] { "function": "random_aux_value", @@ -219,31 +220,31 @@ Defaults to 0… kinda required otherwise pointless? IDK… } } ``` +::: -Sets aux value of an item +设置物品的辅助值 values -Can be integer or min/max object -Min/max object chosen uniformly randomly -Only used for aux value; won't, for example, set damage of a tool but will set color of wool -Overrides any provided aux value as identifier `:suffix`, like `minecraft:wool:10` -Works on block data, too +可以是整数或min/max对象 +随机均匀选择 +仅影响辅助值(如羊毛颜色而非工具耐久) +会覆盖标识符中的`:suffix`值(如`minecraft:wool:10`) +同样适用于方块数据 -### Durability +### 耐久度 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | -Item durability can be set using the `set_damage` function. +`set_damage`设置物品耐久度。 -Durability Function - -```json +::: code-group +```json [耐久函数] { "function": "set_damage", @@ -253,280 +254,276 @@ Item durability can be set using the `set_damage` function. } } ``` +::: -The `"damage"` property sets the item's durability. It can be represented either as a number or a [range object](#). Values are intended to range from `0` to `1`, where `0` is the minimum possible durability for an item and `1` is undamaged. +`"damage"`属性可以是数字或[范围对象](#),值域`0`到`1`,`0`表示完全损坏,`1`表示全新。 -## Item-Specific Data -Some functions are only usable by a certain set of items. See each function for which items are relevant. +## 物品专属功能 +以下功能仅适用于特定物品。 -| Function | Container Loot | Block Drops | Fishing | Entity Drops | Entity Equipment | Trade Tables | -| -------------------- | -------------- | ----------- | ------- | ------------ | ---------------- | ------------ | -| `furnace_smelt` | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | -| `set_book_contents` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `exploration_map` | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ | -| `set_banner_details` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `random_dye` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `set_actor_id` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `fill_container` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| 函数名 | 容器战利品 | 方块掉落 | 钓鱼 | 实体掉落 | 实体装备 | 交易表 | +| ------------------------ | ---------- | -------- | ------ | -------- | -------- | -------- | +| `furnace_smelt` | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | +| `set_book_contents` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `exploration_map` | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ | +| `set_banner_details` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `random_dye` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `set_actor_id` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `fill_container` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -### Heat Item +### 熔炼物品 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ❌ | -| Block drops | ❌ | -| Fishing | ❌ | -| Entity drops | ✅ | -| Entity equipment | ❌ | -| Trade table | ❌ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ❌ | +| 方块掉落 | ❌ | +| 钓鱼 | ❌ | +| 实体掉落 | ✅ | +| 实体装备 | ❌ | +| 交易表 | ❌ | `furnace_smelt` -Heat Item Function - -```json +::: code-group +```json [熔炼函数] { "function": "furnace_smelt" } ``` +::: -auto-implies that the entity must’ve been on fire when they died -Vanilla files use a function condition for this, but even removing that condition still implies that the entity must’ve died on fire for the furnace_smelt function to trigger +暗示实体必须在死亡时处于燃烧状态 +即使移除条件检查,仍需要实体着火死亡才能触发 -### Book Contents +### 书册内容 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `set_book_contents` -Book Contents Function - -```json +::: code-group +```json [书册函数] { "function": "set_book_contents", - "title": "", - "author": "", + "title": "书名", + "author": "作者", "pages": [ - "", - "" + "第一页内容", + "第二页内容" ] } ``` +::: -Sets data for a book -Can only be used on `writable_book` or `written_book` +仅适用于`writable_book`和`written_book` author -String name of the author +作者名字符串 title -String name of the book +书名字符串 pages -Array of strings — each string is the contents of that page -Supports up to 50 strings and 798 characters per string -12,800‌ character limit across all pages -Use `\n` in the string (not `\\n`) to add newlines -Can’t use tabs -Can use color codes; Each different page string resets the color codes each time +字符串数组,每元素一页 +最多50页,每页798字符 +总字符限制12,800 +使用`\n`换行(非`\\n`) +不支持制表符 +支持颜色代码,每页格式独立 -### Exploration Map +### 探险地图 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `exploration_map` -Exploration Map Function - -```json +::: code-group +```json [地图函数] { "function": "exploration_map", "destination": "village" } ``` +::: -trade table info: +交易表信息: destination -Currently only `monument` `mansion`. -Nothing else, not even buried treasure (this one looks like it’ll work — names the map right instead of Unknown Map like the others, but it doesn’t point anywhere). :( +目前仅支持`monument`和`mansion` +其他类型(如沉船宝藏)会显示为"未知地图" -Loot table info: -Destination -Works for any /locate location (see old recipe notes for caveats there; this is for container loot tables) -Only works if in the appropriate dimension -If a mansion or monument, gets named, colored, and icon’d correctly, corresponding to the right marker decoration -If invalid or no destination is given, shows no marker but still has the river and ocean lines on the map -Works in containers and both entity equipment and drops -Keep in mind how only 2 locations worked from traders +战利品表信息: +支持所有/locate定位点 +需在对应维度 +海底神殿和林地府邸会显示正确图标和名称 +无效目标仍会显示基础地图轮廓 +适用于所有获取方式 -### Banner Type +### 旗帜类型 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `set_banner_details` -Banner Type Function - -```json +::: code-group +```json [旗帜函数] { "function": "set_banner_details" } ``` +::: -Sets type of a `banner` (only usable on this) +仅适用于`banner` type -Can only be 0 or 1 -0 is just a white banner -1 is illager banner +只能是0或1 +0为白色旗帜 +1为灾厄旗帜 -### Random Dyeing +### 随机染色 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `random_dye` -Random Dyeing Function - -```json +::: code-group +```json [染色函数] { "function": "random_dye" } ``` +::: -Randomly dyes leather armor or horse armor -Doesn’t work on wool or whatever +随机染色皮革装备或马铠 +不适用于羊毛等方块 -### Spawn Eggs +### 刷怪蛋 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `set_actor_id` -Spawn Eggs Function - -```json +::: code-group +```json [刷怪蛋函数] { "function": "set_actor_id" } ``` +::: -Usable with spawn eggs +适用于刷怪蛋 id -Should be the identifier for the mob -in trade tables, defaults to trader's entity type +生物标识符 +交易表中默认为交易者实体类型 -### Container Contents +### 容器内容 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `fill_container` -Container Contents Function - -```json +::: code-group +```json [容器函数] { "function": "fill_container" } ``` +::: -Sets the contents of a container block +设置容器方块内容 loot_table -Path to loot table file from behavior pack root +从行为包根目录开始的战利品表路径 +必需,否则显示普通物品 +不能指向当前战利品表 +适用于所有获取方式 -loot_table needed or will just be the normal item -Cannot point to that current loot table -Works in containers and both entity stuff and blocks +## 附魔功能 +| 函数名 | 容器战利品 | 方块掉落 | 钓鱼 | 实体掉落 | 实体装备 | 交易表 | +| -------------------------- | ---------- | -------- | ------ | -------- | -------- | -------- | +| `enchant_book_for_trading` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `enchant_with_levels` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `enchant_randomly` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `enchant_random_gear` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `specific_enchants` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -## Enchanting -| Function | Container Loot | Block Drops | Fishing | Entity Drops | Entity Equipment | Trade Tables | -| -------------------------- | -------------- | ----------- | ------- | ------------ | ---------------- | ------------ | -| `enchant_book_for_trading` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `enchant_with_levels` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `enchant_randomly` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `enchant_random_gear` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| `specific_enchants` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +### 交易附魔书 -### Enchant for Trading - -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `enchant_book_for_trading` -Enchant for Trading Function - -```json +::: code-group +```json [交易附魔函数] { "function": "enchant_book_for_trading" } ``` +::: -documented in trade tables +详见交易表文档 -### Level-Based Enchantments +### 等级附魔 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | -`enchant_with_levels` enchants items using enchantment table logic, optionally allowing for treasure enchantments. +`enchant_with_levels`使用附魔台逻辑附魔物品,可选是否允许宝藏附魔。 -Level-Based Enchantments Function - -```json +::: code-group +```json [等级附魔函数] { "function": "enchant_with_levels", @@ -537,133 +534,127 @@ documented in trade tables "treasure": true } ``` +::: -Enchants books as though off an enchantment table with the given levels -Unlike enchanting table, doesn’t cap at 30, otherwise seems symmetrical -level 99999 gives ludicrously powerful books… with pretty much every possible enchantment on them +类似附魔台机制但不限于30级 +99999级会产生包含几乎所有附魔的超强书 treasure - Enables treasure enchantments as possibilities for that item - boolean, defaults to false - If false, curses can't appear as possibilities; if true, they can +布尔值,默认false +开启宝藏附魔和诅咒附魔可能 levels - Can be number or min/max object - Defaults to 0 - Can be negative, but will just be remapped as though 0. - -### Random Enchantments +数字或min/max对象 +默认0 +负值视为0 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +### 随机附魔 + +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `enchant_randomly` -Random Enchantments Function - -```json +::: code-group +```json [随机附魔函数] { "function": "enchant_randomly" } ``` +::: -Randomly picks a count of enchantments and their strengths for the given item +随机选择附魔类型和等级 treasure -Enables treasure enchantments as possibilities for that item -boolean, defaults to false +布尔值,默认false +开启宝藏附魔可能 -### Enchant Gear +### 装备附魔 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `enchant_random_gear` -Enchant Gear Function - -```json +::: code-group +```json [装备附魔函数] { "function": "enchant_random_gear" } ``` +::: -Randomly picks a count of enchantments and their strengths for the given item -Pretty much like enchant_randomly, but seemingly no treasure enchantments -Not working on shears, but does even work on carrot-on-a-stick +类似enchant_randomly但不含宝藏附魔 +适用于胡萝卜钓竿等非常规装备 chance -Number from 0 to 1 -Chance that the item is enchanted at all -Defaults to 0 -Going over 1 doesn't make it "more" enchanted +0到1的数字 +默认0 +决定是否附魔的概率 -### Specific Enchantments +### 指定附魔 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ✅ | -| Block drops | ✅ | -| Fishing | ✅ | -| Entity drops | ✅ | -| Entity equipment | ✅ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ✅ | +| 方块掉落 | ✅ | +| 钓鱼 | ✅ | +| 实体掉落 | ✅ | +| 实体装备 | ✅ | +| 交易表 | ✅ | `specific_enchants` -Specific Enchantments Function - -```json +::: code-group +```json [指定附魔函数] { "function": "specific_enchants" } ``` +::: -Applies a specific set of enchantments +应用特定附魔组合 enchants -Can be string array or object -For array, any mix of strings or objects (see below) -For string, an enchantment id -For object: +字符串数组或对象 +字符串为附魔ID +对象格式: id -The identifier for the enchantment -See below for names +附魔标识符 level -Optional, defaults to 1 -Can be an exact number or a 2-valued array, representing min and max, inclusive +可选,默认1 +可以是数字或[min,max]数组 -## External Factors -| Function | Container Loot | Block Drops | Fishing | Entity Drops | Entity Equipment | Trade Tables | -| --------------------------- | -------------- | ----------- | ------- | ------------ | ---------------- | ------------ | -| `looting_enchant` | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | -| `explosion_decay` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | -| `set_data_from_color_index` | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | -| `trader_material_type` | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | +## 外部因素 +| 函数名 | 容器战利品 | 方块掉落 | 钓鱼 | 实体掉落 | 实体装备 | 交易表 | +| --------------------------- | ---------- | -------- | ------ | -------- | -------- | -------- | +| `looting_enchant` | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | +| `explosion_decay` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | +| `set_data_from_color_index` | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | +| `trader_material_type` | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | -### Held Tool Looting Enchantment +### 抢夺附魔 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ❌ | -| Block drops | ❌ | -| Fishing | ❌ | -| Entity drops | ✅ | -| Entity equipment | ❌ | -| Trade table | ❌ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ❌ | +| 方块掉落 | ❌ | +| 钓鱼 | ❌ | +| 实体掉落 | ✅ | +| 实体装备 | ❌ | +| 交易表 | ❌ | `looting_enchant` -Held Tool Looting Function - -```json +::: code-group +```json [抢夺函数] { "function": "looting_enchant", @@ -673,74 +664,75 @@ Can be an exact number or a 2-valued array, representing min and max, inclusive } } ``` +::: -Count can be an integer or min/max +count可以是整数或min/max -### Explosion Decay +### 爆炸衰减 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ❌ | -| Block drops | ✅ | -| Fishing | ❌ | -| Entity drops | ❌ | -| Entity equipment | ❌ | -| Trade table | ❌ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ❌ | +| 方块掉落 | ✅ | +| 钓鱼 | ❌ | +| 实体掉落 | ❌ | +| 实体装备 | ❌ | +| 交易表 | ❌ | `explosion_decay` -Explosion Decay Function - -```json +::: code-group +```json [爆炸函数] { "function": "explosion_decay" } ``` +::: -By default, always survives. If in an explosion, has a chance of not dropping based on explosion power at that block’s location +默认总能存活。在爆炸中时,根据爆炸威力有概率不掉落 -### Entity Color +### 实体颜色 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ❌ | -| Block drops | ❌ | -| Fishing | ❌ | -| Entity drops | ❌ | -| Entity equipment | ❌ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ❌ | +| 方块掉落 | ❌ | +| 钓鱼 | ❌ | +| 实体掉落 | ❌ | +| 实体装备 | ❌ | +| 交易表 | ✅ | `set_data_from_color_index` -Entity Color Function - -```json +::: code-group +```json [颜色函数] { "function": "set_data_from_color_index" } ``` +::: -Sets the data value of the block to the value of the `minecraft:color` component on the entity +将方块数据值设置为实体`minecraft:color`组件的值 -### Trader Material Type +### 交易者材料类型 -| Usage | Usable | -| ---------------- | ------ | -| Container loot | ❌ | -| Block drops | ❌ | -| Fishing | ❌ | -| Entity drops | ❌ | -| Entity equipment | ❌ | -| Trade table | ✅ | +| 使用场景 | 是否可用 | +| ------------------ | -------- | +| 容器战利品 | ❌ | +| 方块掉落 | ❌ | +| 钓鱼 | ❌ | +| 实体掉落 | ❌ | +| 实体装备 | ❌ | +| 交易表 | ✅ | `trader_material_type` -Trader Material Type Function - -```json +::: code-group +```json [交易材料函数] { "function": "trader_material_type" } ``` +::: -Only in trades? Maybe it can work somewhere in loot +仅限交易使用?可能也适用于某些战利品 \ No newline at end of file diff --git a/docs/wiki/loot/recipes.md b/docs/wiki/loot/recipes.md index 3985cd12..885a3341 100644 --- a/docs/wiki/loot/recipes.md +++ b/docs/wiki/loot/recipes.md @@ -1,10 +1,10 @@ --- -title: Recipes -category: Documentation +title: 配方系统 +category: 文档 nav_order: 3 tags: - - Stable - - Last updated for Version 1.20.30 + - 稳定版本 + - 最后更新于1.20.30版本 mentions: - Ciosciaa - SirLich @@ -14,21 +14,25 @@ mentions: - QuazChick --- -Recipes are the means of handling several item transactions, namely those occurring in crafting tables, furnaces, campfires, and brewing stands. +# 配方系统 + + + +配方系统用于处理多种物品转换逻辑,包括工作台、熔炉、营火和酿造台的合成流程。 ![](/assets/images/loot/recipes/recipe.png) ::: tip -Anvil interactions are handled within an [item definition](/wiki/items/item-components), not via recipe files. Loom transactions are currently unavailable. +铁砧交互通过[物品定义](/wiki/items/item-components)实现,而非配方文件。织布机交互当前暂不可用。 ::: -No experimental toggles are required to use recipes or any of their features. +使用配方功能无需开启任何实验性选项。 -### Registration +## 注册方式 -All recipes are stored in the `recipes` folder in the behavior pack root. The files can be named and organized under any folder hierarchy as desired. +所有配方文件需存放在行为包根目录的`recipes`文件夹中,支持任意子目录结构和命名方式。 -This arbitrary structure is used for the paths in this document: +以下示例展示了本文档采用的目录结构: -As an example, a "cold steel sword" might be crafted using the following [shaped recipe](#shaped-recipes): +例如,可通过以下[有序配方](#有序配方)制作"寒钢剑": -BP/recipes/crafting/weapons/cold_steel_sword.json -```json +::: code-group +```json [BP/recipes/crafting/weapons/cold_steel_sword.json] { "format_version": "1.17.41", "minecraft:recipe_shaped": { @@ -77,211 +81,217 @@ As an example, a "cold steel sword" might be crafted using the following [shaped } } ``` - -## Shared Properties and Structures - -### Format Version - -The [format version](/wiki/guide/format-version) is intended to version the schema used for the body of a recipe. It is provided with the top-level `"format_version"` property. - -#/ -```json -"format_version": "1.17.41" -``` - -In practice, the format version can be set to any value or even omitted. - -::: warning -It's strongly recommended to include a format version anyway, choosing a value that represents an actual Minecraft version to help future-proof the code. Consider using the current release version or last major release version. ::: -### Description +## 通用属性与结构 -The `"description"` object, required within any recipe type, holds the identifier of a recipe. +### 格式版本 -#/minecraft:recipe_shaped/ -```json +[格式版本](/wiki/guide/format-version)用于标识配方文件的架构版本,通过顶层`"format_version"`属性指定。 + +::: code-group +```json [#/] +"format_version": "1.17.41" +``` +::: + +实际使用中格式版本可设为任意值或省略。 + +::: warning +强烈建议仍保留格式版本,并选择与当前Minecraft版本匹配的值以保证未来兼容性。推荐使用最新正式版或上一个主版本号。 +::: + +### 描述信息 + +`"description"`对象是所有配方类型的必填项,用于声明配方唯一标识符。 + +::: code-group +```json [#/minecraft:recipe_shaped/] "description": { "identifier": "wiki:cold_steel_sword" } ``` +::: -Its only child is the required `"identifier"` property, which is designed to uniquely identify a recipe across all packs applied to a world. There are no namespacing requirements for recipe identifiers except that no two full recipe identifiers in a single pack may match. +其中必填的`"identifier"`属性用于在世界中所有行为包范围内唯一标识配方。单个包内不允许存在重复的完整配方ID。 ::: warning -It's strongly recommended to use a namespace. Namespaces are a standard in other add-on domains and assist in logically scoping the recipe to a pack, lessening possibilities of collisions for players wanting to use multiple behavior packs in their world. +强烈建议使用命名空间。命名空间是附加组件领域的通用规范,有助于将配方逻辑归属到特定行为包,减少多包混用时发生冲突的可能性。 ::: -### Tags +### 标签系统 -Recipes are linked to crafting interfaces using the required `"tags"` array property, which must be placed within any recipe type. These tags will make the recipe be shared across different blocks that uses the `minecraft:crafting_table` component. When the recipe does not inlcude the `crafting_table` tag, or any vanilla tag, but a tag from your custom block, the recipe will only be shared to that custom block and not the crafting table/stonecutter/etc. At least one tag must be provided. +通过必填的`"tags"`数组属性将配方与合成界面关联,该属性需置于任何配方类型中。这些标签会使配方在具有`minecraft:crafting_table`组件的不同方块间共享。若配方不包含`crafting_table`标签或任何原版标签,但包含自定义方块的标签,则该配方仅适用于该自定义方块而非工作台/切石机等。必须提供至少一个标签。 -#/minecraft:recipe_shaped/ -```json +::: code-group +```json [#/minecraft:recipe_shaped/] "tags": ["crafting_table", "altar"] ``` - -Vanilla interfaces are exposed to tags for each set of recipe types. - -Crafting: - -- `crafting_table` -- `stonecutter` -- `smithing_table` - -::: -warning Note that if you want to make a smithing recipe, you will need to use `:netherite_ingot` for the second slot, though using a different identifier will not work. **This no longer works after 1.18.30**. ::: -Cooking and Smelting: +原版界面为各类配方类型开放了对应标签: -- `furnace` -- `blast_furnace` -- `smoker` -- `campfire` -- `soul_campfire` +合成类: +- `crafting_table` +- `stonecutter` +- `smithing_table` -Brewing: +::: warning +注意:若要制作锻造台配方,第二个槽位必须使用`<命名空间>:netherite_ingot`,使用其他标识符将无效。**此特性在1.18.30后已失效**。 +::: -- `brewing_stand` +熔炼类: +- `furnace` +- `blast_furnace` +- `smoker` +- `campfire` +- `soul_campfire` -Education: +酿造类: +- `brewing_stand` -- `material_reducer` +教育版: +- `material_reducer` -::: tip -Additionally, [custom crafting tables](/wiki/blocks/block-components#crafting-table) can declare a custom tag for crafting recipes to use. Custom cooking and smelting blocks and custom brewing stands are not currently available. +::: tip +此外,[自定义工作台](/wiki/blocks/block-components#crafting-table)可声明自定义标签供合成配方使用。目前不支持自定义熔炉和酿造台。 ::: ::: tip -To effectively disable a recipe (useful for [overriding](#overrides) a prior recipe), set the tag array to `[""]`. +要禁用配方(常用于[覆盖](#覆盖机制)已有配方),可将标签数组设为`[""]`。 ::: -### Recipe Unlocking -Minecraft 1.20.30 added recipe unlocking to the game. In order to have your recipes use this function, you `manifest.json` must have a `min_engine_version` of 1.20.11 (1.20.30 is recommender). You also need to add the `unlock` array with its objects to your recipe. +### 配方解锁 +Minecraft 1.20.30新增了配方解锁功能。要使用此功能,需确保`manifest.json`中的`min_engine_version`至少为1.20.11(推荐1.20.30),并在配方中添加`unlock`数组: ```json "unlock": [ { - "item": "wiki:cold_steel" //item to unlock recipe + "item": "wiki:cold_steel" //解锁配方所需物品 }, { - "item": "minecraft:wool", //item to unlock recipe + "item": "minecraft:wool", //解锁配方所需物品 "data": 3 }, { - "context": "PlayerInWater" //event to unlock recipe + "context": "PlayerInWater" //解锁配方所需事件 } ] ``` -Each object in this array contains `"item"` and this tells the recipe what item the player needs in their inventory in order for this recipe to be unlocked. It also accepts data values. `"context"` is used to determine what event unlocks this recipe. `"PlayerInWater"` will unlock this recipe when the player enters water. This is also the only known context for recipes. +数组中每个对象的`"item"`字段表示玩家背包中需要存在的物品(支持数据值)。`"context"`字段表示触发解锁的事件,目前仅知`"PlayerInWater"`会在玩家入水时解锁配方。 -### Item Descriptors +### 物品描述符 -Working with recipes entails referencing items across a number of properties. Items may be provided in one of two formats: a string reference or an item object. Both formats have means of handling data values, but only the item object may be used to specify a count for that item (usable in recipe outputs). For recipe inputs, if no data value is provided, items with any data value under that identifier will be usable for that input. The data value for an output defaults to `0` if one is not explicitly provided. Selecting recipe inputs by item tags is not supported. +配方系统中涉及多种物品引用方式,支持两种格式:字符串引用和物品对象。两种格式均可处理数据值,但只有物品对象能指定数量(用于配方输出)。对于配方输入,若未指定数据值,则该标识符下任意数据值的物品都可用作输入。输出物品的数据值默认为`0`(若未显式指定)。不支持通过物品标签选择配方输入。 -#### String Reference +#### 字符串引用 -Generally, a string reference is just the namespace and identifier combination for that item: +基本格式为物品的命名空间加标识符组合: -#/minecraft:recipe_shapeless/ingredients/0 -```json +::: code-group +```json [#/minecraft:recipe_shapeless/ingredients/0] "minecraft:planks" ``` +::: -String references additionally support specification of a data value as a suffix: +字符串引用还支持通过后缀指定数据值: -#/minecraft:recipe_shapeless/ingredients/0 -```json +::: code-group +```json [#/minecraft:recipe_shapeless/ingredients/0] "minecraft:planks:2" ``` +::: -#### Item Object +#### 物品对象 -The item object is a more explicit construct for referencing items. +物品对象提供了更明确的物品引用结构。 -#/minecraft:recipe_shapeless/ingredients/0 -```json +::: code-group +```json [#/minecraft:recipe_shapeless/ingredients/0] { "item": "minecraft:planks", "data": 2, "count": 3 } ``` +::: -The required `"item"` property functions the same as the string reference format. Although an explicit data field is available, the data suffix string format is still supported in the `"item"` property. However, unlike the suffix form, `"data"` can accept Molang. The Molang here is evaluated once on world load, not per-crafting attempt. Variables cannot be used to pass data between properties in a recipe. Furthermore, the nature of input items cannot be queried. Currently, the only known usable query in the `"data"` property is `q.get_actor_info_id`, used to look up the ID of an entity's spawn egg by its identifier: +必填的`"item"`属性功能同字符串引用。虽然提供了独立的数据字段,但`"item"`属性仍支持数据值后缀格式。不同于后缀形式,`"data"`可接受Molang表达式(该表达式仅在世界加载时计算一次,而非每次合成时计算)。无法通过变量在配方属性间传递数据。目前已知`"data"`属性中唯一可用的查询是`q.get_actor_info_id`,用于通过实体标识符获取其刷怪蛋ID: -#/minecraft:recipe_shapeless/result -```json +::: code-group +```json [#/minecraft:recipe_shapeless/result] { "item": "minecraft:spawn_egg", "data": "q.get_actor_info_id('minecraft:chicken')" } ``` +::: -The optional integer `"count"` property may be used to stack items. It defaults to `1`. Currently, setting the count only functions in [crafting](#crafting) and [furnace](#heating) recipe outputs and [shapeless recipe ingredients](#ingredients). A provided count is ignored in other locations. +可选的整数`"count"`属性用于堆叠物品,默认为`1`。当前仅在[合成](#合成)与[熔炼](#加热)配方输出及[无序配方原料](#原料)中有效,其他场景下会被忽略。 -::: tip NOTE -If a count greater than `1` is provided for an item that does not stack, an error will be thrown. There is no way to force single-return recipe outputs, like those in shapeless recipes or brewing mixes, to return multiple items in one transaction. +::: tip 注意 +若对不可堆叠物品设置数量大于`1`,将抛出错误。无法强制单次返回多个合成输出(如无序配方或酿造混合产物)。 ::: ::: warning -Despite having similarities to trade [table item descriptors](/wiki/loot/trade-tables#items), recipe item descriptors cannot use functions. +尽管与交易[表物品描述符](/wiki/loot/trade-tables#items)相似,配方物品描述符不能使用函数。 ::: -#### Identifier Additions +#### 特殊标识符 -Additional identifiers not typically usable are available to recipes to describe basic potions. +配方系统额外支持描述基础药水的特殊标识符。 -#/minecraft:recipe_brewing_mix/input -```json +::: code-group +```json [#/minecraft:recipe_brewing_mix/input] "minecraft:potion_type:strength" ``` +::: -These identifiers are not usable in the object notation, only the string notation. Variants are unavailable for splash and lingering potions. All such identifiers follow the format: minecraft:potion_type:potion_effect, where potion_effect can be one of the following: +这些标识符仅支持字符串格式,不支持对象格式,且无喷溅/滞留药水变种。所有此类标识符遵循格式:minecraft:potion_type:药水效果,其中药水效果可为以下之一: -- `water` -- `awkward` -- `mundane` -- `thick` -- `healing` -- `regeneration` -- `swiftness` -- `strength` -- `harming` -- `poison` -- `slowness` -- `weakness` -- `water_breathing` -- `fire_resistance` -- `nightvision` -- `invisibility` -- `leaping` -- `slow_falling` -- `turtle_master` -- `wither` +- `water`(水) +- `awkward`(粗制的) +- `mundane`(平凡的) +- `thick`(浓稠的) +- `healing`(治疗) +- `regeneration`(再生) +- `swiftness`(迅捷) +- `strength`(力量) +- `harming`(伤害) +- `poison`(剧毒) +- `slowness`(缓慢) +- `weakness`(虚弱) +- `water_breathing`(水下呼吸) +- `fire_resistance`(抗火) +- `nightvision`(夜视) +- `invisibility`(隐身) +- `leaping`(跳跃) +- `slow_falling`(缓降) +- `turtle_master`(神龟) +- `wither`(衰变) -Where supported, `long_` and `strong_` prefixes may be used to designate modified potions, such as `minecraft:potion_type:strong_poison`. +支持添加`long_`和`strong_`前缀表示强化药水,如`minecraft:potion_type:strong_poison`。 -## Crafting +## 合成系统 -Crafting operations instantly transform inputs to outputs using crafting grids. Two crafting recipe types are available: [shapeless recipes](#shapeless-recipes), whose inputs may be arranged in any way, and [shaped recipes](#shaped-recipes), used to define strict arrangements of inputs. -Crafting recipes support both crafting tables and stonecutters: +合成操作通过合成网格即时转换物品。支持两种配方类型:[无序配方](#无序配方)(原料可任意排列)和[有序配方](#有序配方)(需严格排列原料)。 +合成配方同时支持工作台和切石机: -#/minecraft:recipe_shapeless/ -```json +::: code-group +```json [#/minecraft:recipe_shapeless/] "tags": ["crafting_table", "stonecutter"] ``` +::: -`"crafting_table"` applies to both vanilla crafting tables and the player 2 × 2 crafting grid in their inventory. There is currently no way to opt into one but not the other. Crafting recipes additionally support custom tags, linking recipes to a [crafting grid provided by a custom block](/wiki/blocks/block-components#crafting-table). +`"crafting_table"`同时适用于原版工作台和玩家物品栏中的2×2合成网格,当前无法单独启用其中一种。合成配方还支持自定义标签,可将配方关联到[自定义方块提供的合成网格](/wiki/blocks/block-components#crafting-table)。 -### Shapeless Recipes +### 无序配方 -Shapeless recipes simply bind a collection of inputs to a single output on a crafting grid. +无序配方将原料集合与单个输出简单绑定。 ![](/assets/images/loot/recipes/shapeless_recipe.png) -BP/recipes/decorations/knobs/brass.json -```json +::: code-group +```json [BP/recipes/decorations/knobs/brass.json] { "format_version": "1.17.41", "minecraft:recipe_shapeless": { @@ -316,13 +326,14 @@ Shapeless recipes simply bind a collection of inputs to a single output on a cra } } ``` +::: -#### Ingredients +#### 原料配置 -The required `"ingredients"` array property lists the items required as inputs for the crafting recipe. +必填的`"ingredients"`数组列出了合成所需的原料物品。 -#/minecraft:recipe_shapeless/ -```json +::: code-group +```json [#/minecraft:recipe_shapeless/] "ingredients": [ "wiki:brass", { @@ -331,29 +342,31 @@ The required `"ingredients"` array property lists the items required as inputs f } ] ``` +::: -Each entry is an [item descriptor](#item-descriptors). If an ingredient provides a count, that count must be expressed across multiple crafting grid slots. Using stacked items in a single grid slot to yield a product is unsupported. If the items required for crafting are available but the count of ingredients is greater than the crafting interface being used supports, the recipe will automatically be made unavailable in the recipe book. +每项均为[物品描述符](#物品描述符)。若原料设置了数量,该数量必须通过多个合成网格槽位实现(单个槽位堆叠物品无法用于合成)。当所需物品存在但原料数量超过当前合成界面容量时,配方书会自动将该配方标记为不可用。 -#### Shapeless Results +#### 无序配方输出 -Shapeless recipe outputs are expressed using the required `"result"` property and may be expressed as either an [item descriptor](#item-descriptors) or an array of a single item descriptor. +通过必填的`"result"`属性声明输出,可以是[物品描述符](#物品描述符)或单物品描述符的数组。 -#/minecraft:recipe_shapeless/ -```json +::: code-group +```json [#/minecraft:recipe_shapeless/] "result": { "item": "wiki:door_knob", "data": 3 } ``` +::: -### Shaped Recipes +### 有序配方 -Shaped recipes enforce that the ingredients used during crafting conform to a strict shape. +有序配方要求原料必须按特定图案排列。 ![](/assets/images/loot/recipes/shaped_recipe.png) -BP/recipes/covered_arch.json -```json +::: code-group +```json [BP/recipes/covered_arch.json] { "format_version": "1.17.41", "minecraft:recipe_shaped": { @@ -385,7 +398,6 @@ Shaped recipes enforce that the ingredients used during crafting conform to a st "result": [ { "item": "wiki:covered_arch", - "count": 3 }, "wiki:crafting_scrap" @@ -393,70 +405,75 @@ Shaped recipes enforce that the ingredients used during crafting conform to a st } } ``` +::: -#### Patterns +#### 图案定义 -The required `"pattern"` array property establishes the shape used for the recipe. +必填的`"pattern"`数组属性用于建立配方图案。 -#/minecraft:recipe_shaped/ -```json +::: code-group +```json [#/minecraft:recipe_shaped/] "pattern": [ "SSS", "I I", "I I" ] ``` - -Each entry in the array is a string representing a row in the crafting grid. Each character in each string represents a slot within that row. Spaces by default represent slots that should be empty. - -Characters act as a shorthand to visually describe an item. Each distinct character is matched with a [key](#keys) that dictates what item should be present in that slot. - -::: tip -If the pattern is only comprised of spaces, empty crafting interfaces able to fit that pattern's size will constantly match the recipe. A player may retrieve an infinite amount of the crafting output, including immediately filling their inventory to the limit upon shift-retrieving the result. ::: -##### Row Normalization +数组每项代表合成网格的一行,字符串每个字符代表该行的槽位。默认空格表示该槽位需留空。 -The pattern grid must be at most 3 × 3 but may be smaller. If string lengths are mismatched, Minecraft will automatically extend shorter strings, implying spaces in filled slots. The following two are equivalent: +字符作为物品的视觉简写,每个独特字符需与[键定义](#键定义)匹配以指定对应槽位的物品。 -#/minecraft:recipe_shaped/ -```json +::: tip +若图案全由空格组成,任何能容纳该图案尺寸的空合成界面都会持续匹配该配方。玩家可无限获取输出物品,包括通过Shift键一次性填满背包。 +::: + +##### 行标准化 + +图案网格最大为3×3,可更小。若字符串长度不一致,Minecraft会自动补全较短字符串(用空格填充空缺槽位)。以下两组定义等效: + +::: code-group +```json [#/minecraft:recipe_shaped/] "pattern": [ "MA", "IFI", "M" ] ``` +::: -#/minecraft:recipe_shaped/ -```json +::: code-group +```json [#/minecraft:recipe_shaped/] "pattern": [ "MA ", "IFI", "M " ] ``` - -::: tip NOTE -Currently, no crafting grids, including those configurable from custom blocks, may be larger than 3 × 3. If the expressed pattern is unusable within the current crafting interface, the recipe will automatically be unavailable in the recipe book. ::: -##### Grid Freedom +::: tip 注意 +当前所有合成网格(包括自定义方块配置的)最大不超过3×3。若图案超出当前合成界面容量,配方书会自动将其标记为不可用。 +::: -Spaces are not automatically implied to fill in any remaining slots in the 3 × 3 space. If a provided pattern is smaller than the crafting grid being used, the pattern can be used anywhere so long as the structure and contents are maintained. As an example, consider the following pattern on a crafting table: +##### 网格自由度 -#/minecraft:recipe_shaped/ -```json +空格不会自动填充3×3网格的剩余槽位。若提供的图案小于当前合成网格,只要保持结构和内容,图案可在网格任意位置使用。例如以下图案在工作台上的表现: + +::: code-group +```json [#/minecraft:recipe_shaped/] "pattern": [ "O" "OO" ] ``` +::: -The "L" shape isn't restricted to the upper-left corner of the crafting grid. Using a 3 × 3 grid as an example, the pattern would be usable with any of these configurations: +"L"形图案不限左上角位置,在3×3网格中可能配置如下: - -*Underscores represent empty slots.* + +*下划线代表空槽位* ```txt O__ OO_ @@ -479,87 +496,91 @@ _OO ``` -To restrict placements to a particular location, use explicit spaces, which enforce empty slots in certain locations. The following is only usable in the upper-left corner of a grid: +要限制位置需显式使用空格强制某些槽位留空。以下图案仅能在网格左上角使用: -#/minecraft:recipe_shaped/ -```json +::: code-group +```json [#/minecraft:recipe_shaped/] "pattern": [ "O " "OO " " " ] ``` +::: -##### Symmetry +##### 对称性 -All shaped recipes are innately horizontally symmetric: +所有有序配方默认具有水平对称性: -#/minecraft:recipe_shaped/ -```json +::: code-group +```json [#/minecraft:recipe_shaped/] "pattern": [ "Z " " Z " " Z" ] ``` +::: -The preceding recipe may also be used by a player as though it were set to: +该配方也可被玩家视为以下形式使用: -#/minecraft:recipe_shaped/ -```json +::: code-group +```json [#/minecraft:recipe_shaped/] "pattern": [ " Z" " Z " "Z " ] ``` +::: -#### Keys +#### 键定义 -Keys provide meaning to characters in a [pattern](#patterns), done via the required `"key"` object property, which maps key names to [item descriptors](#item-descriptors). +通过必填的`"key"`对象属性将图案字符映射到[物品描述符](#物品描述符)。 -#/minecraft:recipe_shaped/ -```json +::: code-group +```json [#/minecraft:recipe_shaped/] "key": { "S": "wiki:cloth", "I": "wiki:support" } ``` +::: -Every key present in the pattern should be accounted for here. Keys names are case-sensitive. If an item supports multiple data values and no data value is provided, any item of that identifier will be usable for that key. Any `"count"` property present in an item descriptor is ignored and regarded as `1`; stacked items in a crafting grid slot are only consumable one at a time. +图案中每个字符都需在此定义。键名区分大小写。若物品支持多数据值且未指定数据值,该标识符下任意数据值的物品都可用于该键。物品描述符中的`"count"`属性会被忽略并视为`1`;合成网格槽位中的堆叠物品每次仅消耗一个。 -::: tip NOTE -Any unicode character from `U+0020` to `U+07FF` may be used as a key name. If a key name has more than one character, only the first character is considered. Since spaces are by default used to signify empty slots on a grid and there's no way to re-designate a key for a blank slot, it's not recommended to use them as a key. +::: tip 注意 +可使用`U+0020`到`U+07FF`间的任意Unicode字符作为键名。若键名超过一个字符,仅首字符有效。由于空格默认表示网格空槽且无法重新定义,不建议将其作为键。 ::: ::: warning -If a character in the pattern is not present in the key map, it will be treated as though it were a space, a designated empty tile. +若图案字符未在键映射中定义,将被视为空格(空槽位)。 ::: -### Recipe Unlocking -Minecraft 1.20.30 added recipe unlocking to the game. In order to have your recipes use this function, you `manifest.json` must have a `min_engine_version` of 1.20.11 (1.20.30 is recommender). You also need to add the `unlock` array with its objects to your recipe. +### 配方解锁 +Minecraft 1.20.30新增配方解锁功能。要使用此功能,需确保`manifest.json`中的`min_engine_version`至少为1.20.11(推荐1.20.30),并在配方中添加`unlock`数组: ```json "unlock": [ { - "item": "wiki:cold_steel" //item to unlock recipe + "item": "wiki:cold_steel" //解锁配方所需物品 }, { - "item": "minecraft:wool", //item to unlock recipe + "item": "minecraft:wool", //解锁配方所需物品 "data": 3 }, { - "context": "PlayerInWater" //event to unlock recipe + "context": "PlayerInWater" //解锁配方所需事件 } ] ``` -Each object in this array contains `"item"` and this tells the recipe what item the player needs in their inventory in order for this recipe to be unlocked. `"context"` is used to determine what event unlocks this recipe. `"PlayerInWater"` will unlock this recipe when the player enters water. This is also the only known context for recipes. +数组中每个对象的`"item"`字段表示玩家背包中需要存在的物品。`"context"`字段表示触发解锁的事件,目前仅知`"PlayerInWater"`会在玩家入水时解锁配方。 -#### Shaped Results +#### 有序配方输出 -Shaped crafting recipe outputs behave very similarly to their [shapeless counterparts](#shapeless-results). Unlike array results for shapeless recipes, however, shaped recipe result arrays may contain more than one [item descriptor](#item-descriptors). +有序配方输出行为与[无序配方](#无序配方输出)相似。不同于无序配方的是,有序配方的输出数组可包含多个[物品描述符](#物品描述符)。 -#/minecraft:recipe_shaped/ -```json +::: code-group +```json [#/minecraft:recipe_shaped/] "result": [ { "item": "wiki:covered_arch", @@ -568,56 +589,59 @@ Shaped crafting recipe outputs behave very similarly to their [shapeless counter "wiki:crafting_scrap" ] ``` -The first entry in the array will be used as the visible output of the crafting block. All other values are automatically placed in the player's inventory upon removing the visible result from the output slot. There does not seem to be a limit on the number of items that may be returned from a crafting action. - -::: tip NOTE -Any items not able to fit in the player's inventory are instead placed in the input slots of the crafting table left-to-right and then top-to-bottom. Anything not able to fit there is then thrown from the player as though they had used the "Drop Item" action. ::: -### Recipe Book +数组首项将作为合成方块的可见输出,其余项会在玩家取走可见输出后自动放入背包。目前似乎没有对单次合成返回物品数量的限制。 -The recipe book automatically indexes and displays available recipes to the player, intelligently accounting for [ingredient counts](#ingredients) in shapeless recipes or [pattern constraints](#patterns) in shaped recipes. When multiple recipes point to the same output, the recipe book uses its own unique prioritization system. +::: tip 注意 +无法放入背包的物品会按从左到右、从上到下的顺序放回合成输入槽。若仍无法容纳,则会像玩家执行"丢弃物品"操作一样抛出。 +::: -When both recipes being compared are shapeless recipes, the following rules determine prioritization in order: +### 配方书 -- Lower ingredient count of the _first_ listed ingredient -- More negative [priority](#priority) -- Lower-valued identifier string +配方书自动索引并显示可用配方,智能考虑无序配方的[原料数量](#原料配置)或有序配方的[图案限制](#图案定义)。当多个配方指向相同输出时,配方书使用独特优先级系统。 -For shaped recipes, recipes with "lesser" identifiers, when compared as strings, are always prioritized. +比较两个无序配方时,按以下顺序确定优先级: +1. 第一个列出原料的较低数量 +2. 更小的[优先级值](#优先级) +3. 字典序较小的标识符字符串 -When comparing a shaped recipe to a shapeless recipe, the rules for comparing shapeless recipes are used; however, the interpreted count of ingredients for the shaped recipe is different from its actual ingredient count. Exactly how the ingredient count for a shaped recipe is determined is unknown. +对于有序配方,字典序较小的标识符始终优先。 -### Grouping +比较有序与无序配方时,使用无序配方规则,但有序配方的原料数量计算方式不同(具体机制未知)。 -This section is included informatively. Groups are present in crafting recipes in vanilla definitions, given with the optional `"group"` string property. +### 分组系统 -#/minecraft:recipe_shaped/ -```json +本节为信息性说明。原版定义中的合成配方包含可选的`"group"`字符串属性。 + +::: code-group +```json [#/minecraft:recipe_shaped/] "group": "slingshots" ``` +::: -It is currently unknown what, if anything, this property achieves. Presumably, it would be used with the [recipe book](#recipe-book). Neither using new custom groups nor reusing groups from vanilla definitions appear to achieve anything. +目前未知该属性的具体作用(推测与[配方书](#配方书)相关)。使用自定义分组或复用原版分组均未观察到实际效果。 -### Priority +### 优先级 -Crafting recipes support an additional property for handling input collisions, `"priority"`, which primarily acts as a [tiebreaker](#prioritization) when multiple recipes could possibly apply to the given situation. Priorities are provided directly within the crafting recipe type object. +合成配方支持额外的`"priority"`属性处理输入冲突,主要在[优先级排序](#优先级排序)时作为决胜条件。 -#/minecraft:recipe_shaped/ -```json +::: code-group +```json [#/minecraft:recipe_shaped/] "priority": 2 ``` +::: -Crafting recipes with lower priority values take precedence. So, if all else is equal, a recipe with a priority of `0` would be used over a recipe with priority `1`. Priorities may be negative if necessary. If `"priority"` is not provided, a priority of `0` is implied. +数值较小的配方优先级更高(如优先级`0`优于`1`)。支持负值,未提供时默认为`0`。 -## Heating +## 加热系统 -Furnace recipes are used to transform an item using a heat source over a period of time. A slight misnomer, furnace recipes are used with any interface that involves a heat source, including campfires. +熔炉配方通过热源随时间转换物品。虽然名称局限,实际适用于所有热源界面(包括营火)。 ![](/assets/images/loot/recipes/furnace_recipe.png) -BP/recipes/magic/magic_ash.json -```json +::: code-group +```json [BP/recipes/magic/magic_ash.json] { "format_version": "1.17.41", "minecraft:recipe_furnace": { @@ -633,71 +657,76 @@ Furnace recipes are used to transform an item using a heat source over a period } } ``` +::: -All vanilla heating blocks are supported via tags. +支持所有原版加热方块的标签: -#/minecraft:recipe_furnace/ -```json +::: code-group +```json [#/minecraft:recipe_furnace/] "tags": ["furnace", "blast_furnace", "smoker", "campfire", "soul_campfire"] ``` +::: -### Heating Transactions +### 加热转换 -Furnace recipes bind exactly one input [item descriptor](#item-descriptors) to exactly one output item descriptor. +熔炉配方将单个输入[物品描述符](#物品描述符)绑定到单个输出物品描述符。 -#/minecraft:recipe_furnace/ -```json +::: code-group +```json [#/minecraft:recipe_furnace/] "input": "wiki:bone_fragments" "output": { "item": "wiki:magic_ash", "count": 4 } ``` +::: -Any count given in the input is ignored. XP returns and fuel sources for a cooking and smelting recipe cannot be altered. The time required to heat an item is set by the used block and is unchangeable. +输入中的数量值会被忽略。无法修改经验返还和燃料设定,加热时间由使用的方块决定且不可更改。 -## Brewing +## 酿造系统 -Brewing recipes are used to transform an item using another item as a catalyst. Two brewing recipe types are available: [brewing mixes](#brewing-mixes), which do not transition data from input to output, and [brewing containers](#brewing-containers), which do. +酿造配方通过催化剂物品转换另一物品。支持两种类型:[酿造混合](#酿造混合)(不传递输入输出数据)和[酿造容器](#酿造容器)(传递数据)。 -Only one interface supports brewing recipes: +仅一种界面支持酿造配方: -#/minecraft:recipe_brewing_container/ -```json +::: code-group +```json [#/minecraft:recipe_brewing_container/] "tags": ["brewing_stand"] ``` +::: -### Brewing Transactions +### 酿造转换 -Brewing transactions are similar to [heating transactions](#heating-transactions), requiring an input and output, each pointing to a single [item descriptor](#item-descriptors). Brewing recipes, however, also require the `"reagent"` property as a catalyst, which also can only point to a single item descriptor. +酿造转换类似[加热转换](#加热转换),需要输入和输出各一个[物品描述符](#物品描述符)。此外还需`"reagent"`属性作为催化剂(也仅接受单个物品描述符)。 -#/minecraft:recipe_brewing_mix/ -```json +::: code-group +```json [#/minecraft:recipe_brewing_mix/] "input": "wiki:flask", "reagent": "wiki:jade", "output": "wiki:insanity_resistance" ``` - -Provided count values are ignored in these brewing properties. Items are meant to transform one at a time in a brew. - -::: warning -If the input item for a brewing recipe has the ability to stack, the _entire_ stack will be consumed in the transformation. There are currently no workarounds to avoid this. ::: -After the brewing time has passed, the catalyst is consumed, and output items directly replace input items. +这些属性中的数量值会被忽略,物品每次转换一个。 ::: warning -Currently, the stackability of the produced output is bugged, regardless of whether a data value was specified. In particular, the output is incompatible and will not stack with items of the same identifier and data value. +若酿造配方的输入物品可堆叠,将消耗整个堆叠。目前无法避免此行为。 ::: -### Brewing Mixes +酿造完成后催化剂被消耗,输出物品直接替换输入物品。 -Brewing mixes are simple brewing recipes theoretically designed to isolate the data value of the input from the data value of the output. +::: warning +当前无论是否指定数据值,产出物品的堆叠都存在bug,无法与相同标识符和数据值的物品堆叠。 +::: + +### 酿造混合 + +酿造混合是简单的酿造配方,理论上设计用于隔离输入输出的数据值。 ![](/assets/images/loot/recipes/brewing_mix_recipe.png) -BP/recipes/brewing/negative/paralysis.json -```json +::: code-group +```json [BP/recipes/brewing/negative/paralysis.json] { "format_version": "1.17.41", "minecraft:recipe_brewing_mix": { @@ -711,28 +740,28 @@ Brewing mixes are simple brewing recipes theoretically designed to isolate the d } } ``` - -::: warning -Unfortunately, assigned data values are broken for brewing mix recipes. - -In general, a brewing recipe will never work if a data value is supplied to the input. The only exceptions are if the input is one of the following: - -- `minecraft:potion` -- `minecraft:splash_potion` -- `minecraft:lingering_potion` -- [Potion identifier additions](#identifier-additions) - -If a data value is specified for a reagent using the `"data"` property format, a brew occurs when any item with the given identifier is placed as a reagent for that recipe, regardless of data value. However, the brew only succeeds if the correct data value is matched. If it’s not, the brew will appear to succeed, but the input will not be transformed into the output; despite the brew failing, the reagent and a percentage of the blaze powder fuel are consumed anyway. ::: -### Brewing Containers +::: warning +不幸的是,酿造混合配方的数据值设定存在缺陷。 -Brewing containers are designed to pass the data value of an input to the transformed output. +通常,若对输入指定数据值,酿造配方将完全失效。例外情况是输入为以下之一: +- `minecraft:potion` +- `minecraft:splash_potion` +- `minecraft:lingering_potion` +- [药水特殊标识符](#特殊标识符) + +若通过`"data"`属性为催化剂指定数据值,当酿造台放入该标识符物品时会触发酿造(无论数据值是否匹配)。但只有数据值正确时才会成功转换,否则看似成功实则不转换输入(但仍会消耗催化剂和部分烈焰粉燃料)。 +::: + +### 酿造容器 + +酿造容器设计用于将输入数据值传递到输出。 ![](/assets/images/loot/recipes/brewing_container_recipe.png) -BP/recipes/illumination_potion.json -```json +::: code-group +```json [BP/recipes/illumination_potion.json] { "format_version": "1.17.41", "minecraft:recipe_brewing_container": { @@ -746,33 +775,32 @@ Brewing containers are designed to pass the data value of an input to the transf } } ``` - -Brewing containers are stricter than [brewing mixes](#brewing-mixes) about their inputs. Only the following item types are allowed in a brewing container recipe: - -- `minecraft:potion` -- `minecraft:splash_potion` -- `minecraft:lingering_potion` -- [Potion identifier additions](#identifier-additions) - -Because the data value is carried downstream from input to output in a brewing container recipe, assigned data values in `"input"` and `"output"` are ignored. - -## Overrides - -As with all domains in add-ons, the pack order in the behavior pack list affects how Minecraft chooses files to use during gameplay. Higher-listed behavior pack entries take priority over lower-listed ones, including the base vanilla pack. - -To override a recipe in a lower-listed pack, the recipe type and identifiers must both match. The override file can be named and located in any way — only the contents matter. Partial overrides are not accepted in recipes; the entire recipe must be redefined. - -::: warning -Overrides only work if the recipe type is an _exact_ match. In most cases, a mismatch results in a new recipe created alongside the existing one. - -If attempting to construct an override that converts between the two crafting recipe types, an error will be thrown. To circumvent this, first copy the vanilla definition into the pack. Next, set the `"tags"` for that file to `[""]`; this effectively disables the recipe. Finally, set up a new file as the other crafting recipe type, choosing a different identifier to avoid the error. ::: -## Prioritization +比[酿造混合](#酿造混合)更严格,仅允许以下输入类型: +- `minecraft:potion` +- `minecraft:splash_potion` +- `minecraft:lingering_potion` +- [药水特殊标识符](#特殊标识符) -After considering [overrides](#overrides), if multiple recipes would apply based on the inputs, the outputs are selected using the following tiebreakers, considered in order: +由于数据值从输入传递到输出,`"input"`和`"output"`中指定的数据值会被忽略。 -- Recipes declared in higher-ordered packs in the world behavior packs list -- If for crafting recipes, _lower_-valued [priority properties](#priority) -- If for crafting recipes, [shaped recipes](#shaped-recipes) over [shapeless ones](#shapeless-recipes) -- "Lesser" identifiers, as interpreted by string comparison +## 覆盖机制 + +与所有附加组件领域相同,行为包加载顺序影响游戏中选择的文件。列表中靠前的行为包会覆盖靠后的(包括原版基础包)。 + +要覆盖低优先级包的配方,需完全匹配配方类型和标识符。覆盖文件可任意命名存放——仅内容重要。配方不支持部分覆盖,必须完全重新定义。 + +::: warning +仅当配方类型完全匹配时覆盖才生效。多数情况下不匹配会导致新建配方而非覆盖。 + +若尝试在两种合成配方类型间转换覆盖,将抛出错误。解决方案:先复制原版定义到包中,将其`"tags"`设为`[""]`(禁用配方),再新建另一种类型的配方文件(使用不同标识符避免冲突)。 +::: + +## 优先级排序 + +考虑[覆盖机制](#覆盖机制)后,若多个配方匹配输入,按以下顺序决胜: +1. 行为包列表中更高优先级的包 +2. 合成配方中更小的[优先级值](#优先级) +3. 合成配方中[有序配方](#有序配方)优于[无序配方](#无序配方) +4. 字典序较小的标识符字符串 \ No newline at end of file diff --git a/docs/wiki/loot/trade-tables.md b/docs/wiki/loot/trade-tables.md index 6e770c4d..96c3782b 100644 --- a/docs/wiki/loot/trade-tables.md +++ b/docs/wiki/loot/trade-tables.md @@ -1,28 +1,32 @@ --- -title: Trade Tables -category: Documentation +title: 交易表 +category: 文档 nav_order: 2 tags: - - Stable - - Last updated for Version 1.18.10 + - 稳定版 + - 最后更新于版本1.18.10 mentions: - Ciosciaa - SirLich - TheItsNameless --- -Trade tables represent the fundamental data behind trading item transactions for an entity. Trade tables are not standalone; they must be referenced from an [entity component](https://bedrock.dev/docs/stable/Entities#minecraft%3Aeconomy_trade_table). Using the randomizing properties available to trade tables, trade offers, item counts, and cost calculations may vary across entity instances, even if all would point to the same trade table. +# 交易表 + + + +交易表是实体进行物品交易的基础数据载体。交易表不能独立使用,必须通过[实体组件](https://bedrock.dev/docs/stable/Entities#minecraft%3Aeconomy_trade_table)引用。利用交易表提供的随机化特性,即使多个实体实例引用同一交易表,其交易报价、物品数量和成本计算也可能各不相同。 ![](/assets/images/loot/trade_tables/trading.png) -Trade tables are not identified or versioned. Like loot tables, trade tables do not support Molang and instead rely on JSON constructs, like range objects and [functions](#functions). Despite being different, trade tables still support comments. +交易表没有标识符或版本控制。与战利品表类似,交易表不支持Molang,而是依赖JSON结构(如范围对象和[函数](#functions))。虽然结构不同,交易表仍支持注释功能。 -## Integration +## 集成方式 -Trade tables don't represent a primary add-on system, like blocks or biomes. They aren't registered by being placed in a specific folder; instead, they're referenced (from entities). Trade tables may be placed anywhere within a behavior pack. +交易表不属于核心附加系统(如方块或生物群系)。它们不是通过放置在特定文件夹来注册,而是通过实体引用。交易表可以放置在行为包的任何位置。 ::: tip -It's recommended to follow vanilla convention and place all trade tables within the top-level `trading` directory in a behavior pack. From there, any hierarchy can be employed. +建议遵循原版规范,将所有交易表放在行为包的顶级`trading`目录下。在此目录下可采用任意层级结构。 ::: -The following example is referenced and analyzed throughout the document: +下文将通过一个贯穿文档的示例进行分析: - +::: details 交易表示例文件 -BP/trading/minister.json -```json +::: code-group +```json [BP/trading/minister.json] { "tiers": [ { @@ -159,15 +163,14 @@ The following example is referenced and analyzed throughout the document: ] } ``` - +::: -## Structure +## 结构 -Trade tables are represented as un-versioned, un-namespaced objects. +交易表采用无版本、无命名空间的JSON对象结构。 -# - -```json +::: code-group +```json [#] { "tiers": [ { @@ -175,204 +178,200 @@ Trade tables are represented as un-versioned, un-namespaced objects. }, { "total_exp_required": 28, - "trades": […] } ] } ``` +::: -Trade tables use [tiers](#tiers) to structure trade organization. Tiers are defined with the required top-level `"tiers"` array property. Tiers appear in order in the trading interface. +交易表使用[层级(tiers)](#tiers)来组织交易结构。层级通过顶层的必需数组属性`"tiers"`定义。层级会按照顺序显示在交易界面中。 -### Tiers +### 交易层级 -Tiers act as an unlockable set of trades and represent the highest level of grouping in a trade table. +层级代表可解锁的交易集合,是交易表中的最高级分组单位。 -#/tiers/0 - -```json +::: code-group +```json [#/tiers/0] { "groups": […] } ``` +::: -#/tiers/1 - -```json +::: code-group +```json [#/tiers/1] { "total_exp_required": 28, - "trades": […] } ``` - -Each tier must either represent a set of [trades](#trades) (as `"trades"`) or [trade groups](#groups) (as `"groups"`); one of these properties is required. If trades are specified, all such trades will appear for that tier. If instead groups are given, trades from all listed groups will be used for that tier; how each group selects its trades depends on its configuration. - -::: tip NOTE -If both `"trades"` and `"groups"` are given in a tier, the trades declaration is ignored in favor of groups. ::: -Within a tier, trades appear in order in the trading interface. If trades are grouped, those groups will appear in their defined order as well, organized by group and then by trade. Trades in one group are not visually differentiable from trades in other groups; only tiers are visually separated and identifiable. +每个层级必须包含[交易(trades)](#trades)数组(`"trades"`)或[交易组(groups)](#groups)数组(`"groups"`)中的至少一个属性。如果指定交易数组,该层级将显示所有列出的交易。如果指定交易组数组,则根据组配置从所有列出的组中选择交易。 -#### Experience Requirement +::: tip 注意 +如果同时指定`"trades"`和`"groups"`,系统会优先使用groups而忽略trades声明。 +::: -Tiers are unlocked when the _trader_ meets experience thresholds. Each trader has its own internal lifetime experience that accumulates when trading with players. The amount of experience obtained per trade depends on that trade's [experience reward](#trader-experience). The optional `"total_exp_required"` property specifies how much experience the trader needs in order for that tier to unlock. +在层级内部,交易会按照定义顺序显示。如果交易分组,各组及其内部交易也会按定义顺序组织。不同组的交易在视觉上没有区分,只有层级会进行视觉分隔和标识。 -#/tiers/1/ +#### 经验需求 -```json +当交易者达到经验阈值时,层级会被解锁。每个交易者有独立的累计经验值,通过与玩家交易获得。每次交易获得的经验量取决于该交易的[交易者经验奖励](#trader-experience)。可选属性`"total_exp_required"`指定交易者解锁该层级所需的总经验值。 + +::: code-group +```json [#/tiers/1/] "total_exp_required": 28 ``` - -By default, the amount of experience needed is set to the index of the trade tier. Therefore, the second tier would require the trader to have 1 XP; the third tier would require 2 XP; and so forth. The first tier is always unlocked automatically, [regardless of its set experience threshold](#initial-tier-experience). - -#### Tier Unlocking - -Tiers are unlocked in order. When a new tier is unlocked, the subsequent tier is additionally checked to see if its threshold is met by the current XP. If it is, it unlocks and checks its subsequent tier, and so forth. Tier unlocking is checked when the rewarded trader experience would suffice for multiple tiers or if a [provided initial experience](#initial-tier-experience) would unlock subsequent tiers when correctly updated by the game. - -::: tip NOTE -Since tiers are checked one-at-a-time, if tier unlocking would stop due to the XP requirements of a tier not being met, no subsequent tiers will be checked, even if those later tiers' XP requirements have been met. ::: -##### Initial Tier Experience +默认情况下,所需经验值等于交易层级的索引值。因此第二层需要交易者有1点经验,第三层需要2点,以此类推。[无论设置如何](#initial-tier-experience),第一层级总是自动解锁。 -Special handling occurs for a non-zero experience threshold in the first tier. If negative, _all_ tiers will be unlocked. If greater than 0, the initial experience of the trader is set to the provided value. +#### 层级解锁机制 + +层级按顺序解锁。当新层级解锁时,系统会检查后续层级是否满足当前经验值的阈值要求。如果满足则继续解锁后续层级,依此类推。在以下情况会触发层级解锁检查:(1) 获得的交易者经验足以解锁多个层级时;(2) 游戏正确更新后,[提供的初始经验](#initial-tier-experience)可以解锁后续层级时。 + +::: tip 注意 +由于层级是逐个检查的,如果某个层级的经验要求未满足导致解锁中断,即使后续层级的经验要求已满足,也不会继续检查。 +::: + +##### 初始层级经验 + +第一层级的非零经验阈值有特殊处理:如果为负数,将解锁所有层级;如果大于0,交易者的初始经验值将被设为该值。 ::: warning -When the initial tier's experience threshold is non-zero, a manual update is required for a trader's trades to reflect the actual nature of their trade table. In these cases, performing a trade or closing and re-opening the trading interface will update the interface correctly. Initially, only the first tier will be available even if other tiers should be unlocked. +当第一层级的经验阈值非零时,需要手动更新才能使交易者的交易界面正确反映交易表实际状态。此时需要进行一次交易或关闭再重新打开交易界面才能正确更新界面显示。初始时即使其他层级应该解锁,也只会显示第一层级。 ::: -##### Tier Freezing +##### 层级冻结 -Excluding the [initial tier](#initial-tier-experience), it's possible to freeze trades at a tier: +除[初始层级](#initial-tier-experience)外,可以将交易冻结在某个层级: -Example Tier Freeze - -```json +::: code-group +```json [示例层级冻结] "total_exp_required": -1 ``` +::: -When its prior tier is unlocked, a tier with a negative XP requirement will immediately unlock, [as expected](#tier-unlocking). However, it will be impossible for the player to progress to any subsequent tiers. +当上一层级解锁时,经验要求为负数的层级会立即解锁([符合预期](#tier-unlocking)),但玩家将无法继续解锁后续任何层级。 -### Trade Groups +### 交易组 -Trade groups are a way to randomly select which trades an individual trader should use for a tier. +交易组用于随机选择单个交易者在某个层级应该使用的交易。 -#/tiers/0/groups/0 - -```json +::: code-group +```json [#/tiers/0/groups/0] { "num_to_select": 1, - "trades": […] } ``` +::: -The trades from which to select are given with the required `"trades"` array; each entry is a [trade](#trades). A select number of these trades, indicated by the optional `"num_to_select"` property, will be picked for that tier for each trader. If `"num_to_select"` is `0`, all trades will be selected; this is the default. +通过必需的`"trades"`数组指定候选交易,每个条目都是一个[交易](#trades)。可选属性`"num_to_select"`表示每个交易者实例在该层级选择交易的数量。如果`"num_to_select"`为0(默认值),将选择所有交易。 -::: tip NOTE -Trade groups cannot be nested for advanced chance selection. +::: tip 注意 +交易组不支持嵌套以实现高级概率选择。 ::: ::: tip -Currently, no random selection count is possible. Nor is weighting by trade, but trades can be duplicated within the array to effectively increase their likelihood of being selected. +目前无法随机选择数量,也无法按交易设置权重。但可以通过在数组中重复交易条目来有效增加其被选中的概率。 ::: -### Trades +### 交易 -Trades represent a transaction between a trader and the player. +交易代表交易者与玩家之间的物品交换。 -#/tiers/0/trades/1 - -```json +::: code-group +```json [#/tiers/0/trades/1] { "wants": […], "gives": […], "max_uses": 2, - "reward_exp": false, "trader_exp": 8 } ``` - -Once a trade is picked for a trade slot, it will not fundamentally change. Only the [quantity](#quantity) can be modified in certain situations. - -::: tip -Individual trade definitions can affect more than just trades themselves. Notably, an entity can [hold a particular item](https://bedrock.dev/docs/stable/Entities#minecraft%3Abehavior.trade_interest) in response to the player holding an item. ::: -#### Wanted and Given Items +一旦交易被选入交易槽,其基本内容不会改变。只有[数量](#quantity)在某些情况下可能被修改。 -The fundamental transactional units are declared using `"wants"` and `"gives"`; players trade with `"wants"` to receive `"gives"`. Both properties must be arrays and are required. +::: tip +单个交易定义可以影响交易之外的内容。值得注意的是,实体可以[持有特定物品](https://bedrock.dev/docs/stable/Entities#minecraft%3Abehavior.trade_interest)来响应玩家持有的物品。 +::: -#/tiers/0/trades/1/ +#### 需求与给予物品 -```json +基础交易单元通过`"wants"`和`"gives"`声明:玩家用`"wants"`交换`"gives"`。这两个属性都是必需的数组。 + +::: code-group +```json [#/tiers/0/trades/1/] "wants": […], "gives": […] ``` - -A trade can have between 1 and 2 wanted entries and must have exactly 1 given entry. Each entry of either array may be either an [item](#items) or a [choice](#choices). - -The trading interface will adapt depending on the number of items wanted. In some circumstances, some trading modifiers, such as [quantity-modifying enchantment functions](#quantity-modifying-enchantment-functions), only affect the first wanted item. - -::: tip NOTE -If an object is provided as an entry that contains both item and choice properties, only the choice part is considered; the item parts will be ignored. ::: -#### Trade Limit +每笔交易可以有1-2个需求条目,必须有1个给予条目。每个条目可以是[物品](#items)或[选择项](#choices)。 -A trader can typically only perform an individual trade a set number of times before having to resupply. The numeric `"max_uses"` property configures this number. +交易界面会根据需求物品数量自动调整。某些情况下,[数量修改附魔函数](#quantity-modifying-enchantment-functions)等交易修饰符只影响第一个需求物品。 -#/tiers/0/trades/1/ +::: tip 注意 +如果条目对象同时包含item和choice属性,只有choice部分会被考虑,item部分将被忽略。 +::: -```json +#### 交易次数限制 + +交易者通常只能在补充库存前执行有限次数的单个交易。数值属性`"max_uses"`配置这个限制次数。 + +::: code-group +```json [#/tiers/0/trades/1/] "max_uses": 2 ``` - -Trade limits are specific to each trade. Diminishing supply in one trade won't affect another trade, even if both trades have the same wanted and given items. By default, a trader will be able to carry out an individual trade 7 times before needing to resupply. - -::: tip NOTE -The act of resupplying is handled by an entity component (`"minecraft:trade_resupply": {}`). ::: -If a value of `0` is given, that trade will be shown in the trading interface but will be impossible to use. If a negative value is given, that trade will never need resupplying; it will be infinitely usable. +交易限制是每个交易独立的。一个交易的库存减少不会影响另一个交易,即使两者需求与给予物品完全相同。默认情况下,交易者可以在需要补充前执行7次单个交易。 -#### Player Experience +::: tip 注意 +补充行为由实体组件(`"minecraft:trade_resupply": {}`)处理。 +::: -Experience orbs intended for the _player_ can be disabled for a trade using the optional Boolean `"reward_exp"` property. +如果值为0,该交易会显示在界面中但无法使用。如果为负值,该交易将无限次使用,无需补充。 -#/tiers/0/trades/1/ +#### 玩家经验 -```json +通过可选布尔属性`"reward_exp"`可以禁用交易给玩家的经验球。 + +::: code-group +```json [#/tiers/0/trades/1/] "reward_exp": false ``` - -By default, `"reward_exp"` is true, and the player will be rewarded with some experience for trading. The amount of experience received is not modifiable within a trade table. - -#### Trader Experience - -Traders may receive experience when the player finalizes a trade. This property is the key to establishing a trade progression system with a trader using [tiers](#tiers). - -#/tiers/0/trades/1/ - -```json -"trader_exp": 8 -``` - -The amount of experience to reward the _trader_ is given the the optional numeric property `"trader_exp"`. By default, the trader will receive 1 XP. - -::: tip -For non-linearly spaced tiers, it's typical for the trader experience to increase in higher tiers. This way, lower-tier trades will have less leveling impact than higher-tier trades. ::: -### Choices +默认`"reward_exp"`为true,玩家会因交易获得经验。交易表中无法修改获得的经验量。 -Choices are simple objects for randomly selecting an item to use for a trade. One item is selected with uniform randomness for that trade for each instance of a trader. +#### 交易者经验 -#/tiers/1/trades/0/wants/0 +玩家完成交易时,交易者可能获得经验。此属性是通过[层级](#tiers)建立交易者交易进度系统的关键。 -```json +::: code-group +```json [#/tiers/0/trades/1/] +"trader_exp": 8 +``` +::: + +可选数值属性`"trader_exp"`设置奖励给交易者的经验值。默认交易者获得1点经验。 + +::: tip +对于非线性分布的层级,通常高阶交易的交易者经验奖励更高。这样低阶交易对升级的影响小于高阶交易。 +::: + +### 选择项 + +选择项是简单对象,用于随机选择交易使用的物品。每个交易者实例会均匀随机选择一个物品用于该交易。 + +::: code-group +```json [#/tiers/1/trades/0/wants/0] { "choice": [ { @@ -386,44 +385,42 @@ Choices are simple objects for randomly selecting an item to use for a trade. On ] } ``` +::: -Choices only contain the required `"choice"` array property. Each entry in the array is an [item](#items). At least one item must be provided. +选择项只包含必需的`"choice"`数组属性。数组中必须至少提供一个物品条目。 -::: tip NOTE -Choices cannot be nested. +::: tip 注意 +选择项不能嵌套。 ::: ::: tip -There are currently no means of specifying a weight for a given item, but an item may be duplicated within the array to effectively increase its likelihood for being selected. +目前无法为物品指定权重,但可以通过在数组中重复物品来有效增加其被选中的概率。 ::: -### Items +### 物品 -Items are the subjects of a trade. Their definitions are shared between wanted and given items, but there are some various implications depending on location used. +物品是交易的主体。其定义在需求与给予物品间共享,但根据使用位置有不同的含义。 -#/tiers/1/trades/0/wants/0/choice/0 - -```json +::: code-group +```json [#/tiers/1/trades/0/wants/0/choice/0] { "item": "wiki:sacred_stones", "quantity": { "min": 4, "max": 6 }, - "price_multiplier": 0.5 } ``` +::: -#/tiers/0/groups/0/trades/1/gives/0 - -```json +::: code-group +```json [#/tiers/0/groups/0/trades/1/gives/0] { "item": "wiki:exalted_blade", "functions": [ { "function": "enchant_with_levels", - "treasure": true, "levels": { "min": 15, @@ -433,112 +430,109 @@ Items are the subjects of a trade. Their definitions are shared between wanted a ] } ``` - -#### Item Reference - -Items are referenced within trades using the required `"item"` string property. - -#/tiers/1/trades/0/wants/0/choice/0/ - -```json -"item": "wiki:exalted_blade" -``` - -The item reference must point to the identifier of an item. A data value can be provided in-place to the reference as a suffix: - -Example Data Assignment - -```json -"item": "minecraft:log:2" -``` - -::: tip -Data values can also be set (and much more conveniently randomized) using the `set_data` function. ::: -If no data value is specified for a _wanted_ item, any item with that identifier may be traded. If no data value is specified for a _given_ item, a data value of `0` is implied. +#### 物品引用 -#### Quantity +通过必需的字符串属性`"item"`在交易中引用物品。 -The optional `"quantity"` property specifies the count of items wanted or given in a trade. +::: code-group +```json [#/tiers/1/trades/0/wants/0/choice/0/] +"item": "wiki:exalted_blade" +``` +::: -#/tiers/1/trades/0/wants/0/choice/0/ +物品引用必须指向物品标识符。可以直接在引用后缀中指定数据值: -```json +::: code-group +```json [示例数据值分配] +"item": "minecraft:log:2" +``` +::: + +::: tip +也可以通过`set_data`函数设置(更方便地随机化)数据值。 +::: + +如果需求物品未指定数据值,任何该标识符的物品都可交易。如果给予物品未指定数据值,默认为0。 + +#### 数量 + +可选属性`"quantity"`指定交易中需求或给予的物品数量。 + +::: code-group +```json [#/tiers/1/trades/0/wants/0/choice/0/] "quantity": { "min": 4, "max": 6 } ``` - -Quantity can be expressed as either an integer literal or a range object, such as seen above. If expressed as a range, a random value is selected uniformly inclusively within the specified limits. If no quantity is provided, the item count will default to 1. - -::: tip NOTE -Quantity is always bounded by the stack size and can only affect a single slot in a trade. It's impossible to, for example, enforce a requirement of 100 planks from a single slot (although this can be done using 2 `"wants"`) or giving 2 un-stackable swords to the player in a single trade. ::: -#### Price Multiplier +数量可以是整数或范围对象(如上)。如果是范围,会在最小最大值之间均匀随机选择。未指定时默认为1。 -The price multiplier dictates how an item's [base quantity](#quantity) is altered due to certain events. +::: tip 注意 +数量始终受堆叠限制,且只能影响交易中的单个槽位。无法通过单个槽位要求100个木板(虽然可以用2个`"wants"`实现),也无法通过单个交易给玩家2把不可堆叠的剑。 +::: -#/tiers/1/trades/0/wants/0/choice/0/ +#### 价格乘数 -```json +价格乘数决定物品的[基础数量](#quantity)如何因特定事件而变化。 + +::: code-group +```json [#/tiers/1/trades/0/wants/0/choice/0/] "price_multiplier": 0.5 ``` +::: -`"price_multiplier"` is optional and defaults to `0`. Two systems exist that use the price multiplier: a modern and a legacy system. In the modern system, the given price multiplier can only affect the _first wanted item_ in a trade. In the legacy system, any _wanted items_ can be affected. +`"price_multiplier"`可选,默认为0。存在新旧两套使用价格乘数的系统。新系统中,价格乘数只能影响交易的第一个需求物品。旧系统中,可以影响任何需求物品。 -##### Fluctuation Factors +##### 波动因素 -Trade prices fluctuate as a result of serval factors: +交易价格因以下因素波动: -- An increased demand, occurring when trading for the same item across multiple [resupplies](#trade-limit) -- Being recently cured, such as villagers being cured from being zombie villagers -- Being _near_ a trader who was recently cured -- Trading with a player who is affected with "Hero of the Village" +- 需求增加:同一物品在多次[补充](#trade-limit)后交易 +- 最近被治愈:如村民从僵尸村民治愈 +- 靠近最近被治愈的交易者 +- 与受"村庄英雄"效果影响的玩家交易 -The price multiplier affects all these situations with the exception of a player having "Hero of the Village" when using the new pricing formula, which uses fixed values. +除使用新定价公式的"村庄英雄"效果外,价格乘数影响所有这些情况。新公式使用固定值。 -##### Cost Calculations +##### 成本计算 -The price multiplier directly and solely affects cost increases in response to an increased demand for a trade. By default, demand is 0 and cannot decrease past that value. Demand for a trade stacks, increasing when resupplying after that trade [has been exhausted](#trade-limit) and decreasing if no trades occurred between resupplies. +价格乘数直接影响且仅影响因交易需求增加导致的成本上升。默认需求为0且不能为负。当交易[耗尽](#trade-limit)后补充时需求增加,如果在补充期间未发生交易则需求减少。 -Cost increase due solely to demand is linear, where each increase in demand adds a proportion of the base cost, given by the price multiplier. Assuming the following variables… +仅因需求增加的成本变化是线性的,每增加1点需求就增加基础成本的比例部分(由价格乘数决定)。假设以下变量: -| Variable | Meaning | -| -------- | ------------------------------------------------------------------------------------ | -| _c_ | Total cost | -| _p_ | Base cost, including [quantity overrides](#quantity-modifying-enchantment-functions) | -| _m_ | Price multiplier | -| _d_ | Current demand | - -
-…The following formula can be used to calculate the total cost when no other factors are present: +| 变量 | 含义 | +|------|------| +| _c_ | 总成本 | +| _p_ | 基础成本(含[数量覆盖](#quantity-modifying-enchantment-functions)) | +| _m_ | 价格乘数 | +| _d_ | 当前需求 | +计算公式如下(无其他因素时): _c_ = _p_ × (1 + _m_ \* _d_) -::: tip NOTE -Other situations additionally use entity properties for cost calculations and are not provided here. +::: tip 注意 +其他情况还使用实体属性计算成本,此处不提供。 ::: -If the price multiplier is `0`, the quantity will remain constant in most situations (except the "Hero of the Village" modifier using the new pricing formula). +如果价格乘数为0,在大多数情况下数量保持不变(使用新定价公式的"村庄英雄"修饰符除外)。 -::: tip NOTE -A negative price multiplier is possible but can't affect increasing costs due to [demand](#trade-limit); the multiplier will effectively be capped to `0`. However, negative values do affect prices in response to the trader recently being cured, the trader being nearby another trader who was recently cured, or trading with a player affected with "Hero of the Village" _using the legacy pricing formulas_. +::: tip 注意 +负价格乘数可能,但不会影响因[需求](#trade-limit)增加导致的成本上升(乘数实际被限制为0)。但负值会影响交易者最近被治愈、靠近被治愈交易者或与受"村庄英雄"影响的玩家交易(使用旧定价公式时)的价格。 ::: -#### Functions +#### 函数 -Functions are used to modify the nature of the item. The optional `"functions"` array contains a collection of functions to be applied to the item. +函数用于修改物品属性。可选数组`"functions"`包含应用于物品的函数集合。 -#/tiers/0/groups/0/trades/1/gives/0/ - -```json +::: code-group +```json [#/tiers/0/groups/0/trades/1/gives/0/] "functions": [ { "function": "enchant_with_levels", - "treasure": true, "levels": { "min": 15, @@ -547,56 +541,55 @@ Functions are used to modify the nature of the item. The optional `"functions"` } ] ``` - -The functions used by trade tables are shared with loot tables. When used ([where usable](#unusable-wanted-item-functions)) in a wanted item declaration, they act to restrict the nature of the wanted item. Such function restrictions can only affect the first wanted item. - -##### Generally Unusable Functions - -In general, functions behave well for trading; however, the following do not work anywhere in trade tables: - -- `set_count` -- `furnace_smelt` -- `looting_enchant` -- `trader_material_type` - -::: tip NOTE -`set_count`'s functionality is replaced by the [quantity property](#quantity). - -`trader_material_type`, seen only in a single vanilla trade table, would theoretically set the data value of the item based on the mark variant of the entity, but this doesn't seem to be usable in any custom way. ::: -##### Unusable Wanted Item Functions +交易表与战利品表共享函数。在需求物品声明中使用时([可用处](#unusable-wanted-item-functions)),用于限制需求物品的属性。此类函数限制只能影响第一个需求物品。 -In general, using functions to specify item attributes for a wanted item will require the offered item to conform to those attributes. However, the following functions do not enforce a strict match and are therefore useless on wanted items: +##### 通用不可用函数 -- `set_name` -- `set_lore` -- `set_damage` -- `set_book_contents` -- `random_dye` -- `fill_container` +通常函数在交易中表现良好,但以下函数在交易表中完全无效: -##### Quantity-Modifying Enchantment Functions +- `set_count` +- `furnace_smelt` +- `looting_enchant` +- `trader_material_type` -2 functions actually set the quantity for the first _wanted item_ if being used as _given items_, potentially overriding any provided [quantity](#quantity) for that first wanted item: +::: tip 注意 +`set_count`的功能由[quantity属性](#quantity)替代。 -- `enchant_with_levels` -- `enchant_book_for_trading` - -::: tip NOTE -Despite overriding the quantity, all [modified trade prices](#fluctuation-factors) adapt correctly. These functions cannot affect the quantity of a second wanted item, even when using the legacy cost formulas. If these functions are used on a _wanted item_, the quantity is not overridden. +`trader_material_type`仅在一个原版交易表中出现,理论上会根据实体的mark变种设置物品数据值,但似乎无法自定义使用。 ::: -###### Enchant with Levels Function +##### 需求物品不可用函数 -`enchant_with_levels` randomly enchants an item as through enchanted from an enchantment table. +通常使用函数指定需求物品属性会要求提供的物品符合这些属性。但以下函数不会强制严格匹配,因此在需求物品上无效: -#/tiers/0/groups/0/trades/1/gives/0/functions/0 +- `set_name` +- `set_lore` +- `set_damage` +- `set_book_contents` +- `random_dye` +- `fill_container` -```json +##### 修改数量的附魔函数 + +2个函数实际上会设置第一个需求物品的数量(当作为给予物品使用时),可能覆盖该需求物品的[quantity](#quantity): + +- `enchant_with_levels` +- `enchant_book_for_trading` + +::: tip 注意 +尽管覆盖了数量,所有[修改的交易价格](#fluctuation-factors)都会正确调整。这些函数不能影响第二个需求物品的数量(即使使用旧成本公式)。如果在需求物品上使用这些函数,数量不会被覆盖。 +::: + +###### 附魔等级函数 + +`enchant_with_levels`随机附魔物品,如同通过附魔台附魔。 + +::: code-group +```json [#/tiers/0/groups/0/trades/1/gives/0/functions/0] { "function": "enchant_with_levels", - "treasure": true, "levels": { "min": 5, @@ -604,100 +597,97 @@ Despite overriding the quantity, all [modified trade prices](#fluctuation-factor } } ``` +::: -The cost for the first wanted item is determined by adding this function's chosen level value (capped to `0` if it would be negative) to the original [quantity](#quantity). The level value is computed from the optional `"levels"` property. If a numeric literal is used, that value is the chosen level value. If a range object is used, as above, a random number is rolled inclusively between the provided minimum and maximum. That random number then acts as the chosen level value. In the above example, the first wanted item's cost would be increased by 5 to 25. +第一个需求物品的成本通过将此函数选择的等级值(如果为负则限制为0)加到原始[数量](#quantity)计算。等级值通过可选属性`"levels"`计算。如果使用数值,则为固定等级值。如果使用范围对象(如上),会在最小最大值之间随机选择。上例中第一个需求物品的成本会增加5-25。 -###### Enchant Book for Trading Function +###### 交易附魔书函数 -`enchant_book_for_trading` is intended solely for trading. Its properties combine to determine the first wanted item's cost. +`enchant_book_for_trading`专为交易设计。其属性共同决定第一个需求物品的成本。 -#/tiers/0/groups/0/trades/0/gives/0/functions/0 - -```json +::: code-group +```json [#/tiers/0/groups/0/trades/0/gives/0/functions/0] { "function": "enchant_book_for_trading", - "base_cost": 4, "base_random_cost": 12, "per_level_cost": 4, "per_level_random_cost": 8 } ``` - -This function was only designed to be used on books, rolling for a single enchantment across all possible non-curse enchantments, including treasure enchantments. The function doesn't adapt to the current item. If used on a book, an enchantment will always successfully be applied; if used on something else enchantable, it's possible the item won't be successfully enchanted. - -::: tip NOTE -Presumably, when failing, the function rolls for an enchantment not applicable to the item and then fails to apply this irrelevant enchantment, resulting in an unenchanted item. The successfulness of enchanting a non-book is therefore proportional to the number of enchantments applicable to that item. ::: -The total cost is set from a base cost, which is independent of the rolled enchantment, and a per-level cost, which is dependent on the random roll. All cost configuration properties are optional. +此函数专为书籍设计,在所有可能的非诅咒附魔(包括宝藏附魔)中随机选择一项。函数不适配当前物品。用于书籍时总能成功附魔;用于其他可附魔物品时可能失败。 -The base cost is computed by summing a starting value and a random roll. The starting value is given with `"base_cost"`, which defaults to `2`. The random roll is provided via `"base_random_cost"`, which defaults to `4`. A number will be uniformly randomly selected inclusively between 0 and the `"base_random_cost"` when a trade is generated for a trader. +::: tip 注意 +失败时,函数可能选择了不适用于该物品的附魔导致附魔失败。因此非书籍物品的成功率与其适用附魔数量成正比。 +::: -For each level on the chosen enchantment, the same process occurs as in the base cost calculations: a fixed value is added to a uniformly randomly selected value. In this case, the base per-level cost is given with `"per_level_cost"`, which defaults to `3`, and the random per-level cost is given with `"per_level_random_cost"`, which defaults to `10`. The random per-level roll may be different for each level. +总成本由基础成本(独立于随机附魔)和每级成本(依赖随机结果)组成。所有成本配置属性都是可选的。 -Once the base cost and costs for each level are calculated, they are summed together to form the total cost. Finally, if the chosen enchantment is a treasure enchantment, the cost is then doubled. As usual, this cost cannot be less than 1 or greater than the stack size of that item. This formula holds true regardless of the pricing system being used by the trader. +基础成本是起始值与随机值的和。起始值由`"base_cost"`设置(默认2),随机值由`"base_random_cost"`设置(默认4),在生成交易时均匀随机选择0到`"base_random_cost"`之间的值。 + +每级成本同样计算:固定值加上随机值。固定每级成本由`"per_level_cost"`设置(默认3),随机每级成本由`"per_level_random_cost"`设置(默认10)。每级的随机值可能不同。 + +计算基础成本和所有等级成本后求和得到总成本。如果选择的附魔是宝藏附魔,成本会翻倍。此成本不会小于1或大于物品堆叠上限。无论交易者使用何种定价系统,此公式都适用。 ::: warning -If either random cost property is negative, there seems to be a 50-50 chance that the cost will be either the given [quantity](#quantity) or the maximum stack size for that first wanted item. +如果任一随机成本属性为负,似乎有50%概率使用给定的[数量](#quantity)或第一个需求物品的最大堆叠数作为成本。 ::: ::: tip -If the total combined cost would be negative (assuming no negative random cost properties were used), the provided [quantity](#quantity) of the affected wanted item is used instead. The simplest means of guaranteeing this would be: +如果总成本为负(假设未使用负随机成本属性),则使用受影响需求物品的[数量](#quantity)。最简单的保证方法是: -Example Quantity-Based Enchanted Book Cost - -```json +::: code-group +```json [基于数量的附魔书成本示例] { "function": "enchant_book_for_trading", - "base_cost": -1, "base_random_cost": 0, "per_level_cost": 0, "per_level_random_cost": 0 } ``` - ::: -##### Spawn Egg Trader Binding +##### 刷怪蛋绑定交易者 -The `"set_actor_id"` function is used to set the data value of a spawn egg based on a provided entity identifier, given with `"id"`. +`"set_actor_id"`函数通过`"id"`属性设置刷怪蛋的数据值(基于提供的实体标识符)。 -Example Spawn Egg Trader Binding - -```json +::: code-group +```json [刷怪蛋绑定交易者示例] { "function": "set_actor_id" } ``` - -In trade tables, if no ID is provided, the trader's entity type will be assigned to the egg. - -## Overrides - -Because trade tables do not use in-data identifiers, they are overridden simply by replacing a prior trade table with a new one. You can learn more about [asset overrides here](/wiki/concepts/overwriting-assets) - -Below are the currently used vanilla trade tables for each trader: -|Trader|Path| -|-|-| -|Stone Mason|`BP/trading/economy_trades/stone_mason_trades.json`| -|Farmer|`BP/trading/economy_trades/farmer_trades.json`| -|Fisherman|`BP/trading/economy_trades/fisherman_trades.json`| -|Butcher|`BP/trading/economy_trades/butcher_trades.json`| -|Shepherd|`BP/trading/economy_trades/shepherd_trades.json`| -|Leather Worker|`BP/trading/economy_trades/leather_worker_trades.json`| -|Librarian|`BP/trading/economy_trades/librarian_trades.json`| -|Cartographer|`BP/trading/economy_trades/cartographer_trades.json`| -|Cleric|`BP/trading/economy_trades/cleric_trades.json`| -|Tool Smith|`BP/trading/economy_trades/tool_smith_trades.json`| -|Weapon Smith|`BP/trading/economy_trades/weapon_smith_trades.json`| -|Fletcher|`BP/trading/economy_trades/fletcher_trades.json`| -|Armorer|`BP/trading/economy_trades/armorer_trades.json`| -|Wandering Trader|`BP/trading/economy_trades/wandering_trader_trades.json`| - -::: tip NOTE -Additional trade tables exist directly within the `trading` folder, but these are deprecated. Only the tables in the `economy_trades` sub-folder are currently used. ::: -Alternatively, a trader entity definition can be updated to point to a new trade table location. +在交易表中,如果未提供ID,刷怪蛋将绑定交易者的实体类型。 + +## 覆盖 + +由于交易表不使用数据内标识符,只需用新交易表替换旧表即可实现覆盖。了解更多关于[资源覆盖](/wiki/concepts/overwriting-assets)的内容。 + +以下是各交易者当前使用的原版交易表: +|交易者|路径| +|-|-| +|石匠|`BP/trading/economy_trades/stone_mason_trades.json`| +|农民|`BP/trading/economy_trades/farmer_trades.json`| +|渔夫|`BP/trading/economy_trades/fisherman_trades.json`| +|屠夫|`BP/trading/economy_trades/butcher_trades.json`| +|牧羊人|`BP/trading/economy_trades/shepherd_trades.json`| +|制革师|`BP/trading/economy_trades/leather_worker_trades.json`| +|图书管理员|`BP/trading/economy_trades/librarian_trades.json`| +|制图师|`BP/trading/economy_trades/cartographer_trades.json`| +|牧师|`BP/trading/economy_trades/cleric_trades.json`| +|工具匠|`BP/trading/economy_trades/tool_smith_trades.json`| +|武器匠|`BP/trading/economy_trades/weapon_smith_trades.json`| +|制箭师|`BP/trading/economy_trades/fletcher_trades.json`| +|盔甲匠|`BP/trading/economy_trades/armorer_trades.json`| +|流浪商人|`BP/trading/economy_trades/wandering_trader_trades.json`| + +::: tip 注意 +`trading`文件夹中还存在其他交易表,但已弃用。目前仅使用`economy_trades`子文件夹中的表。 +::: + +或者,可以更新交易者实体定义以指向新的交易表位置。 \ No newline at end of file diff --git a/docs/wiki/meta/index.md b/docs/wiki/meta/index.md index f2207e98..7e694dfe 100644 --- a/docs/wiki/meta/index.md +++ b/docs/wiki/meta/index.md @@ -1,3 +1,4 @@ --- title: Meta +nav_order: 12 --- diff --git a/docs/wiki/modsdk/index.md b/docs/wiki/modsdk/index.md index a19ab678..f1b0cb1c 100644 --- a/docs/wiki/modsdk/index.md +++ b/docs/wiki/modsdk/index.md @@ -1,5 +1,6 @@ --- title: 中国版Mod开发 +nav_order: 2 categories: - title: 基础 color: blue diff --git a/docs/wiki/modsdk/modsdk-intro.md b/docs/wiki/modsdk/modsdk-intro.md index 618e0990..ff744984 100644 --- a/docs/wiki/modsdk/modsdk-intro.md +++ b/docs/wiki/modsdk/modsdk-intro.md @@ -106,7 +106,7 @@ class MyClientSystem(ClientSystem): BOOM!就这么简单! :::details :bulb: 为什么需要这些System? - + ::: ## 3. 运行你的Mod diff --git a/docs/wiki/nbt/index.md b/docs/wiki/nbt/index.md index 6ea6e7bd..4813ddb3 100644 --- a/docs/wiki/nbt/index.md +++ b/docs/wiki/nbt/index.md @@ -1,5 +1,6 @@ --- title: NBT +nav_order: 13 categories: - title: 基础 color: blue diff --git a/docs/wiki/particles/index.md b/docs/wiki/particles/index.md index e271ae85..2bd7085d 100644 --- a/docs/wiki/particles/index.md +++ b/docs/wiki/particles/index.md @@ -1,5 +1,6 @@ --- title: 粒子 Particles +nav_order: 14 categories: - title: 基础 color: blue diff --git a/docs/wiki/servers/index.md b/docs/wiki/servers/index.md index 91bb0cac..7ddbeedc 100644 --- a/docs/wiki/servers/index.md +++ b/docs/wiki/servers/index.md @@ -1,3 +1,4 @@ --- title: 服务器 & 领域服 +nav_order: 15 --- diff --git a/docs/wiki/visuals/index.md b/docs/wiki/visuals/index.md index 48a28eee..1d9b0936 100644 --- a/docs/wiki/visuals/index.md +++ b/docs/wiki/visuals/index.md @@ -1,5 +1,6 @@ --- title: 视觉效果 +nav_order: 16 categories: - title: 基础 color: blue diff --git a/docs/wiki/vr/index.md b/docs/wiki/vr/index.md index cac4ce94..a7b90491 100644 --- a/docs/wiki/vr/index.md +++ b/docs/wiki/vr/index.md @@ -1,5 +1,6 @@ --- title: 虚拟现实 VR +nav_order: 17 categories: - title: 基础 color: blue diff --git a/docs/wiki/world-generation/index.md b/docs/wiki/world-generation/index.md index 0d3a1fba..bc222337 100644 --- a/docs/wiki/world-generation/index.md +++ b/docs/wiki/world-generation/index.md @@ -1,5 +1,6 @@ --- title: 世界生成器 +nav_order: 18 categories: - title: 基础 color: blue diff --git a/scripts/ai-translate.mjs b/scripts/ai-translate.mjs index 2b85c800..424f8193 100644 --- a/scripts/ai-translate.mjs +++ b/scripts/ai-translate.mjs @@ -64,7 +64,7 @@ async function findMarkdownFiles(dir) { const content = await fs.readFile(fullPath, 'utf-8'); // 如果超过600行,跳过 const lines = content.split('\n').length; - if (lines > 600) { + if (lines > 6000) { console.log(`⏭️ 跳过超过600行的文件: ${path.relative(targetDir, fullPath)}`); continue; }