feat: d binding

This commit is contained in:
Alexander Medvedev 2026-09-17 09:23:24 +02:00
parent 72d1b05a20
commit 5c23b676ed
412 changed files with 40107 additions and 1456 deletions

172
bun.lock
View File

@ -8,8 +8,8 @@
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.4.2", "@types/bun": "^1.4.2",
"vitepress": "^2.0.0-alpha.19", "vitepress": "^2.0.0-alpha.20",
"vue": "^3.6.0-rc.2", "vue": "^3.6.0-rc.8",
}, },
}, },
}, },
@ -18,9 +18,9 @@
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="],
"@babel/parser": ["@babel/parser@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" }, "bin": "./bin/babel-parser.js" }, "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg=="], "@babel/parser": ["@babel/parser@7.29.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="],
"@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], "@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="],
"@docsearch/css": ["@docsearch/css@4.7.0", "", {}, "sha512-Sk5xkdRFeE7PeWjG9l4AfTwdvMfr9wHiwNNCpHXT4v4SNyNMKdHGvEILc31BgaVFGDDNbv5u/a73tofRiwbEZw=="], "@docsearch/css": ["@docsearch/css@4.7.0", "", {}, "sha512-Sk5xkdRFeE7PeWjG9l4AfTwdvMfr9wHiwNNCpHXT4v4SNyNMKdHGvEILc31BgaVFGDDNbv5u/a73tofRiwbEZw=="],
@ -28,41 +28,43 @@
"@docsearch/sidepanel-js": ["@docsearch/sidepanel-js@4.7.0", "", {}, "sha512-A8r34jCU8kcIk2viECEn2msA28ojUF1BLi/3v5OWWc5G2N3jOuuumBXoeYjfr8dA0UxgFSy5R2bt12dnFJQSyA=="], "@docsearch/sidepanel-js": ["@docsearch/sidepanel-js@4.7.0", "", {}, "sha512-A8r34jCU8kcIk2viECEn2msA28ojUF1BLi/3v5OWWc5G2N3jOuuumBXoeYjfr8dA0UxgFSy5R2bt12dnFJQSyA=="],
"@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.93", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-/XhANjfGYOuqvSR3TmUnkQkINvQ4GVjVuukvymRbxtVFBvIq/yiXJqCDycKcQPT401OYT9H2vIY6ihAlz1QIAw=="], "@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.96", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-/FmCYo/H5rIywTLV/P6OYsr0rg/31vuc8jYq0QnkOZl6m7PWIs+h5oAnSTT2cqRhOsMaKqbXcdkka6tnZ1WiUA=="],
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="],
"@oxc-project/types": ["@oxc-project/types@0.143.0", "", {}, "sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA=="], "@oxc-project/types": ["@oxc-project/types@0.150.0", "", {}, "sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw=="],
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.3", "", { "os": "android", "cpu": "arm64" }, "sha512-zrJtHDcaZJ1Fp7xf4hNl+7seH9Cn/N5TwLYkhgXREtBwAd/jaqW3uqeHxpDugJLVICWg4eW44kOQEGJ1r6jCGw=="], "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.9", "", { "os": "android", "cpu": "arm" }, "sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw=="],
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ieIiibVCp0tX7TLu2cafoNPv8wJyYi01ekXpbf8q2j7F4rGAhhXb/eQh7ge9DRBY78GwmRQtvjZDux7EDbA8kA=="], "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.9", "", { "os": "android", "cpu": "arm64" }, "sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg=="],
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Zh9tCon19eDXJoihx0rqKhMUlMYqzwj3aPsSuHmI4RWZh62dWUL+DJN4C5YQya5TcQBJU/Fe8+rY0jhXTQITqA=="], "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw=="],
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-nGbJWewA1wrXXZiQhjAT5rhibGfns5ZNkDVqxsO6zJ3f3YvpoDNNmGMSbbhLuXKjNScaBJVOAboztAWVespQMg=="], "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw=="],
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.3", "", { "os": "linux", "cpu": "arm" }, "sha512-QNniJr5Kml0kDEB98jiDOJjXNroxIIi0IXIbdYzY26Xt1pVbeP62+KnoIZLwirOymX/0jDk/2gI/bNUv7A7OIw=="], "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g=="],
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-TkqEAcmmvH3I/q4114NB4RVt6241Dao48pF45uLcFGrwAaIn0iITgTAKP/dLjbN0R4buJjGb91+UHSoFmpgIWw=="], "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.9", "", { "os": "linux", "cpu": "arm" }, "sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw=="],
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-NHqjnxpsndf4MPymxteFAWHHfkTL8HjWh1KB7z23ofZ6QO2euONuxDXjat69dKZRALnGypg8k8SsK8vZJoXv1Q=="], "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw=="],
"@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-6tbrbwfz5GB9DQ4Jwo6hy9v+vR31xZlvzZ6n5Xut6Hhx5PvrA9q/HsK8KMaYQp063iqZGXwNvZtYNLD7EM/x0w=="], "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA=="],
"@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-oyuXxXmoZHjXC917IAPFAAv4wWAa0cM9afk8nx1+9/jNNOX1uPf8yDA6p7G0RypOfw/X0PQt5IfoquY1um+zSg=="], "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw=="],
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-TytMwF2KVGqP2tgd0I1OY0PAv78dZRAYcF5ssDzjM34SUXCED3uXvSd5+lHoC0bTD6eEdFz7LdQNCO1y0oVk9w=="], "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ=="],
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-/E9m3qstrJFVPoULV25mVQblSNExY2+kBsYe4sy0Tn0yOOgJ8wZbZt3KnRbF/XeU2Gl1STKUQnDNTqhIE5MD4A=="], "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.9", "", { "os": "linux", "cpu": "x64" }, "sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q=="],
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.3", "", { "os": "none", "cpu": "arm64" }, "sha512-Kr0OcsoQI816i6HOl3vFHpd1K0eZyh76zgfj4c1nTyaTsd5r2Mj1lwM4R90y/qaCfmTn9eHy0SKwi98eitRxug=="], "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.9", "", { "os": "linux", "cpu": "x64" }, "sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ=="],
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-hOtMwTqnME+/gJcH/PCZ0wn0zPUjiWOgkHpxbSJpfGKMezHltx1S7/k1SitzVa7Ww2cqrDDaFbZEhcJZO8o+Jw=="], "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.9", "", { "os": "none", "cpu": "arm64" }, "sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg=="],
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.3", "", { "os": "win32", "cpu": "x64" }, "sha512-ekcqMMkI2PlhYnfzQnB/cEdYUVVJViWvoUyLrbzgDoi3Snfc1mVBwdnc306ufA5ejy8JSPjT2RlW1nQSjW7efg=="], "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww=="],
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.9", "", { "os": "win32", "cpu": "x64" }, "sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="],
@ -90,31 +92,31 @@
"@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="], "@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="],
"@types/markdown-it": ["@types/markdown-it@14.1.2", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog=="], "@types/markdown-it": ["@types/markdown-it@14.2.0", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-NoQ2yGlLWj4wpxMs+TYmRKk3thDrQ97agr7sFqfLsAlvoS8SNQuTrlObhFqG9iugdTtgOE9jpJ6FNM4ZGsa5xQ=="],
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
"@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="], "@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="],
"@types/node": ["@types/node@22.13.4", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg=="], "@types/node": ["@types/node@22.20.3", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-DZmzkmwHzXrLPAXPyKNDzlIwMMUZCVacoD25ywdy5YTKGbOx/2ld+Q38Im2zJ0vBuZP5Prd3VZutKZyXwkOS8A=="],
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="], "@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="],
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], "@ungap/structured-clone": ["@ungap/structured-clone@1.4.0", "", {}, "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ=="],
"@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.8", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.1" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "vue": "^3.2.25" } }, "sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew=="], "@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.9", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.1" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "vue": "^3.2.25" } }, "sha512-rD/MORlhaZMlXWW0rEn4FB4wMinWC0z/D7Ye160S5+Rs1mC8ZDAdcDp4SjKfUhG5t8q1ktcPVw4xuTkPRlzrSA=="],
"@vue/compiler-core": ["@vue/compiler-core@3.6.0-rc.2", "", { "dependencies": { "@babel/parser": "^7.29.7", "@vue/shared": "3.6.0-rc.2", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-Xx79h4EpJktQBShelXNKaRuvn9N6YsYL1j+RXdvPKzI+8tohYziBJbxOFGAkdcOKBwKc2SIWV4DOlTAMhE96yQ=="], "@vue/compiler-core": ["@vue/compiler-core@3.6.0-rc.8", "", { "dependencies": { "@babel/parser": "^7.29.8", "@vue/shared": "3.6.0-rc.8", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-Z5Q4i8woJK2RRjw6hwFhCtsLOhq5DTPM+NwT6X2Yzw9jrFGxanQLiSmhYSW8sRQn41SdtIqUK959+ZN3YEDIbg=="],
"@vue/compiler-dom": ["@vue/compiler-dom@3.6.0-rc.2", "", { "dependencies": { "@vue/compiler-core": "3.6.0-rc.2", "@vue/shared": "3.6.0-rc.2" } }, "sha512-dRTdTdi/KXzHYIkHtyjGxepTIxnsZ/hB3v1osnS8c4MeycAyzkSoZW6OZkXXN4oVVVU6NKXds1XtKAEKVVw7nA=="], "@vue/compiler-dom": ["@vue/compiler-dom@3.6.0-rc.8", "", { "dependencies": { "@vue/compiler-core": "3.6.0-rc.8", "@vue/shared": "3.6.0-rc.8" } }, "sha512-Bkajwf3oWFMFihpiWXXHQYG7iDPOS0IxFCGezVvUU80ScDzFTWtz75232IwOvswObR40wSelO6j1FTNdNeo21Q=="],
"@vue/compiler-sfc": ["@vue/compiler-sfc@3.6.0-rc.2", "", { "dependencies": { "@babel/parser": "^7.29.7", "@vue/compiler-core": "3.6.0-rc.2", "@vue/compiler-dom": "3.6.0-rc.2", "@vue/compiler-ssr": "3.6.0-rc.2", "@vue/compiler-vapor": "3.6.0-rc.2", "@vue/shared": "3.6.0-rc.2", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.19", "source-map-js": "^1.2.1" } }, "sha512-EZWTNh0UwdxvrBJkFc6+dqfwuUSdTVHDIohQcGDPCqGaYTHOfUL20b+grEAzlyxB741KrVBUb7qqpes92hAh2w=="], "@vue/compiler-sfc": ["@vue/compiler-sfc@3.6.0-rc.8", "", { "dependencies": { "@babel/parser": "^7.29.8", "@vue/compiler-core": "3.6.0-rc.8", "@vue/compiler-dom": "3.6.0-rc.8", "@vue/compiler-ssr": "3.6.0-rc.8", "@vue/compiler-vapor": "3.6.0-rc.8", "@vue/shared": "3.6.0-rc.8", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.19", "source-map-js": "^1.2.1" } }, "sha512-+db2jOxM5v1HqtVbEemHPgqoJZYtmK++OnHEeiu1ZHqvTXg6fCTf1ufQBAY2SXdOk1hh88GTqKFJyml4ye1I3Q=="],
"@vue/compiler-ssr": ["@vue/compiler-ssr@3.6.0-rc.2", "", { "dependencies": { "@vue/compiler-dom": "3.6.0-rc.2", "@vue/shared": "3.6.0-rc.2" } }, "sha512-lqHSdQTmlhKX3dNEvR1TcspUzDlTR82T7BYLDzfvTwAqGXxAI2WJfyGJPcNpPjPKYEMI9JRGF32DU8TlHLx1AA=="], "@vue/compiler-ssr": ["@vue/compiler-ssr@3.6.0-rc.8", "", { "dependencies": { "@vue/compiler-dom": "3.6.0-rc.8", "@vue/shared": "3.6.0-rc.8" } }, "sha512-IEl+wR5nH05+Vwu4VLGGtgNNgNwt2bEIXMTG8qNLMs6yU6spBLxTqvvLTUwT1dXpXC4HXGoDPG4wfTgeEPjVRw=="],
"@vue/compiler-vapor": ["@vue/compiler-vapor@3.6.0-rc.2", "", { "dependencies": { "@babel/parser": "^7.29.7", "@vue/compiler-dom": "3.6.0-rc.2", "@vue/shared": "3.6.0-rc.2", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-QbrA01pbj9xemF2McgBopyaOwj3kQGN0W1GW5EdFXORIT4fQQJpmUOj40h99S3bk09gLs5bFTRS4YE+Oyw/F9w=="], "@vue/compiler-vapor": ["@vue/compiler-vapor@3.6.0-rc.8", "", { "dependencies": { "@babel/parser": "^7.29.8", "@vue/compiler-dom": "3.6.0-rc.8", "@vue/shared": "3.6.0-rc.8", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-N2G2U/e4PAfm/B7r3+EiVMS0m43l+60kavf5NeHH7sW9wexqjJG/XNOjoQw3S+rkkoT6rCydlIlqzmupL/eqRw=="],
"@vue/devtools-api": ["@vue/devtools-api@8.2.1", "", { "dependencies": { "@vue/devtools-kit": "^8.2.1" } }, "sha512-6u4vXBlIBAC1wMplIZgpyPn7uh/s4Bf6F5bMzvLv+EdJ0aHs/+4B7Ygv864EStQSjRbsRzTko/kUG1A1IejQ3A=="], "@vue/devtools-api": ["@vue/devtools-api@8.2.1", "", { "dependencies": { "@vue/devtools-kit": "^8.2.1" } }, "sha512-6u4vXBlIBAC1wMplIZgpyPn7uh/s4Bf6F5bMzvLv+EdJ0aHs/+4B7Ygv864EStQSjRbsRzTko/kUG1A1IejQ3A=="],
@ -122,17 +124,17 @@
"@vue/devtools-shared": ["@vue/devtools-shared@8.2.1", "", {}, "sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g=="], "@vue/devtools-shared": ["@vue/devtools-shared@8.2.1", "", {}, "sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g=="],
"@vue/reactivity": ["@vue/reactivity@3.6.0-rc.2", "", { "dependencies": { "@vue/shared": "3.6.0-rc.2" } }, "sha512-B01EoSTcaVQiJwZDoSoeKYClVgj60BHN43oHEcxXhPVLdxsXI0SOiQuskUskQDZn2ma08llICKJohL60o+UamA=="], "@vue/reactivity": ["@vue/reactivity@3.6.0-rc.8", "", { "dependencies": { "@vue/shared": "3.6.0-rc.8" } }, "sha512-h5Ooef0SYigEjdB6HZx7+BdP+peVNxjpnuDiLFpRgeVltfYwNLtjRmzSMhEwMHFHOnAxJkxOSFz4qQZbp9hiCA=="],
"@vue/runtime-core": ["@vue/runtime-core@3.6.0-rc.2", "", { "dependencies": { "@vue/reactivity": "3.6.0-rc.2", "@vue/shared": "3.6.0-rc.2" } }, "sha512-qFV61Hbg6LyEGxJiVRJYuiIfryxrfO4+cgW1esxtkR1/pvemULwG6KpFImsJDwcC+YxrtvndXGM5PRVwUCGuiA=="], "@vue/runtime-core": ["@vue/runtime-core@3.6.0-rc.8", "", { "dependencies": { "@vue/reactivity": "3.6.0-rc.8", "@vue/shared": "3.6.0-rc.8" } }, "sha512-PRH45UwDCxeDgQ6XkDaVZ/91XGIAyO1cdugJTDF+ZpmdHZ6QNtY44EFzWmr7wCxc7uqp7BRrxXFSmyt7R20+bg=="],
"@vue/runtime-dom": ["@vue/runtime-dom@3.6.0-rc.2", "", { "dependencies": { "@vue/reactivity": "3.6.0-rc.2", "@vue/runtime-core": "3.6.0-rc.2", "@vue/shared": "3.6.0-rc.2", "csstype": "^3.2.3" } }, "sha512-clIE/xk0b61t30BPKoOXZep253nhWdjyw7iac53yy2KN0nxAupkb6x3ImOI9iljjXqOW5lYdNVHNxNlcx3iA1Q=="], "@vue/runtime-dom": ["@vue/runtime-dom@3.6.0-rc.8", "", { "dependencies": { "@vue/reactivity": "3.6.0-rc.8", "@vue/runtime-core": "3.6.0-rc.8", "@vue/shared": "3.6.0-rc.8", "csstype": "^3.2.3" } }, "sha512-gf4sGrMq2nGvj+NPtBKu3fZt8HbnjaLcUbj7l6GOUKSWACr4CeU9iXlFCT3ncu3e/xecj8dUIpKPGSiwNLvLMw=="],
"@vue/runtime-vapor": ["@vue/runtime-vapor@3.6.0-rc.2", "", { "dependencies": { "@vue/reactivity": "3.6.0-rc.2", "@vue/shared": "3.6.0-rc.2" }, "peerDependencies": { "@vue/runtime-dom": "3.6.0-rc.2" } }, "sha512-8EpxbNyT629k/52el4D7PxXmZtiYhJRBHPXJR7CZw0OluiADtT9W8J+XB83EVlzHmFUysXcd+mGWmuHwIhuHZA=="], "@vue/runtime-vapor": ["@vue/runtime-vapor@3.6.0-rc.8", "", { "dependencies": { "@vue/reactivity": "3.6.0-rc.8", "@vue/shared": "3.6.0-rc.8" }, "peerDependencies": { "@vue/runtime-dom": "3.6.0-rc.8" } }, "sha512-GUXwL3J9O8l639N/vI949CZTglBRJvJKdsCgs2snGMdrVTVgt//tzlgWtZwxSM4BRPPTlZHrFqSWd1thrfUb0w=="],
"@vue/server-renderer": ["@vue/server-renderer@3.6.0-rc.2", "", { "dependencies": { "@vue/compiler-ssr": "3.6.0-rc.2", "@vue/runtime-dom": "3.6.0-rc.2", "@vue/shared": "3.6.0-rc.2" } }, "sha512-TIsqoYljs6b0wfoCDhv4EeU3Du2a8gTadkaTGMjIYLTLlO4p8r4VdDqfNp/ZMAm87bW4ST1naBMRe+bXQBpAeQ=="], "@vue/server-renderer": ["@vue/server-renderer@3.6.0-rc.8", "", { "dependencies": { "@vue/compiler-ssr": "3.6.0-rc.8", "@vue/runtime-dom": "3.6.0-rc.8", "@vue/shared": "3.6.0-rc.8" } }, "sha512-aEJABwHk5cpGgeaq4vt8oIfIWlAq0S9Ly/zWu9ii3sjE+zbjQ28cAeeK4GxVSQhUL0tidhzeQReOcNJ/BCmWpQ=="],
"@vue/shared": ["@vue/shared@3.5.41", "", {}, "sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA=="], "@vue/shared": ["@vue/shared@3.5.42", "", {}, "sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g=="],
"@vueuse/core": ["@vueuse/core@14.4.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "14.4.0", "@vueuse/shared": "14.4.0" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ=="], "@vueuse/core": ["@vueuse/core@14.4.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "14.4.0", "@vueuse/shared": "14.4.0" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ=="],
@ -208,7 +210,7 @@
"mark.js": ["mark.js@8.11.1", "", {}, "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ=="], "mark.js": ["mark.js@8.11.1", "", {}, "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ=="],
"mdast-util-to-hast": ["mdast-util-to-hast@13.2.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA=="], "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="],
"micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="],
@ -218,11 +220,11 @@
"micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="],
"micromark-util-types": ["micromark-util-types@2.0.1", "", {}, "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ=="], "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
"minisearch": ["minisearch@7.2.0", "", {}, "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg=="], "minisearch": ["minisearch@7.2.0", "", {}, "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg=="],
"nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="], "nanoid": ["nanoid@3.3.19", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug=="],
"oniguruma-parser": ["oniguruma-parser@0.12.2", "", {}, "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="], "oniguruma-parser": ["oniguruma-parser@0.12.2", "", {}, "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="],
@ -230,15 +232,15 @@
"or": ["or@0.2.0", "", {}, "sha512-BHB8VZq2isxkyRaCBZ6CZCbQBzCT+gy8LPiqdbMH1+Fd6biFj3v8ebjeYzzL51PbsApsPYnGegGTO6KLQMxxDw=="], "or": ["or@0.2.0", "", {}, "sha512-BHB8VZq2isxkyRaCBZ6CZCbQBzCT+gy8LPiqdbMH1+Fd6biFj3v8ebjeYzzL51PbsApsPYnGegGTO6KLQMxxDw=="],
"perfect-debounce": ["perfect-debounce@2.0.0", "", {}, "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow=="], "perfect-debounce": ["perfect-debounce@2.1.0", "", {}, "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="], "picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="],
"postcss": ["postcss@8.5.26", "", { "dependencies": { "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ=="], "postcss": ["postcss@8.5.28", "", { "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A=="],
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], "property-information": ["property-information@7.2.0", "", {}, "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg=="],
"regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="],
@ -246,7 +248,7 @@
"regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="],
"rolldown": ["rolldown@1.2.3", "", { "dependencies": { "@oxc-project/types": "=0.143.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.2.3", "@rolldown/binding-darwin-arm64": "1.2.3", "@rolldown/binding-darwin-x64": "1.2.3", "@rolldown/binding-freebsd-x64": "1.2.3", "@rolldown/binding-linux-arm-gnueabihf": "1.2.3", "@rolldown/binding-linux-arm64-gnu": "1.2.3", "@rolldown/binding-linux-arm64-musl": "1.2.3", "@rolldown/binding-linux-ppc64-gnu": "1.2.3", "@rolldown/binding-linux-s390x-gnu": "1.2.3", "@rolldown/binding-linux-x64-gnu": "1.2.3", "@rolldown/binding-linux-x64-musl": "1.2.3", "@rolldown/binding-openharmony-arm64": "1.2.3", "@rolldown/binding-win32-arm64-msvc": "1.2.3", "@rolldown/binding-win32-x64-msvc": "1.2.3" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-rn9wpmxplLf7NLNyCk9FyWh3FM43DbY8jOzCdEPzH7uflhTftRbCEpqi6Ly2osgoU8OwObtmavMbWLaWy4LX7A=="], "rolldown": ["rolldown@1.2.9", "", { "dependencies": { "@oxc-project/types": "=0.150.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.9", "@rolldown/binding-android-arm64": "1.2.9", "@rolldown/binding-darwin-arm64": "1.2.9", "@rolldown/binding-darwin-x64": "1.2.9", "@rolldown/binding-freebsd-x64": "1.2.9", "@rolldown/binding-linux-arm-gnueabihf": "1.2.9", "@rolldown/binding-linux-arm64-gnu": "1.2.9", "@rolldown/binding-linux-arm64-musl": "1.2.9", "@rolldown/binding-linux-ppc64-gnu": "1.2.9", "@rolldown/binding-linux-s390x-gnu": "1.2.9", "@rolldown/binding-linux-x64-gnu": "1.2.9", "@rolldown/binding-linux-x64-musl": "1.2.9", "@rolldown/binding-openharmony-arm64": "1.2.9", "@rolldown/binding-win32-arm64-msvc": "1.2.9", "@rolldown/binding-win32-x64-msvc": "1.2.9" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg=="],
"shiki": ["shiki@4.4.3", "", { "dependencies": { "@shikijs/core": "4.4.3", "@shikijs/engine-javascript": "4.4.3", "@shikijs/engine-oniguruma": "4.4.3", "@shikijs/langs": "4.4.3", "@shikijs/themes": "4.4.3", "@shikijs/types": "4.4.3", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.5" } }, "sha512-Mb/GvXPHBAXdgGIcnfU5L3ldpn1XcxrGkPHwqgRx17/I2XRfqlFKk2vGkHWINn1kdXvzJZeuO3is6I9KLPFm0g=="], "shiki": ["shiki@4.4.3", "", { "dependencies": { "@shikijs/core": "4.4.3", "@shikijs/engine-javascript": "4.4.3", "@shikijs/engine-oniguruma": "4.4.3", "@shikijs/langs": "4.4.3", "@shikijs/themes": "4.4.3", "@shikijs/types": "4.4.3", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.5" } }, "sha512-Mb/GvXPHBAXdgGIcnfU5L3ldpn1XcxrGkPHwqgRx17/I2XRfqlFKk2vGkHWINn1kdXvzJZeuO3is6I9KLPFm0g=="],
@ -262,94 +264,72 @@
"trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="], "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="],
"unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="],
"unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
"unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="], "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="],
"unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="], "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
"vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="], "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
"vite": ["vite@8.2.1", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", "postcss": "^8.5.25", "rolldown": "~1.2.1", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.4.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw=="], "vite": ["vite@8.3.0", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", "postcss": "^8.5.28", "rolldown": "~1.2.6", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ=="],
"vitepress": ["vitepress@2.0.0-alpha.19", "", { "dependencies": { "@docsearch/css": "^4.7.0", "@docsearch/js": "^4.7.0", "@docsearch/sidepanel-js": "^4.7.0", "@iconify-json/simple-icons": "^1.2.92", "@shikijs/core": "^4.4.1", "@shikijs/transformers": "^4.4.1", "@shikijs/types": "^4.4.1", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^6.0.8", "@vue/devtools-api": "^8.2.1", "@vue/shared": "^3.5.40", "@vueuse/core": "^14.4.0", "@vueuse/integrations": "^14.4.0", "focus-trap": "^8.2.2", "mark.js": "8.11.1", "minisearch": "^7.2.0", "shiki": "^4.4.1", "vite": "^8.2.0", "vue": "^3.5.40" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3", "postcss"], "bin": { "vitepress": "bin/vitepress.js" } }, "sha512-WnBsb0Bwr43kXKyiis+lld/7ri3hnMbthS8N3hpFtjjwsdLO4IRmiAE08D7aud4q6oMDf9uwRowxzNqRFe/amw=="], "vitepress": ["vitepress@2.0.0-alpha.20", "", { "dependencies": { "@docsearch/css": "^4.7.0", "@docsearch/js": "^4.7.0", "@docsearch/sidepanel-js": "^4.7.0", "@iconify-json/simple-icons": "^1.2.93", "@shikijs/transformers": "^4.4.3", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^6.0.8", "@vue/devtools-api": "^8.2.1", "@vue/shared": "^3.5.41", "@vueuse/core": "^14.4.0", "@vueuse/integrations": "^14.4.0", "focus-trap": "^8.2.2", "mark.js": "8.11.1", "minisearch": "^7.2.0", "shiki": "^4.4.3", "vite": "^8.2.1", "vue": "^3.5.41" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3", "postcss"], "bin": { "vitepress": "bin/vitepress.js" } }, "sha512-uQWKmP9PaBkf9zxHn0iOml/ZPPDaGKqQXVMBHz3yjwyyd9Eg+BKLGxbqmOGlfOMCt6Fj8TLiAnE59qlKZ0A3xw=="],
"vue": ["vue@3.6.0-rc.2", "", { "dependencies": { "@vue/compiler-dom": "3.6.0-rc.2", "@vue/compiler-sfc": "3.6.0-rc.2", "@vue/runtime-dom": "3.6.0-rc.2", "@vue/runtime-vapor": "3.6.0-rc.2", "@vue/server-renderer": "3.6.0-rc.2", "@vue/shared": "3.6.0-rc.2" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-pBgoISqETcufJ1e92vVW2/D5MEbCm2XHlC/5dq3hWq8s17tx9v5BEdYv4hojJ0yEEDidYxUL7itS+vV32wfZrw=="], "vue": ["vue@3.6.0-rc.8", "", { "dependencies": { "@vue/compiler-dom": "3.6.0-rc.8", "@vue/compiler-sfc": "3.6.0-rc.8", "@vue/runtime-dom": "3.6.0-rc.8", "@vue/runtime-vapor": "3.6.0-rc.8", "@vue/server-renderer": "3.6.0-rc.8", "@vue/shared": "3.6.0-rc.8" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-9TU0oX/NWj9L4BHWKHXCeyMKmHqQoDLw+olIuqk07tryw0a8sCpmZrEmLps2vBiuRNknskDwcOupooe9J5P3aQ=="],
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
"@vue/compiler-core/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "@vue/compiler-core/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/compiler-dom/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "@vue/compiler-dom/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/compiler-sfc/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "@vue/compiler-sfc/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/compiler-sfc/postcss": ["postcss@8.5.22", "", { "dependencies": { "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ=="], "@vue/compiler-ssr/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/compiler-ssr/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "@vue/compiler-vapor/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/compiler-vapor/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "@vue/reactivity/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/reactivity/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "@vue/runtime-core/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/runtime-core/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "@vue/runtime-dom/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/runtime-dom/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "@vue/runtime-vapor/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/runtime-vapor/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "@vue/server-renderer/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"@vue/server-renderer/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "vitepress/vue": ["vue@3.5.42", "", { "dependencies": { "@vue/compiler-dom": "3.5.42", "@vue/compiler-sfc": "3.5.42", "@vue/runtime-dom": "3.5.42", "@vue/server-renderer": "3.5.42", "@vue/shared": "3.5.42" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA=="],
"hast-util-to-html/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], "vue/@vue/shared": ["@vue/shared@3.6.0-rc.8", "", {}, "sha512-Un8Dd+UDUO8otYoHQFZzY9ySuH4Nk6SqEFbo3lWkZrQULIAEiMTp8JK7NgK/K5/QUQS2PvKC56jQTmaQ6CQcTA=="],
"hast-util-whitespace/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], "vitepress/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.42", "", { "dependencies": { "@vue/compiler-core": "3.5.42", "@vue/shared": "3.5.42" } }, "sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA=="],
"mdast-util-to-hast/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], "vitepress/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.42", "", { "dependencies": { "@babel/parser": "^7.29.8", "@vue/compiler-core": "3.5.42", "@vue/compiler-dom": "3.5.42", "@vue/compiler-ssr": "3.5.42", "@vue/shared": "3.5.42", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.19", "source-map-js": "^1.2.1" } }, "sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw=="],
"vitepress/vue": ["vue@3.5.41", "", { "dependencies": { "@vue/compiler-dom": "3.5.41", "@vue/compiler-sfc": "3.5.41", "@vue/runtime-dom": "3.5.41", "@vue/server-renderer": "3.5.41", "@vue/shared": "3.5.41" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-2laE0p+aK+/AOPG/XL/WepOs/GlK755LJ1XECi9kDUrz1FKNw8rb2Xzlw9JS1rqEV55nb0ttsKxVlTCcd+R5cg=="], "vitepress/vue/@vue/runtime-dom": ["@vue/runtime-dom@3.5.42", "", { "dependencies": { "@vue/reactivity": "3.5.42", "@vue/runtime-core": "3.5.42", "@vue/shared": "3.5.42", "csstype": "^3.2.3" } }, "sha512-rsCmhiWLaRxGltLwhlCWyYkFn7WAbKRh0q17eZ1A6Dq6eqc2ACQ61IIryxz0LrsvCzHSilLA9JHovVwM8CNE2g=="],
"vue/@vue/shared": ["@vue/shared@3.6.0-rc.2", "", {}, "sha512-Tz44lKLjxhWRu3GJ38768dc2hW4XhDtTB5aUo5fCMis6YDyFzwQYkrD/B9SuQ1v/ailv6UVR3wSHiujNXSjMCQ=="], "vitepress/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.42", "", { "dependencies": { "@vue/compiler-ssr": "3.5.42", "@vue/runtime-dom": "3.5.42", "@vue/shared": "3.5.42" } }, "sha512-2++5dUyYS4gvo7xQXSECUDhB7TS0aOl5SeVfC5qSq1Jgfhjvegw1zqhwTIR3imZ+QYPJQw9gfcFvXGAjGZ7ajQ=="],
"@vue/compiler-sfc/postcss/nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="], "vitepress/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.42", "", { "dependencies": { "@babel/parser": "^7.29.8", "@vue/shared": "3.5.42", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ=="],
"vitepress/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.41", "", { "dependencies": { "@vue/compiler-core": "3.5.41", "@vue/shared": "3.5.41" } }, "sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw=="], "vitepress/vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.42", "", { "dependencies": { "@babel/parser": "^7.29.8", "@vue/shared": "3.5.42", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ=="],
"vitepress/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.41", "", { "dependencies": { "@babel/parser": "^7.29.8", "@vue/compiler-core": "3.5.41", "@vue/compiler-dom": "3.5.41", "@vue/compiler-ssr": "3.5.41", "@vue/shared": "3.5.41", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.19", "source-map-js": "^1.2.1" } }, "sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ=="], "vitepress/vue/@vue/compiler-sfc/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.42", "", { "dependencies": { "@vue/compiler-dom": "3.5.42", "@vue/shared": "3.5.42" } }, "sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA=="],
"vitepress/vue/@vue/runtime-dom": ["@vue/runtime-dom@3.5.41", "", { "dependencies": { "@vue/reactivity": "3.5.41", "@vue/runtime-core": "3.5.41", "@vue/shared": "3.5.41", "csstype": "^3.2.3" } }, "sha512-3vVBahVBS9+U6cmXBLyb8nE6/yYo4J/CGI9eVFs3KiMc0YHuudwKyShTD65jtJy/L9PUUxNAFu4cj4LiJ0UFbw=="], "vitepress/vue/@vue/runtime-dom/@vue/reactivity": ["@vue/reactivity@3.5.42", "", { "dependencies": { "@vue/shared": "3.5.42" } }, "sha512-TzNNfKpb7hDxbQltwAut8VDQA5YP+BuRlxntHUuRjyKwlMvmAPbs3unhCvieijifY6vFfVBwsS7wG/C7uq+bEQ=="],
"vitepress/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.41", "", { "dependencies": { "@vue/compiler-ssr": "3.5.41", "@vue/runtime-dom": "3.5.41", "@vue/shared": "3.5.41" } }, "sha512-n6hx/pNFfbD6SuyeuMVkvqox8bwf/ET9JlA/kAz/imw8sw++wkqKe2mHX5KutjPpbKE4Z56yTHszoOjGMI9igQ=="], "vitepress/vue/@vue/runtime-dom/@vue/runtime-core": ["@vue/runtime-core@3.5.42", "", { "dependencies": { "@vue/reactivity": "3.5.42", "@vue/shared": "3.5.42" } }, "sha512-9uACtuHs7vJGkm5Bp3xu4xRDLFTIYy5DgxpToVjqGIAhAEKwQfsaLvKINhM6nFVp6bZPRFGdDqd1g52MqKsotA=="],
"vitepress/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.41", "", { "dependencies": { "@babel/parser": "^7.29.8", "@vue/shared": "3.5.41", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg=="], "vitepress/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.42", "", { "dependencies": { "@vue/compiler-dom": "3.5.42", "@vue/shared": "3.5.42" } }, "sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA=="],
"vitepress/vue/@vue/compiler-sfc/@babel/parser": ["@babel/parser@7.29.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="],
"vitepress/vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.41", "", { "dependencies": { "@babel/parser": "^7.29.8", "@vue/shared": "3.5.41", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg=="],
"vitepress/vue/@vue/compiler-sfc/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.41", "", { "dependencies": { "@vue/compiler-dom": "3.5.41", "@vue/shared": "3.5.41" } }, "sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A=="],
"vitepress/vue/@vue/compiler-sfc/postcss": ["postcss@8.5.22", "", { "dependencies": { "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ=="],
"vitepress/vue/@vue/runtime-dom/@vue/reactivity": ["@vue/reactivity@3.5.41", "", { "dependencies": { "@vue/shared": "3.5.41" } }, "sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA=="],
"vitepress/vue/@vue/runtime-dom/@vue/runtime-core": ["@vue/runtime-core@3.5.41", "", { "dependencies": { "@vue/reactivity": "3.5.41", "@vue/shared": "3.5.41" } }, "sha512-Vcry58hiAKwGen9Z1jUZE0feFsNArPCMOImYI8el48A9Idf6DuQYD0U05zZIF2Iad1hGhPSvcbBbAOhNr55fhg=="],
"vitepress/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.41", "", { "dependencies": { "@vue/compiler-dom": "3.5.41", "@vue/shared": "3.5.41" } }, "sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A=="],
"vitepress/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser": ["@babel/parser@7.29.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="],
"vitepress/vue/@vue/compiler-sfc/@babel/parser/@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="],
"vitepress/vue/@vue/compiler-sfc/postcss/nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="],
"vitepress/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="],
} }
} }

View File

@ -5,13 +5,25 @@ export const de = defineConfig({
description: "Hochperformante Minecraft-Server-Software in Rust", description: "Hochperformante Minecraft-Server-Software in Rust",
themeConfig: { themeConfig: {
// https://vitepress.dev/reference/default-theme-config siteTitle: "Pumpkin Docs",
search: { search: {
provider: "local", provider: "local",
}, },
nav: [ nav: [
{ {
text: "Startseite", text: "Administration",
link: "/de/admin/introduction",
},
{
text: "Mitwirkende",
link: "/de/developer/introduction",
},
{
text: "Plugins",
link: "/de/plugin-dev/introduction",
},
{
text: "Webseite",
link: "https://pumpkinmc.org/", link: "https://pumpkinmc.org/",
}, },
], ],
@ -23,34 +35,124 @@ export const de = defineConfig({
], ],
}, },
{ {
text: "Konfiguration", text: "Administration",
collapsed: false,
items: [ items: [
{ text: "Einführung", link: "/de/config/introduction" }, { text: "Übersicht", link: "/de/admin/introduction" },
{ text: "Grundkonfiguration", link: "/de/config/basic" }, { text: "Migration von Bukkit", link: "/de/admin/migrating-from-bukkit" },
{ text: "Proxy", link: "/de/config/proxy" }, {
{ text: "Authentifizierung", link: "/de/config/authentication" }, text: "Konfiguration",
{ text: "Kompression", link: "/de/config/compression" }, collapsed: true,
{ text: "Ressourcenpaket", link: "/de/config/resource-pack" }, items: [
{ text: "Befehle", link: "/de/config/commands" }, { text: "Einführung", link: "/de/config/introduction" },
{ text: "RCON", link: "/de/config/rcon" }, { text: "Grundkonfiguration", link: "/de/config/basic" },
{ text: "PVP", link: "/de/config/pvp" }, { text: "Welt", link: "/de/config/world" },
{ text: "Logging", link: "/de/config/logging" }, { text: "Chat & Anti-Spam", link: "/de/config/chat" },
{ text: "Query", link: "/de/config/query" }, { text: "Befehle", link: "/de/config/commands" },
{ text: "LAN-Broadcast", link: "/de/config/lan-broadcast" }, { text: "Bedrock & NetherNet", link: "/de/config/bedrock" },
{ text: "Proxy", link: "/de/config/proxy" },
{ text: "Authentifizierung", link: "/de/config/authentication" },
{ text: "Paket-Begrenzer", link: "/de/config/packet-limiter" },
{ text: "Kompression", link: "/de/config/compression" },
{ text: "Ressourcenpaket", link: "/de/config/resource-pack" },
{ text: "Plugins", link: "/de/config/plugins" },
{ text: "Server-Links", link: "/de/config/server-links" },
{ text: "Spielerdaten", link: "/de/config/player-data" },
{ text: "Logging", link: "/de/config/logging" },
{ text: "Query", link: "/de/config/query" },
{ text: "RCON", link: "/de/config/rcon" },
{ text: "PVP", link: "/de/config/pvp" },
{ text: "LAN-Broadcast", link: "/de/config/lan-broadcast" },
],
},
], ],
}, },
{ {
text: "Entwickler", text: "Mitwirkende",
items: [ items: [
{ text: "Beitragen", link: "/de/developer/contributing" },
{ text: "Einführung", link: "/de/developer/introduction" }, { text: "Einführung", link: "/de/developer/introduction" },
{ text: "Beitragsleitfaden", link: "/de/developer/contributing" },
{ text: "Architektur", link: "/de/developer/architecture" },
{ text: "Daten-Extraktor", link: "/de/developer/extractor" },
{ text: "Code-Generierung", link: "/de/developer/codegen" },
{ text: "Versionen portieren", link: "/de/developer/porting-versions" },
{ {
text: "Netzwerk", text: "Netzwerk",
link: "/de/developer/networking/networking", collapsed: true,
items: [ items: [
{ {
text: "Authentifizierung", text: "Einführung",
link: "/de/developer/networking/authentication", link: "/de/developer/networking/",
},
{
text: "Metadaten & Synchronisierte Daten",
link: "/de/developer/networking/metadata",
},
{
text: "Java Edition",
collapsed: true,
items: [
{
text: "Übersicht",
link: "/de/developer/networking/java/overview",
},
{
text: "Paket hinzufügen",
link: "/de/developer/networking/java/adding-packets",
},
{
text: "Authentifizierung",
link: "/de/developer/networking/java/authentication",
},
],
},
{
text: "Bedrock Edition",
collapsed: true,
items: [
{
text: "Übersicht",
link: "/de/developer/networking/bedrock/overview",
},
{
text: "Paket hinzufügen",
link: "/de/developer/networking/bedrock/adding-packets",
},
{
text: "Authentifizierung",
link: "/de/developer/networking/bedrock/authentication",
},
{
text: "NetherNet",
link: "/de/developer/networking/bedrock/nethernet",
},
],
},
{
text: "Proxy-Weiterleitung",
collapsed: true,
items: [
{
text: "Übersicht",
link: "/de/developer/networking/proxy/",
},
{
text: "BungeeCord",
link: "/de/developer/networking/proxy/bungeecord",
},
{
text: "Velocity",
link: "/de/developer/networking/proxy/velocity",
},
{
text: "Vine",
link: "/de/developer/networking/proxy/vine",
},
],
},
{
text: "Query (GameSpy4)",
link: "/de/developer/networking/query",
}, },
{ {
text: "RCON", text: "RCON",
@ -58,7 +160,51 @@ export const de = defineConfig({
}, },
], ],
}, },
{ text: "Welt", link: "/de/developer/world" }, {
text: "Blöcke",
collapsed: true,
items: [
{ text: "Übersicht", link: "/de/developer/blocks/" },
{ text: "Block hinzufügen", link: "/de/developer/blocks/adding-blocks" },
],
},
{
text: "Gegenstände",
collapsed: true,
items: [
{ text: "Übersicht", link: "/de/developer/items/" },
{ text: "Gegenstand hinzufügen", link: "/de/developer/items/adding-items" },
],
},
{
text: "Entities",
collapsed: true,
items: [
{ text: "Übersicht & Hierarchie", link: "/de/developer/entities/" },
{ text: "Spawning & Tracking", link: "/de/developer/entities/spawning-and-tracking" },
{ text: "Mob-KI & Ziele", link: "/de/developer/entities/ai-and-mobs" },
],
},
{
text: "Befehle",
collapsed: true,
items: [
{ text: "Übersicht & Dispatcher", link: "/de/developer/commands/" },
{ text: "Befehl hinzufügen", link: "/de/developer/commands/adding-commands" },
{ text: "Argumente & Vorschläge", link: "/de/developer/commands/arguments-and-suggestions" },
{ text: "Ausführung & Kontext", link: "/de/developer/commands/execution-and-context" },
],
},
{
text: "Plugin-Engine",
collapsed: true,
items: [
{ text: "Übersicht", link: "/de/developer/plugins/" },
{ text: "Plugin-Loader hinzufügen", link: "/de/developer/plugins/loaders" },
{ text: "WASM-Signierung & Verifizierung", link: "/de/developer/plugins/wasm-signing" },
],
},
{ text: "Welt-Engine", link: "/de/developer/world" },
{ text: "Mobile Entwicklung", link: "/de/developer/mobile" }, { text: "Mobile Entwicklung", link: "/de/developer/mobile" },
], ],
}, },
@ -69,9 +215,35 @@ export const de = defineConfig({
text: "Einführung", text: "Einführung",
link: "/de/plugin-dev/introduction", link: "/de/plugin-dev/introduction",
}, },
{
text: "Migration von Bukkit",
collapsed: true,
items: [
{
text: "Übersicht",
link: "/de/plugin-dev/migrating-from-bukkit/",
},
{
text: "Befehle",
link: "/de/plugin-dev/migrating-from-bukkit/commands",
},
{
text: "Events",
link: "/de/plugin-dev/migrating-from-bukkit/events",
},
{
text: "Inventare & GUIs",
link: "/de/plugin-dev/migrating-from-bukkit/inventories",
},
{
text: "Konfiguration & Daten",
link: "/de/plugin-dev/migrating-from-bukkit/configuration",
},
],
},
{ {
text: "Rust", text: "Rust",
link: "/de/plugin-dev/rust/introduction", collapsed: true,
items: [ items: [
{ {
text: "Projekt erstellen", text: "Projekt erstellen",
@ -82,36 +254,44 @@ export const de = defineConfig({
link: "/de/plugin-dev/rust/basic-logic", link: "/de/plugin-dev/rust/basic-logic",
}, },
{ {
text: "Join-Event", text: "Events",
link: "/de/plugin-dev/rust/join-event", link: "/de/plugin-dev/rust/events",
}, },
{ {
text: "Befehle", text: "Befehle",
items: [ items: [
{
text: "Erster Befehl",
link: "/de/plugin-dev/rust/command/first-command",
},
{ {
text: "Schere-Stein-Papier", text: "Schere-Stein-Papier",
link: "/de/plugin-dev/rust/command/rock-paper-scissors", link: "/de/plugin-dev/rust/command/rock-paper-scissors",
}, },
{
text: "Inventare",
link: "/de/plugin-dev/rust/command/inventories",
},
], ],
}, },
{
text: "Lizenzierung & Updates",
link: "/de/plugin-dev/rust/plugin-utils",
},
], ],
}, },
{ {
text: "Python", text: "Python",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Quick Start", text: "Schnellstart",
link: "/de/plugin-dev/python/quick-start", link: "/de/plugin-dev/python/quick-start",
}, },
{ {
text: "Basic Logic", text: "Grundlogik",
link: "/de/plugin-dev/python/basic-logic", link: "/de/plugin-dev/python/basic-logic",
}, },
{
text: "Erster Befehl",
link: "/de/plugin-dev/python/first-command",
},
{ {
text: "Events", text: "Events",
link: "/de/plugin-dev/python/events", link: "/de/plugin-dev/python/events",
@ -120,22 +300,72 @@ export const de = defineConfig({
}, },
{ {
text: "C#", text: "C#",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Quick Start", text: "Schnellstart",
link: "/de/plugin-dev/csharp/quick-start", link: "/de/plugin-dev/csharp/quick-start",
}, },
{
text: "Erster Befehl",
link: "/de/plugin-dev/csharp/first-command",
},
], ],
}, },
{ {
text: "C", text: "C",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Schnellstart", text: "Schnellstart",
link: "/de/plugin-dev/c/quick-start", link: "/de/plugin-dev/c/quick-start",
}, },
{
text: "Erster Befehl",
link: "/de/plugin-dev/c/first-command",
},
],
},
{
text: "Go",
collapsed: true,
items: [
{
text: "Schnellstart",
link: "/de/plugin-dev/go/quick-start",
},
{
text: "Grundlogik",
link: "/de/plugin-dev/go/basic-logic",
},
{
text: "Erster Befehl",
link: "/de/plugin-dev/go/first-command",
},
],
},
{
text: "Kotlin",
collapsed: true,
items: [
{
text: "Schnellstart",
link: "/de/plugin-dev/kotlin/quick-start",
},
{
text: "Erster Befehl",
link: "/de/plugin-dev/kotlin/first-command",
},
],
},
{
text: "D",
collapsed: true,
items: [
{
text: "Schnellstart",
link: "/de/plugin-dev/d/quick-start",
},
], ],
}, },
], ],
@ -145,7 +375,7 @@ export const de = defineConfig({
items: [ items: [
{ {
text: "Häufige Probleme", text: "Häufige Probleme",
link: "/de/troubleshooting/common_issues.md", link: "/de/troubleshooting/common_issues",
}, },
], ],
}, },

View File

@ -359,6 +359,16 @@ export const en = defineConfig({
}, },
], ],
}, },
{
text: "D",
collapsed: true,
items: [
{
text: "Quick Start",
link: "/plugin-dev/d/quick-start",
},
],
},
], ],
}, },
{ {

View File

@ -5,13 +5,25 @@ export const jaJP = defineConfig({
description: "Rust で書かれた高性能 Minecraft サーバーソフトウェア", description: "Rust で書かれた高性能 Minecraft サーバーソフトウェア",
themeConfig: { themeConfig: {
// https://vitepress.dev/reference/default-theme-config siteTitle: "Pumpkin Docs",
search: { search: {
provider: "local", provider: "local",
}, },
nav: [ nav: [
{ {
text: "ホーム", text: "管理",
link: "/ja_jp/admin/introduction",
},
{
text: "開発者・貢献者",
link: "/ja_jp/developer/introduction",
},
{
text: "プラグイン",
link: "/ja_jp/plugin-dev/introduction",
},
{
text: "ウェブサイト",
link: "https://pumpkinmc.org/", link: "https://pumpkinmc.org/",
}, },
], ],
@ -23,34 +35,124 @@ export const jaJP = defineConfig({
], ],
}, },
{ {
text: "設定", text: "管理",
collapsed: false,
items: [ items: [
{ text: "はじめに", link: "/ja_jp/config/introduction" }, { text: "概要", link: "/ja_jp/admin/introduction" },
{ text: "基本設定", link: "/ja_jp/config/basic" }, { text: "Bukkit からの移行", link: "/ja_jp/admin/migrating-from-bukkit" },
{ text: "プロキシ", link: "/ja_jp/config/proxy" }, {
{ text: "認証", link: "/ja_jp/config/authentication" }, text: "設定",
{ text: "圧縮", link: "/ja_jp/config/compression" }, collapsed: true,
{ text: "リソースパック", link: "/ja_jp/config/resource-pack" }, items: [
{ text: "コマンド", link: "/ja_jp/config/commands" }, { text: "はじめに", link: "/ja_jp/config/introduction" },
{ text: "RCON", link: "/ja_jp/config/rcon" }, { text: "基本設定", link: "/ja_jp/config/basic" },
{ text: "PVP", link: "/ja_jp/config/pvp" }, { text: "ワールド", link: "/ja_jp/config/world" },
{ text: "ロギング", link: "/ja_jp/config/logging" }, { text: "チャット・スパム防止", link: "/ja_jp/config/chat" },
{ text: "Query", link: "/ja_jp/config/query" }, { text: "コマンド", link: "/ja_jp/config/commands" },
{ text: "LAN ブロードキャスト", link: "/ja_jp/config/lan-broadcast" }, { text: "Bedrock & NetherNet", link: "/ja_jp/config/bedrock" },
{ text: "プロキシ", link: "/ja_jp/config/proxy" },
{ text: "認証", link: "/ja_jp/config/authentication" },
{ text: "パケットリミッター", link: "/ja_jp/config/packet-limiter" },
{ text: "圧縮", link: "/ja_jp/config/compression" },
{ text: "リソースパック", link: "/ja_jp/config/resource-pack" },
{ text: "プラグイン", link: "/ja_jp/config/plugins" },
{ text: "サーバーリンク", link: "/ja_jp/config/server-links" },
{ text: "プレイヤーデータ", link: "/ja_jp/config/player-data" },
{ text: "ロギング", link: "/ja_jp/config/logging" },
{ text: "Query", link: "/ja_jp/config/query" },
{ text: "RCON", link: "/ja_jp/config/rcon" },
{ text: "PVP", link: "/ja_jp/config/pvp" },
{ text: "LAN ブロードキャスト", link: "/ja_jp/config/lan-broadcast" },
],
},
], ],
}, },
{ {
text: "開発者", text: "開発者",
items: [ items: [
{ text: "貢献ガイド", link: "/ja_jp/developer/contributing" },
{ text: "はじめに", link: "/ja_jp/developer/introduction" }, { text: "はじめに", link: "/ja_jp/developer/introduction" },
{ text: "貢献ガイド", link: "/ja_jp/developer/contributing" },
{ text: "アーキテクチャ", link: "/ja_jp/developer/architecture" },
{ text: "データ抽出ツール", link: "/ja_jp/developer/extractor" },
{ text: "コード生成", link: "/ja_jp/developer/codegen" },
{ text: "バージョン移行", link: "/ja_jp/developer/porting-versions" },
{ {
text: "ネットワーキング", text: "ネットワーキング",
link: "/ja_jp/developer/networking/networking", collapsed: true,
items: [ items: [
{ {
text: "認証", text: "はじめに",
link: "/ja_jp/developer/networking/authentication", link: "/ja_jp/developer/networking/",
},
{
text: "メタデータと同期データ",
link: "/ja_jp/developer/networking/metadata",
},
{
text: "Java Edition",
collapsed: true,
items: [
{
text: "概要",
link: "/ja_jp/developer/networking/java/overview",
},
{
text: "パケットの追加",
link: "/ja_jp/developer/networking/java/adding-packets",
},
{
text: "認証",
link: "/ja_jp/developer/networking/java/authentication",
},
],
},
{
text: "Bedrock Edition",
collapsed: true,
items: [
{
text: "概要",
link: "/ja_jp/developer/networking/bedrock/overview",
},
{
text: "パケットの追加",
link: "/ja_jp/developer/networking/bedrock/adding-packets",
},
{
text: "認証",
link: "/ja_jp/developer/networking/bedrock/authentication",
},
{
text: "NetherNet",
link: "/ja_jp/developer/networking/bedrock/nethernet",
},
],
},
{
text: "プロキシ転送",
collapsed: true,
items: [
{
text: "概要",
link: "/ja_jp/developer/networking/proxy/",
},
{
text: "BungeeCord",
link: "/ja_jp/developer/networking/proxy/bungeecord",
},
{
text: "Velocity",
link: "/ja_jp/developer/networking/proxy/velocity",
},
{
text: "Vine",
link: "/ja_jp/developer/networking/proxy/vine",
},
],
},
{
text: "Query (GameSpy4)",
link: "/ja_jp/developer/networking/query",
}, },
{ {
text: "RCON", text: "RCON",
@ -58,7 +160,51 @@ export const jaJP = defineConfig({
}, },
], ],
}, },
{ text: "ワールド", link: "/ja_jp/developer/world" }, {
text: "ブロック",
collapsed: true,
items: [
{ text: "概要", link: "/ja_jp/developer/blocks/" },
{ text: "ブロックの追加", link: "/ja_jp/developer/blocks/adding-blocks" },
],
},
{
text: "アイテム",
collapsed: true,
items: [
{ text: "概要", link: "/ja_jp/developer/items/" },
{ text: "アイテムの追加", link: "/ja_jp/developer/items/adding-items" },
],
},
{
text: "エンティティ",
collapsed: true,
items: [
{ text: "概要と階層", link: "/ja_jp/developer/entities/" },
{ text: "スポーンと追跡", link: "/ja_jp/developer/entities/spawning-and-tracking" },
{ text: "Mob AI とゴール", link: "/ja_jp/developer/entities/ai-and-mobs" },
],
},
{
text: "コマンド",
collapsed: true,
items: [
{ text: "概要とディスパッチャー", link: "/ja_jp/developer/commands/" },
{ text: "コマンドの追加", link: "/ja_jp/developer/commands/adding-commands" },
{ text: "引数とサジェスト", link: "/ja_jp/developer/commands/arguments-and-suggestions" },
{ text: "実行とコンテキスト", link: "/ja_jp/developer/commands/execution-and-context" },
],
},
{
text: "プラグインエンジン",
collapsed: true,
items: [
{ text: "概要", link: "/ja_jp/developer/plugins/" },
{ text: "プラグインローダーの追加", link: "/ja_jp/developer/plugins/loaders" },
{ text: "WASM 署名と検証", link: "/ja_jp/developer/plugins/wasm-signing" },
],
},
{ text: "ワールドエンジン", link: "/ja_jp/developer/world" },
{ text: "モバイル開発", link: "/ja_jp/developer/mobile" }, { text: "モバイル開発", link: "/ja_jp/developer/mobile" },
], ],
}, },
@ -69,9 +215,35 @@ export const jaJP = defineConfig({
text: "はじめに", text: "はじめに",
link: "/ja_jp/plugin-dev/introduction", link: "/ja_jp/plugin-dev/introduction",
}, },
{
text: "Bukkit からの移行",
collapsed: true,
items: [
{
text: "概要",
link: "/ja_jp/plugin-dev/migrating-from-bukkit/",
},
{
text: "コマンド",
link: "/ja_jp/plugin-dev/migrating-from-bukkit/commands",
},
{
text: "イベント",
link: "/ja_jp/plugin-dev/migrating-from-bukkit/events",
},
{
text: "インベントリ & GUI",
link: "/ja_jp/plugin-dev/migrating-from-bukkit/inventories",
},
{
text: "設定とデータ",
link: "/ja_jp/plugin-dev/migrating-from-bukkit/configuration",
},
],
},
{ {
text: "Rust", text: "Rust",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "プロジェクトの作成", text: "プロジェクトの作成",
@ -98,11 +270,15 @@ export const jaJP = defineConfig({
}, },
], ],
}, },
{
text: "ライセンスとアップデート",
link: "/ja_jp/plugin-dev/rust/plugin-utils",
},
], ],
}, },
{ {
text: "Python", text: "Python",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "クイックスタート", text: "クイックスタート",
@ -112,6 +288,10 @@ export const jaJP = defineConfig({
text: "基本ロジック", text: "基本ロジック",
link: "/ja_jp/plugin-dev/python/basic-logic", link: "/ja_jp/plugin-dev/python/basic-logic",
}, },
{
text: "最初のコマンド",
link: "/ja_jp/plugin-dev/python/first-command",
},
{ {
text: "イベント", text: "イベント",
link: "/ja_jp/plugin-dev/python/events", link: "/ja_jp/plugin-dev/python/events",
@ -120,27 +300,35 @@ export const jaJP = defineConfig({
}, },
{ {
text: "C#", text: "C#",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "クイックスタート", text: "クイックスタート",
link: "/ja_jp/plugin-dev/csharp/quick-start", link: "/ja_jp/plugin-dev/csharp/quick-start",
}, },
{
text: "最初のコマンド",
link: "/ja_jp/plugin-dev/csharp/first-command",
},
], ],
}, },
{ {
text: "C", text: "C",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "クイックスタート", text: "クイックスタート",
link: "/ja_jp/plugin-dev/c/quick-start", link: "/ja_jp/plugin-dev/c/quick-start",
}, },
{
text: "最初のコマンド",
link: "/ja_jp/plugin-dev/c/first-command",
},
], ],
}, },
{ {
text: "Go", text: "Go",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "クイックスタート", text: "クイックスタート",
@ -150,6 +338,34 @@ export const jaJP = defineConfig({
text: "基本ロジック", text: "基本ロジック",
link: "/ja_jp/plugin-dev/go/basic-logic", link: "/ja_jp/plugin-dev/go/basic-logic",
}, },
{
text: "最初のコマンド",
link: "/ja_jp/plugin-dev/go/first-command",
},
],
},
{
text: "Kotlin",
collapsed: true,
items: [
{
text: "クイックスタート",
link: "/ja_jp/plugin-dev/kotlin/quick-start",
},
{
text: "最初のコマンド",
link: "/ja_jp/plugin-dev/kotlin/first-command",
},
],
},
{
text: "D",
collapsed: true,
items: [
{
text: "クイックスタート",
link: "/ja_jp/plugin-dev/d/quick-start",
},
], ],
}, },
], ],
@ -159,7 +375,7 @@ export const jaJP = defineConfig({
items: [ items: [
{ {
text: "よくある問題", text: "よくある問題",
link: "/ja_jp/troubleshooting/common_issues.md", link: "/ja_jp/troubleshooting/common_issues",
}, },
], ],
}, },
@ -172,16 +388,16 @@ export const jaJP = defineConfig({
logo: "/assets/favicon.ico", logo: "/assets/favicon.ico",
footer: { footer: {
message: "MIT ライセンスの下で公開されています。", message: "MIT ライセンスの下でリリースされています。",
copyright: `Copyright © 2024-${new Date().getFullYear()} Aleksandr Medvedev`, copyright: `Copyright © 2024-${new Date().getFullYear()} Aleksandr Medvedev`,
}, },
editLink: { editLink: {
pattern: pattern:
"https://github.com/Pumpkin-MC/Pumpkin-Docs/blob/master/docs/:path", "https://github.com/Pumpkin-MC/Pumpkin-Docs/blob/master/docs/:path",
text: "GitHub でこのページを編集する", text: "GitHub でこのページを編集",
}, },
lastUpdated: { lastUpdated: {
text: "最終更新", text: "最終更新日",
formatOptions: { formatOptions: {
dateStyle: "medium", dateStyle: "medium",
timeStyle: "medium", timeStyle: "medium",

View File

@ -5,14 +5,26 @@ export const nl = defineConfig({
description: "Een Minecraft-serversoftware met hoge prestaties, geschreven in Rust", description: "Een Minecraft-serversoftware met hoge prestaties, geschreven in Rust",
themeConfig: { themeConfig: {
// https://vitepress.dev/reference/default-theme-config siteTitle: "Pumpkin Docs",
search: { search: {
provider: "local", provider: "local",
}, },
nav: [ nav: [
{ {
text: "Documentatie", text: "Beheer",
link: "/nl/about/introduction", link: "/nl/admin/introduction",
},
{
text: "Bijdragers",
link: "/nl/developer/introduction",
},
{
text: "Plugins",
link: "/nl/plugin-dev/introduction",
},
{
text: "Website",
link: "https://pumpkinmc.org/",
}, },
], ],
sidebar: [ sidebar: [
@ -23,36 +35,176 @@ export const nl = defineConfig({
], ],
}, },
{ {
text: "Configuratie", text: "Beheer",
collapsed: false,
items: [ items: [
{ text: "Introductie", link: "/nl/config/introduction" }, { text: "Overzicht", link: "/nl/admin/introduction" },
{ text: "Basis", link: "/nl/config/basic" }, { text: "Migreren van Bukkit", link: "/nl/admin/migrating-from-bukkit" },
{ text: "Proxy", link: "/nl/config/proxy" }, {
{ text: "Authenticatie", link: "/nl/config/authentication" }, text: "Configuratie",
{ text: "Compressie", link: "/nl/config/compression" }, collapsed: true,
{ text: "Resource Pack", link: "/nl/config/resource-pack" }, items: [
{ text: "Commando's", link: "/nl/config/commands" }, { text: "Introductie", link: "/nl/config/introduction" },
{ text: "RCON", link: "/nl/config/rcon" }, { text: "Basis", link: "/nl/config/basic" },
{ text: "PVP", link: "/nl/config/pvp" }, { text: "Wereld", link: "/nl/config/world" },
{ text: "Logbestanden", link: "/nl/config/logging" }, { text: "Chat & Anti-Spam", link: "/nl/config/chat" },
{ text: "Query", link: "/nl/config/query" }, { text: "Commando's", link: "/nl/config/commands" },
{ text: "LAN Broadcast", link: "/nl/config/lan-broadcast" }, { text: "Bedrock & NetherNet", link: "/nl/config/bedrock" },
{ text: "Proxy", link: "/nl/config/proxy" },
{ text: "Authenticatie", link: "/nl/config/authentication" },
{ text: "Pakketlimiet", link: "/nl/config/packet-limiter" },
{ text: "Compressie", link: "/nl/config/compression" },
{ text: "Resource Pack", link: "/nl/config/resource-pack" },
{ text: "Plugins", link: "/nl/config/plugins" },
{ text: "Serverlinks", link: "/nl/config/server-links" },
{ text: "Spelergegevens", link: "/nl/config/player-data" },
{ text: "Logbestanden", link: "/nl/config/logging" },
{ text: "Query", link: "/nl/config/query" },
{ text: "RCON", link: "/nl/config/rcon" },
{ text: "PVP", link: "/nl/config/pvp" },
{ text: "LAN Broadcast", link: "/nl/config/lan-broadcast" },
],
},
], ],
}, },
{ {
text: "Ontwikkelaars", text: "Bijdragers",
items: [ items: [
{ text: "Bijdragen", link: "/nl/developer/contributing" },
{ text: "Introductie", link: "/nl/developer/introduction" }, { text: "Introductie", link: "/nl/developer/introduction" },
{ text: "Bijdragegids", link: "/nl/developer/contributing" },
{ text: "Architectuur", link: "/nl/developer/architecture" },
{ text: "Gegevensextractor", link: "/nl/developer/extractor" },
{ text: "Codegeneratie", link: "/nl/developer/codegen" },
{ text: "Versies overzetten", link: "/nl/developer/porting-versions" },
{ {
text: "Netwerken", text: "Netwerken",
link: "/nl/developer/networking/networking", collapsed: true,
items: [ items: [
{ text: "Authenticatie", link: "/nl/developer/networking/authentication" }, {
{ text: "RCON", link: "/nl/developer/networking/rcon" }, text: "Introductie",
] link: "/nl/developer/networking/",
},
{
text: "Metadata & Gesynchroniseerde Gegevens",
link: "/nl/developer/networking/metadata",
},
{
text: "Java Edition",
collapsed: true,
items: [
{
text: "Overzicht",
link: "/nl/developer/networking/java/overview",
},
{
text: "Pakket toevoegen",
link: "/nl/developer/networking/java/adding-packets",
},
{
text: "Authenticatie",
link: "/nl/developer/networking/java/authentication",
},
],
},
{
text: "Bedrock Edition",
collapsed: true,
items: [
{
text: "Overzicht",
link: "/nl/developer/networking/bedrock/overview",
},
{
text: "Pakket toevoegen",
link: "/nl/developer/networking/bedrock/adding-packets",
},
{
text: "Authenticatie",
link: "/nl/developer/networking/bedrock/authentication",
},
{
text: "NetherNet",
link: "/nl/developer/networking/bedrock/nethernet",
},
],
},
{
text: "Proxy-doorsturing",
collapsed: true,
items: [
{
text: "Overzicht",
link: "/nl/developer/networking/proxy/",
},
{
text: "BungeeCord",
link: "/nl/developer/networking/proxy/bungeecord",
},
{
text: "Velocity",
link: "/nl/developer/networking/proxy/velocity",
},
{
text: "Vine",
link: "/nl/developer/networking/proxy/vine",
},
],
},
{
text: "Query (GameSpy4)",
link: "/nl/developer/networking/query",
},
{
text: "RCON",
link: "/nl/developer/networking/rcon",
},
],
}, },
{ text: "Wereld", link: "/nl/developer/world" }, {
text: "Blokken",
collapsed: true,
items: [
{ text: "Overzicht", link: "/nl/developer/blocks/" },
{ text: "Blok toevoegen", link: "/nl/developer/blocks/adding-blocks" },
],
},
{
text: "Items",
collapsed: true,
items: [
{ text: "Overzicht", link: "/nl/developer/items/" },
{ text: "Item toevoegen", link: "/nl/developer/items/adding-items" },
],
},
{
text: "Entities",
collapsed: true,
items: [
{ text: "Overzicht & Hiërarchie", link: "/nl/developer/entities/" },
{ text: "Spawning & Tracking", link: "/nl/developer/entities/spawning-and-tracking" },
{ text: "Mob-AI & Doelen", link: "/nl/developer/entities/ai-and-mobs" },
],
},
{
text: "Commando's",
collapsed: true,
items: [
{ text: "Overzicht & Dispatcher", link: "/nl/developer/commands/" },
{ text: "Commando toevoegen", link: "/nl/developer/commands/adding-commands" },
{ text: "Argumenten & Suggesties", link: "/nl/developer/commands/arguments-and-suggestions" },
{ text: "Uitvoering & Context", link: "/nl/developer/commands/execution-and-context" },
],
},
{
text: "Plugin-engine",
collapsed: true,
items: [
{ text: "Overzicht", link: "/nl/developer/plugins/" },
{ text: "Plugin-loader toevoegen", link: "/nl/developer/plugins/loaders" },
{ text: "WASM-ondertekening & Verificatie", link: "/nl/developer/plugins/wasm-signing" },
],
},
{ text: "Wereld-engine", link: "/nl/developer/world" },
{ text: "Mobiele ontwikkeling", link: "/nl/developer/mobile" }, { text: "Mobiele ontwikkeling", link: "/nl/developer/mobile" },
], ],
}, },
@ -63,9 +215,35 @@ export const nl = defineConfig({
text: "Introductie", text: "Introductie",
link: "/nl/plugin-dev/introduction", link: "/nl/plugin-dev/introduction",
}, },
{
text: "Migreren van Bukkit",
collapsed: true,
items: [
{
text: "Overzicht",
link: "/nl/plugin-dev/migrating-from-bukkit/",
},
{
text: "Commando's",
link: "/nl/plugin-dev/migrating-from-bukkit/commands",
},
{
text: "Events",
link: "/nl/plugin-dev/migrating-from-bukkit/events",
},
{
text: "Inventarissen & GUI's",
link: "/nl/plugin-dev/migrating-from-bukkit/inventories",
},
{
text: "Configuratie & Gegevens",
link: "/nl/plugin-dev/migrating-from-bukkit/configuration",
},
],
},
{ {
text: "Rust", text: "Rust",
link: "/nl/plugin-dev/rust/introduction", collapsed: true,
items: [ items: [
{ {
text: "Project aanmaken", text: "Project aanmaken",
@ -76,23 +254,44 @@ export const nl = defineConfig({
link: "/nl/plugin-dev/rust/basic-logic", link: "/nl/plugin-dev/rust/basic-logic",
}, },
{ {
text: "Join Event", text: "Events",
link: "/nl/plugin-dev/rust/join-event", link: "/nl/plugin-dev/rust/events",
},
{
text: "Commando's",
items: [
{
text: "Eerste commando",
link: "/nl/plugin-dev/rust/command/first-command",
},
{
text: "Steen-papier-schaar",
link: "/nl/plugin-dev/rust/command/rock-paper-scissors",
},
],
},
{
text: "Licenties & Updates",
link: "/nl/plugin-dev/rust/plugin-utils",
}, },
], ],
}, },
{ {
text: "Python", text: "Python",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Quick Start", text: "Quick Start",
link: "/nl/plugin-dev/python/quick-start", link: "/nl/plugin-dev/python/quick-start",
}, },
{ {
text: "Basic Logic", text: "Basislogica",
link: "/nl/plugin-dev/python/basic-logic", link: "/nl/plugin-dev/python/basic-logic",
}, },
{
text: "Eerste commando",
link: "/nl/plugin-dev/python/first-command",
},
{ {
text: "Events", text: "Events",
link: "/nl/plugin-dev/python/events", link: "/nl/plugin-dev/python/events",
@ -101,22 +300,72 @@ export const nl = defineConfig({
}, },
{ {
text: "C#", text: "C#",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Quick Start", text: "Quick Start",
link: "/nl/plugin-dev/csharp/quick-start", link: "/nl/plugin-dev/csharp/quick-start",
}, },
{
text: "Eerste commando",
link: "/nl/plugin-dev/csharp/first-command",
},
], ],
}, },
{ {
text: "C", text: "C",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Snelstart", text: "Quick Start",
link: "/nl/plugin-dev/c/quick-start", link: "/nl/plugin-dev/c/quick-start",
}, },
{
text: "Eerste commando",
link: "/nl/plugin-dev/c/first-command",
},
],
},
{
text: "Go",
collapsed: true,
items: [
{
text: "Quick Start",
link: "/nl/plugin-dev/go/quick-start",
},
{
text: "Basislogica",
link: "/nl/plugin-dev/go/basic-logic",
},
{
text: "Eerste commando",
link: "/nl/plugin-dev/go/first-command",
},
],
},
{
text: "Kotlin",
collapsed: true,
items: [
{
text: "Quick Start",
link: "/nl/plugin-dev/kotlin/quick-start",
},
{
text: "Eerste commando",
link: "/nl/plugin-dev/kotlin/first-command",
},
],
},
{
text: "D",
collapsed: true,
items: [
{
text: "Quick Start",
link: "/nl/plugin-dev/d/quick-start",
},
], ],
}, },
], ],
@ -126,7 +375,7 @@ export const nl = defineConfig({
items: [ items: [
{ {
text: "Veelvoorkomende problemen", text: "Veelvoorkomende problemen",
link: "/nl/troubleshooting/common_issues.md", link: "/nl/troubleshooting/common_issues",
}, },
], ],
}, },
@ -155,5 +404,5 @@ export const nl = defineConfig({
}, },
}, },
outline: "deep", outline: "deep",
} },
}); });

View File

@ -1,18 +1,30 @@
import { defineConfig } from "vitepress"; import { defineConfig } from "vitepress";
export const pt = defineConfig({ export const pt = defineConfig({
lang: "pt-BR", lang: "pt",
description: "Um servidor Minecraft de alto desempenho escrito em Rust", description: "Um software de servidor Minecraft de alta performance escrito em Rust",
themeConfig: { themeConfig: {
// https://vitepress.dev/reference/default-theme-config siteTitle: "Pumpkin Docs",
search: { search: {
provider: "local", provider: "local",
}, },
nav: [ nav: [
{ {
text: "Documentação", text: "Administração",
link: "/pt/about/introduction", link: "/pt/admin/introduction",
},
{
text: "Contribuidores",
link: "/pt/developer/introduction",
},
{
text: "Plugins",
link: "/pt/plugin-dev/introduction",
},
{
text: "Site",
link: "https://pumpkinmc.org/",
}, },
], ],
sidebar: [ sidebar: [
@ -23,36 +35,176 @@ export const pt = defineConfig({
], ],
}, },
{ {
text: "Configuração", text: "Administração",
collapsed: false,
items: [ items: [
{ text: "Introdução", link: "/pt/config/introduction" }, { text: "Visão Geral", link: "/pt/admin/introduction" },
{ text: "Básico", link: "/pt/config/basic" }, { text: "Migrando do Bukkit", link: "/pt/admin/migrating-from-bukkit" },
{ text: "Proxy", link: "/pt/config/proxy" }, {
{ text: "Autenticação", link: "/pt/config/authentication" }, text: "Configuração",
{ text: "Compressão", link: "/pt/config/compression" }, collapsed: true,
{ text: "Pacote de Recursos", link: "/pt/config/resource-pack" }, items: [
{ text: "Comandos", link: "/pt/config/commands" }, { text: "Introdução", link: "/pt/config/introduction" },
{ text: "RCON", link: "/pt/config/rcon" }, { text: "Básico", link: "/pt/config/basic" },
{ text: "PVP", link: "/pt/config/pvp" }, { text: "Mundo", link: "/pt/config/world" },
{ text: "Log", link: "/pt/config/logging" }, { text: "Chat e Anti-Spam", link: "/pt/config/chat" },
{ text: "Query", link: "/pt/config/query" }, { text: "Comandos", link: "/pt/config/commands" },
{ text: "Transmissão LAN", link: "/pt/config/lan-broadcast" }, { text: "Bedrock e NetherNet", link: "/pt/config/bedrock" },
{ text: "Proxy", link: "/pt/config/proxy" },
{ text: "Autenticação", link: "/pt/config/authentication" },
{ text: "Limitador de Pacotes", link: "/pt/config/packet-limiter" },
{ text: "Compressão", link: "/pt/config/compression" },
{ text: "Pacote de Recursos", link: "/pt/config/resource-pack" },
{ text: "Plugins", link: "/pt/config/plugins" },
{ text: "Links do Servidor", link: "/pt/config/server-links" },
{ text: "Dados do Jogador", link: "/pt/config/player-data" },
{ text: "Registros (Logging)", link: "/pt/config/logging" },
{ text: "Query", link: "/pt/config/query" },
{ text: "RCON", link: "/pt/config/rcon" },
{ text: "PVP", link: "/pt/config/pvp" },
{ text: "Transmissão LAN", link: "/pt/config/lan-broadcast" },
],
},
], ],
}, },
{ {
text: "Desenvolvedores", text: "Contribuidores",
items: [ items: [
{ text: "Contribuindo", link: "/pt/developer/contributing" },
{ text: "Introdução", link: "/pt/developer/introduction" }, { text: "Introdução", link: "/pt/developer/introduction" },
{ text: "Guia de Contribuição", link: "/pt/developer/contributing" },
{ text: "Arquitetura", link: "/pt/developer/architecture" },
{ text: "Extrator de Dados", link: "/pt/developer/extractor" },
{ text: "Geração de Código", link: "/pt/developer/codegen" },
{ text: "Portando Versões", link: "/pt/developer/porting-versions" },
{ {
text: "Rede", text: "Rede",
link: "/pt/developer/networking/networking", collapsed: true,
items: [ items: [
{ text: "Autenticação", link: "/pt/developer/networking/authentication" }, {
{ text: "RCON", link: "/pt/developer/networking/rcon" }, text: "Introdução",
] link: "/pt/developer/networking/",
},
{
text: "Metadados e Dados Sincronizados",
link: "/pt/developer/networking/metadata",
},
{
text: "Java Edition",
collapsed: true,
items: [
{
text: "Visão Geral",
link: "/pt/developer/networking/java/overview",
},
{
text: "Adicionando um Pacote",
link: "/pt/developer/networking/java/adding-packets",
},
{
text: "Autenticação",
link: "/pt/developer/networking/java/authentication",
},
],
},
{
text: "Bedrock Edition",
collapsed: true,
items: [
{
text: "Visão Geral",
link: "/pt/developer/networking/bedrock/overview",
},
{
text: "Adicionando um Pacote",
link: "/pt/developer/networking/bedrock/adding-packets",
},
{
text: "Autenticação",
link: "/pt/developer/networking/bedrock/authentication",
},
{
text: "NetherNet",
link: "/pt/developer/networking/bedrock/nethernet",
},
],
},
{
text: "Encaminhamento de Proxy",
collapsed: true,
items: [
{
text: "Visão Geral",
link: "/pt/developer/networking/proxy/",
},
{
text: "BungeeCord",
link: "/pt/developer/networking/proxy/bungeecord",
},
{
text: "Velocity",
link: "/pt/developer/networking/proxy/velocity",
},
{
text: "Vine",
link: "/pt/developer/networking/proxy/vine",
},
],
},
{
text: "Query (GameSpy4)",
link: "/pt/developer/networking/query",
},
{
text: "RCON",
link: "/pt/developer/networking/rcon",
},
],
}, },
{ text: "Mundo", link: "/pt/developer/world" }, {
text: "Blocos",
collapsed: true,
items: [
{ text: "Visão Geral", link: "/pt/developer/blocks/" },
{ text: "Adicionando um Bloco", link: "/pt/developer/blocks/adding-blocks" },
],
},
{
text: "Itens",
collapsed: true,
items: [
{ text: "Visão Geral", link: "/pt/developer/items/" },
{ text: "Adicionando um Item", link: "/pt/developer/items/adding-items" },
],
},
{
text: "Entidades",
collapsed: true,
items: [
{ text: "Visão Geral e Hierarquia", link: "/pt/developer/entities/" },
{ text: "Spawning e Rastreamento", link: "/pt/developer/entities/spawning-and-tracking" },
{ text: "IA e Objetivos de Mobs", link: "/pt/developer/entities/ai-and-mobs" },
],
},
{
text: "Comandos",
collapsed: true,
items: [
{ text: "Visão Geral e Despachante", link: "/pt/developer/commands/" },
{ text: "Adicionando um Comando", link: "/pt/developer/commands/adding-commands" },
{ text: "Argumentos e Sugestões", link: "/pt/developer/commands/arguments-and-suggestions" },
{ text: "Execução e Contexto", link: "/pt/developer/commands/execution-and-context" },
],
},
{
text: "Motor de Plugins",
collapsed: true,
items: [
{ text: "Visão Geral", link: "/pt/developer/plugins/" },
{ text: "Adicionando um Carregador de Plugins", link: "/pt/developer/plugins/loaders" },
{ text: "Assinatura e Verificação WASM", link: "/pt/developer/plugins/wasm-signing" },
],
},
{ text: "Motor do Mundo", link: "/pt/developer/world" },
{ text: "Desenvolvimento Mobile", link: "/pt/developer/mobile" }, { text: "Desenvolvimento Mobile", link: "/pt/developer/mobile" },
], ],
}, },
@ -64,59 +216,156 @@ export const pt = defineConfig({
link: "/pt/plugin-dev/introduction", link: "/pt/plugin-dev/introduction",
}, },
{ {
text: "Rust", text: "Migrando do Bukkit",
link: "/pt/plugin-dev/rust/introduction", collapsed: true,
items: [ items: [
{ {
text: "Criando um projeto", text: "Visão Geral",
link: "/pt/plugin-dev/migrating-from-bukkit/",
},
{
text: "Comandos",
link: "/pt/plugin-dev/migrating-from-bukkit/commands",
},
{
text: "Eventos",
link: "/pt/plugin-dev/migrating-from-bukkit/events",
},
{
text: "Inventários e GUIs",
link: "/pt/plugin-dev/migrating-from-bukkit/inventories",
},
{
text: "Configuração e Dados",
link: "/pt/plugin-dev/migrating-from-bukkit/configuration",
},
],
},
{
text: "Rust",
collapsed: true,
items: [
{
text: "Criando o Projeto",
link: "/pt/plugin-dev/rust/creating-project", link: "/pt/plugin-dev/rust/creating-project",
}, },
{ {
text: "Lógica básica", text: "Lógica Básica",
link: "/pt/plugin-dev/rust/basic-logic", link: "/pt/plugin-dev/rust/basic-logic",
}, },
{ {
text: "Gerenciador de eventos", text: "Eventos",
link: "/pt/plugin-dev/rust/join-event", link: "/pt/plugin-dev/rust/events",
},
{
text: "Comandos",
items: [
{
text: "Primeiro Comando",
link: "/pt/plugin-dev/rust/command/first-command",
},
{
text: "Pedra, Papel e Tesoura",
link: "/pt/plugin-dev/rust/command/rock-paper-scissors",
},
],
},
{
text: "Licenciamento e Atualizações",
link: "/pt/plugin-dev/rust/plugin-utils",
}, },
], ],
}, },
{ {
text: "Python", text: "Python",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Quick Start", text: "Início Rápido",
link: "/pt/plugin-dev/python/quick-start", link: "/pt/plugin-dev/python/quick-start",
}, },
{ {
text: "Basic Logic", text: "Lógica Básica",
link: "/pt/plugin-dev/python/basic-logic", link: "/pt/plugin-dev/python/basic-logic",
}, },
{ {
text: "Events", text: "Primeiro Comando",
link: "/pt/plugin-dev/python/first-command",
},
{
text: "Eventos",
link: "/pt/plugin-dev/python/events", link: "/pt/plugin-dev/python/events",
}, },
], ],
}, },
{ {
text: "C#", text: "C#",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Quick Start", text: "Início Rápido",
link: "/pt/plugin-dev/csharp/quick-start", link: "/pt/plugin-dev/csharp/quick-start",
}, },
{
text: "Primeiro Comando",
link: "/pt/plugin-dev/csharp/first-command",
},
], ],
}, },
{ {
text: "C", text: "C",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Início Rápido", text: "Início Rápido",
link: "/pt/plugin-dev/c/quick-start", link: "/pt/plugin-dev/c/quick-start",
}, },
{
text: "Primeiro Comando",
link: "/pt/plugin-dev/c/first-command",
},
],
},
{
text: "Go",
collapsed: true,
items: [
{
text: "Início Rápido",
link: "/pt/plugin-dev/go/quick-start",
},
{
text: "Lógica Básica",
link: "/pt/plugin-dev/go/basic-logic",
},
{
text: "Primeiro Comando",
link: "/pt/plugin-dev/go/first-command",
},
],
},
{
text: "Kotlin",
collapsed: true,
items: [
{
text: "Início Rápido",
link: "/pt/plugin-dev/kotlin/quick-start",
},
{
text: "Primeiro Comando",
link: "/pt/plugin-dev/kotlin/first-command",
},
],
},
{
text: "D",
collapsed: true,
items: [
{
text: "Início Rápido",
link: "/pt/plugin-dev/d/quick-start",
},
], ],
}, },
], ],
@ -126,7 +375,7 @@ export const pt = defineConfig({
items: [ items: [
{ {
text: "Problemas Comuns", text: "Problemas Comuns",
link: "/pt/troubleshooting/common_issues.md", link: "/pt/troubleshooting/common_issues",
}, },
], ],
}, },
@ -139,13 +388,13 @@ export const pt = defineConfig({
logo: "/assets/favicon.ico", logo: "/assets/favicon.ico",
footer: { footer: {
message: "Distribuído sob a Licença MIT.", message: "Lançado sob a licença MIT.",
copyright: `Copyright © 2024-${new Date().getFullYear()} Aleksandr Medvedev`, copyright: `Copyright © 2024-${new Date().getFullYear()} Aleksandr Medvedev`,
}, },
editLink: { editLink: {
pattern: pattern:
"https://github.com/Pumpkin-MC/Pumpkin-Docs/blob/master/docs/:path", "https://github.com/Pumpkin-MC/Pumpkin-Docs/blob/master/docs/:path",
text: "Edite esta página no GitHub", text: "Editar esta página no GitHub",
}, },
lastUpdated: { lastUpdated: {
text: "Atualizado em", text: "Atualizado em",
@ -155,5 +404,5 @@ export const pt = defineConfig({
}, },
}, },
outline: "deep", outline: "deep",
} },
}); });

View File

@ -2,16 +2,28 @@ import { defineConfig } from "vitepress";
export const trTR = defineConfig({ export const trTR = defineConfig({
lang: "tr-TR", lang: "tr-TR",
description: "Rust ile yazılmış yüksek performanslı bir Minecraft sunucu yazılımı", description: "Rust ile yazılmış yüksek performanslı Minecraft sunucu yazılımı",
themeConfig: { themeConfig: {
// https://vitepress.dev/reference/default-theme-config siteTitle: "Pumpkin Docs",
search: { search: {
provider: "local", provider: "local",
}, },
nav: [ nav: [
{ {
text: "Ana Sayfa", text: "Yönetim",
link: "/tr_TR/admin/introduction",
},
{
text: "Geliştiriciler",
link: "/tr_TR/developer/introduction",
},
{
text: "Eklentiler",
link: "/tr_TR/plugin-dev/introduction",
},
{
text: "Web Sitesi",
link: "https://pumpkinmc.org/", link: "https://pumpkinmc.org/",
}, },
], ],
@ -23,34 +35,124 @@ export const trTR = defineConfig({
], ],
}, },
{ {
text: "Yapılandırma", text: "Yönetim",
collapsed: false,
items: [ items: [
{ text: "Giriş", link: "/tr_TR/config/introduction" }, { text: "Genel Bakış", link: "/tr_TR/admin/introduction" },
{ text: "Temel", link: "/tr_TR/config/basic" }, { text: "Bukkit'ten Geçiş", link: "/tr_TR/admin/migrating-from-bukkit" },
{ text: "Proxy", link: "/tr_TR/config/proxy" }, {
{ text: "Kimlik Doğrulama", link: "/tr_TR/config/authentication" }, text: "Yapılandırma",
{ text: "Sıkıştırma", link: "/tr_TR/config/compression" }, collapsed: true,
{ text: "Kaynak Paketi", link: "/tr_TR/config/resource-pack" }, items: [
{ text: "Komutlar", link: "/tr_TR/config/commands" }, { text: "Giriş", link: "/tr_TR/config/introduction" },
{ text: "RCON", link: "/tr_TR/config/rcon" }, { text: "Temel", link: "/tr_TR/config/basic" },
{ text: "PVP", link: "/tr_TR/config/pvp" }, { text: "Dünya", link: "/tr_TR/config/world" },
{ text: "Günlükleme", link: "/tr_TR/config/logging" }, { text: "Sohbet & Anti-Spam", link: "/tr_TR/config/chat" },
{ text: "Query", link: "/tr_TR/config/query" }, { text: "Komutlar", link: "/tr_TR/config/commands" },
{ text: "LAN Yayını", link: "/tr_TR/config/lan-broadcast" }, { text: "Bedrock & NetherNet", link: "/tr_TR/config/bedrock" },
{ text: "Proxy", link: "/tr_TR/config/proxy" },
{ text: "Kimlik Doğrulama", link: "/tr_TR/config/authentication" },
{ text: "Paket Sınırlayıcı", link: "/tr_TR/config/packet-limiter" },
{ text: "Sıkıştırma", link: "/tr_TR/config/compression" },
{ text: "Kaynak Paketi", link: "/tr_TR/config/resource-pack" },
{ text: "Eklentiler", link: "/tr_TR/config/plugins" },
{ text: "Sunucu Bağlantıları", link: "/tr_TR/config/server-links" },
{ text: "Oyuncu Verileri", link: "/tr_TR/config/player-data" },
{ text: "Günlük Kaydı (Logging)", link: "/tr_TR/config/logging" },
{ text: "Query", link: "/tr_TR/config/query" },
{ text: "RCON", link: "/tr_TR/config/rcon" },
{ text: "PVP", link: "/tr_TR/config/pvp" },
{ text: "LAN Yayını", link: "/tr_TR/config/lan-broadcast" },
],
},
], ],
}, },
{ {
text: "Geliştiriciler", text: "Geliştiriciler",
items: [ items: [
{ text: "Katkıda Bulunma", link: "/tr_TR/developer/contributing" },
{ text: "Giriş", link: "/tr_TR/developer/introduction" }, { text: "Giriş", link: "/tr_TR/developer/introduction" },
{ text: "Katkı Kılavuzu", link: "/tr_TR/developer/contributing" },
{ text: "Mimari", link: "/tr_TR/developer/architecture" },
{ text: "Veri Çıkarıcı", link: "/tr_TR/developer/extractor" },
{ text: "Kod Üretimi", link: "/tr_TR/developer/codegen" },
{ text: "Sürüm Yükseltme", link: "/tr_TR/developer/porting-versions" },
{ {
text: "Ağ", text: "Ağ İletişimi",
link: "/tr_TR/developer/networking/networking", collapsed: true,
items: [ items: [
{ {
text: "Kimlik Doğrulama", text: "Giriş",
link: "/tr_TR/developer/networking/authentication", link: "/tr_TR/developer/networking/",
},
{
text: "Meta Veriler & Senkronize Veriler",
link: "/tr_TR/developer/networking/metadata",
},
{
text: "Java Edition",
collapsed: true,
items: [
{
text: "Genel Bakış",
link: "/tr_TR/developer/networking/java/overview",
},
{
text: "Paket Ekleme",
link: "/tr_TR/developer/networking/java/adding-packets",
},
{
text: "Kimlik Doğrulama",
link: "/tr_TR/developer/networking/java/authentication",
},
],
},
{
text: "Bedrock Edition",
collapsed: true,
items: [
{
text: "Genel Bakış",
link: "/tr_TR/developer/networking/bedrock/overview",
},
{
text: "Paket Ekleme",
link: "/tr_TR/developer/networking/bedrock/adding-packets",
},
{
text: "Kimlik Doğrulama",
link: "/tr_TR/developer/networking/bedrock/authentication",
},
{
text: "NetherNet",
link: "/tr_TR/developer/networking/bedrock/nethernet",
},
],
},
{
text: "Proxy Yönlendirme",
collapsed: true,
items: [
{
text: "Genel Bakış",
link: "/tr_TR/developer/networking/proxy/",
},
{
text: "BungeeCord",
link: "/tr_TR/developer/networking/proxy/bungeecord",
},
{
text: "Velocity",
link: "/tr_TR/developer/networking/proxy/velocity",
},
{
text: "Vine",
link: "/tr_TR/developer/networking/proxy/vine",
},
],
},
{
text: "Query (GameSpy4)",
link: "/tr_TR/developer/networking/query",
}, },
{ {
text: "RCON", text: "RCON",
@ -58,8 +160,52 @@ export const trTR = defineConfig({
}, },
], ],
}, },
{ text: "Dünya", link: "/tr_TR/developer/world" }, {
{ text: "Mobil geliştirme", link: "/tr_TR/developer/mobile" }, text: "Bloklar",
collapsed: true,
items: [
{ text: "Genel Bakış", link: "/tr_TR/developer/blocks/" },
{ text: "Blok Ekleme", link: "/tr_TR/developer/blocks/adding-blocks" },
],
},
{
text: "Eşyalar",
collapsed: true,
items: [
{ text: "Genel Bakış", link: "/tr_TR/developer/items/" },
{ text: "Eşya Ekleme", link: "/tr_TR/developer/items/adding-items" },
],
},
{
text: "Varlıklar",
collapsed: true,
items: [
{ text: "Genel Bakış & Hiyerarşi", link: "/tr_TR/developer/entities/" },
{ text: "Oluşum & Takip", link: "/tr_TR/developer/entities/spawning-and-tracking" },
{ text: "Yaratık Yapay Zekası & Hedefler", link: "/tr_TR/developer/entities/ai-and-mobs" },
],
},
{
text: "Komutlar",
collapsed: true,
items: [
{ text: "Genel Bakış & Dağıtıcı", link: "/tr_TR/developer/commands/" },
{ text: "Komut Ekleme", link: "/tr_TR/developer/commands/adding-commands" },
{ text: "Argümanlar & Öneriler", link: "/tr_TR/developer/commands/arguments-and-suggestions" },
{ text: "Çalıştırma & Bağlam", link: "/tr_TR/developer/commands/execution-and-context" },
],
},
{
text: "Eklenti Motoru",
collapsed: true,
items: [
{ text: "Genel Bakış", link: "/tr_TR/developer/plugins/" },
{ text: "Eklenti Yükleyici Ekleme", link: "/tr_TR/developer/plugins/loaders" },
{ text: "WASM İmzalama & Doğrulama", link: "/tr_TR/developer/plugins/wasm-signing" },
],
},
{ text: "Dünya Motoru", link: "/tr_TR/developer/world" },
{ text: "Mobil Geliştirme", link: "/tr_TR/developer/mobile" },
], ],
}, },
{ {
@ -69,9 +215,35 @@ export const trTR = defineConfig({
text: "Giriş", text: "Giriş",
link: "/tr_TR/plugin-dev/introduction", link: "/tr_TR/plugin-dev/introduction",
}, },
{
text: "Bukkit'ten Geçiş",
collapsed: true,
items: [
{
text: "Genel Bakış",
link: "/tr_TR/plugin-dev/migrating-from-bukkit/",
},
{
text: "Komutlar",
link: "/tr_TR/plugin-dev/migrating-from-bukkit/commands",
},
{
text: "Olaylar (Events)",
link: "/tr_TR/plugin-dev/migrating-from-bukkit/events",
},
{
text: "Envanterler & Arayüzler",
link: "/tr_TR/plugin-dev/migrating-from-bukkit/inventories",
},
{
text: "Yapılandırma & Veri",
link: "/tr_TR/plugin-dev/migrating-from-bukkit/configuration",
},
],
},
{ {
text: "Rust", text: "Rust",
link: "/tr_TR/plugin-dev/rust/introduction", collapsed: true,
items: [ items: [
{ {
text: "Proje Oluşturma", text: "Proje Oluşturma",
@ -82,60 +254,118 @@ export const trTR = defineConfig({
link: "/tr_TR/plugin-dev/rust/basic-logic", link: "/tr_TR/plugin-dev/rust/basic-logic",
}, },
{ {
text: "Katılma Olayı", text: "Olaylar (Events)",
link: "/tr_TR/plugin-dev/rust/join-event", link: "/tr_TR/plugin-dev/rust/events",
}, },
{ {
text: "Komutlar", text: "Komutlar",
items: [ items: [
{
text: "İlk Komut",
link: "/tr_TR/plugin-dev/rust/command/first-command",
},
{ {
text: "Taş-Kağıt-Makas", text: "Taş-Kağıt-Makas",
link: "/tr_TR/plugin-dev/rust/command/rock-paper-scissors", link: "/tr_TR/plugin-dev/rust/command/rock-paper-scissors",
}, },
{
text: "Envanterler",
link: "/tr_TR/plugin-dev/rust/command/inventories",
},
], ],
}, },
{
text: "Lisanslama & Güncellemeler",
link: "/tr_TR/plugin-dev/rust/plugin-utils",
},
], ],
}, },
{ {
text: "Python", text: "Python",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Quick Start", text: "Hızlı Başlangıç",
link: "/tr_TR/plugin-dev/python/quick-start", link: "/tr_TR/plugin-dev/python/quick-start",
}, },
{ {
text: "Basic Logic", text: "Temel Mantık",
link: "/tr_TR/plugin-dev/python/basic-logic", link: "/tr_TR/plugin-dev/python/basic-logic",
}, },
{ {
text: "Events", text: "İlk Komut",
link: "/tr_TR/plugin-dev/python/first-command",
},
{
text: "Olaylar (Events)",
link: "/tr_TR/plugin-dev/python/events", link: "/tr_TR/plugin-dev/python/events",
}, },
], ],
}, },
{ {
text: "C#", text: "C#",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Hızlı Başlangıç", text: "Hızlı Başlangıç",
link: "/tr_TR/plugin-dev/csharp/quick-start", link: "/tr_TR/plugin-dev/csharp/quick-start",
}, },
{
text: "İlk Komut",
link: "/tr_TR/plugin-dev/csharp/first-command",
},
], ],
}, },
{ {
text: "C", text: "C",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Hızlı Başlangıç", text: "Hızlı Başlangıç",
link: "/tr_TR/plugin-dev/c/quick-start", link: "/tr_TR/plugin-dev/c/quick-start",
}, },
{
text: "İlk Komut",
link: "/tr_TR/plugin-dev/c/first-command",
},
],
},
{
text: "Go",
collapsed: true,
items: [
{
text: "Hızlı Başlangıç",
link: "/tr_TR/plugin-dev/go/quick-start",
},
{
text: "Temel Mantık",
link: "/tr_TR/plugin-dev/go/basic-logic",
},
{
text: "İlk Komut",
link: "/tr_TR/plugin-dev/go/first-command",
},
],
},
{
text: "Kotlin",
collapsed: true,
items: [
{
text: "Hızlı Başlangıç",
link: "/tr_TR/plugin-dev/kotlin/quick-start",
},
{
text: "İlk Komut",
link: "/tr_TR/plugin-dev/kotlin/first-command",
},
],
},
{
text: "D",
collapsed: true,
items: [
{
text: "Hızlı Başlangıç",
link: "/tr_TR/plugin-dev/d/quick-start",
},
], ],
}, },
], ],
@ -145,7 +375,7 @@ export const trTR = defineConfig({
items: [ items: [
{ {
text: "Yaygın Sorunlar", text: "Yaygın Sorunlar",
link: "/tr_TR/troubleshooting/common_issues.md", link: "/tr_TR/troubleshooting/common_issues",
}, },
], ],
}, },
@ -158,16 +388,16 @@ export const trTR = defineConfig({
logo: "/assets/favicon.ico", logo: "/assets/favicon.ico",
footer: { footer: {
message: "MIT Lisansı altında yayımlanmıştır.", message: "MIT Lisansı altında yayınlandı.",
copyright: `Copyright © 2024-${new Date().getFullYear()} Aleksandr Medvedev`, copyright: `Copyright © 2024-${new Date().getFullYear()} Aleksandr Medvedev`,
}, },
editLink: { editLink: {
pattern: pattern:
"https://github.com/Pumpkin-MC/Pumpkin-Docs/blob/master/docs/:path", "https://github.com/Pumpkin-MC/Pumpkin-Docs/blob/master/docs/:path",
text: "Bu sayfayı GitHub'da düzenle", text: "Bu sayfayı GitHub'da düzenleyin",
}, },
lastUpdated: { lastUpdated: {
text: "Güncellenme", text: "Son güncelleme",
formatOptions: { formatOptions: {
dateStyle: "medium", dateStyle: "medium",
timeStyle: "medium", timeStyle: "medium",

View File

@ -2,17 +2,29 @@ import { defineConfig } from "vitepress";
export const zhCN = defineConfig({ export const zhCN = defineConfig({
lang: "zh-CN", lang: "zh-CN",
description: "一款用 Rust 编写的高性能 Minecraft 服务器软件", description: "使用 Rust 编写的高性能 Minecraft 服务器软件",
themeConfig: { themeConfig: {
// https://vitepress.dev/reference/default-theme-config siteTitle: "Pumpkin Docs",
search: { search: {
provider: "local", provider: "local",
}, },
nav: [ nav: [
{ {
text: "文档", text: "管理",
link: "/zh_cn/about/introduction", link: "/zh_cn/admin/introduction",
},
{
text: "贡献者",
link: "/zh_cn/developer/introduction",
},
{
text: "插件开发",
link: "/zh_cn/plugin-dev/introduction",
},
{
text: "官网",
link: "https://pumpkinmc.org/",
}, },
], ],
sidebar: [ sidebar: [
@ -23,34 +35,124 @@ export const zhCN = defineConfig({
], ],
}, },
{ {
text: "配置", text: "管理",
collapsed: false,
items: [ items: [
{ text: "介绍", link: "/zh_cn/config/introduction" }, { text: "概述", link: "/zh_cn/admin/introduction" },
{ text: "基础配置", link: "/zh_cn/config/basic" }, { text: "从 Bukkit 迁移", link: "/zh_cn/admin/migrating-from-bukkit" },
{ text: "代理", link: "/zh_cn/config/proxy" }, {
{ text: "身份验证", link: "/zh_cn/config/authentication" }, text: "配置",
{ text: "压缩", link: "/zh_cn/config/compression" }, collapsed: true,
{ text: "资源包", link: "/zh_cn/config/resource-pack" }, items: [
{ text: "命令", link: "/zh_cn/config/commands" }, { text: "介绍", link: "/zh_cn/config/introduction" },
{ text: "RCON", link: "/zh_cn/config/rcon" }, { text: "基础配置", link: "/zh_cn/config/basic" },
{ text: "PVP", link: "/zh_cn/config/pvp" }, { text: "世界", link: "/zh_cn/config/world" },
{ text: "日志", link: "/zh_cn/config/logging" }, { text: "聊天与反垃圾", link: "/zh_cn/config/chat" },
{ text: "查询", link: "/zh_cn/config/query" }, { text: "命令", link: "/zh_cn/config/commands" },
{ text: "局域网广播", link: "/zh_cn/config/lan-broadcast" }, { text: "基岩版与 NetherNet", link: "/zh_cn/config/bedrock" },
{ text: "代理", link: "/zh_cn/config/proxy" },
{ text: "身份验证", link: "/zh_cn/config/authentication" },
{ text: "数据包限制器", link: "/zh_cn/config/packet-limiter" },
{ text: "压缩", link: "/zh_cn/config/compression" },
{ text: "资源包", link: "/zh_cn/config/resource-pack" },
{ text: "插件", link: "/zh_cn/config/plugins" },
{ text: "服务器链接", link: "/zh_cn/config/server-links" },
{ text: "玩家数据", link: "/zh_cn/config/player-data" },
{ text: "日志", link: "/zh_cn/config/logging" },
{ text: "Query", link: "/zh_cn/config/query" },
{ text: "RCON", link: "/zh_cn/config/rcon" },
{ text: "PVP", link: "/zh_cn/config/pvp" },
{ text: "局域网广播", link: "/zh_cn/config/lan-broadcast" },
],
},
], ],
}, },
{ {
text: "开发者", text: "贡献者",
items: [ items: [
{ text: "贡献指南", link: "/zh_cn/developer/contributing" },
{ text: "介绍", link: "/zh_cn/developer/introduction" }, { text: "介绍", link: "/zh_cn/developer/introduction" },
{ text: "贡献指南", link: "/zh_cn/developer/contributing" },
{ text: "架构", link: "/zh_cn/developer/architecture" },
{ text: "数据提取器", link: "/zh_cn/developer/extractor" },
{ text: "代码生成", link: "/zh_cn/developer/codegen" },
{ text: "版本迁移", link: "/zh_cn/developer/porting-versions" },
{ {
text: "网络", text: "网络",
link: "/zh_cn/developer/networking/networking", collapsed: true,
items: [ items: [
{ {
text: "身份验证", text: "介绍",
link: "/zh_cn/developer/networking/authentication", link: "/zh_cn/developer/networking/",
},
{
text: "元数据与同步数据",
link: "/zh_cn/developer/networking/metadata",
},
{
text: "Java Edition",
collapsed: true,
items: [
{
text: "概述",
link: "/zh_cn/developer/networking/java/overview",
},
{
text: "添加数据包",
link: "/zh_cn/developer/networking/java/adding-packets",
},
{
text: "身份验证",
link: "/zh_cn/developer/networking/java/authentication",
},
],
},
{
text: "Bedrock Edition",
collapsed: true,
items: [
{
text: "概述",
link: "/zh_cn/developer/networking/bedrock/overview",
},
{
text: "添加数据包",
link: "/zh_cn/developer/networking/bedrock/adding-packets",
},
{
text: "身份验证",
link: "/zh_cn/developer/networking/bedrock/authentication",
},
{
text: "NetherNet",
link: "/zh_cn/developer/networking/bedrock/nethernet",
},
],
},
{
text: "代理转发",
collapsed: true,
items: [
{
text: "概述",
link: "/zh_cn/developer/networking/proxy/",
},
{
text: "BungeeCord",
link: "/zh_cn/developer/networking/proxy/bungeecord",
},
{
text: "Velocity",
link: "/zh_cn/developer/networking/proxy/velocity",
},
{
text: "Vine",
link: "/zh_cn/developer/networking/proxy/vine",
},
],
},
{
text: "Query (GameSpy4)",
link: "/zh_cn/developer/networking/query",
}, },
{ {
text: "RCON", text: "RCON",
@ -58,7 +160,51 @@ export const zhCN = defineConfig({
}, },
], ],
}, },
{ text: "世界", link: "/zh_cn/developer/world" }, {
text: "方块",
collapsed: true,
items: [
{ text: "概述", link: "/zh_cn/developer/blocks/" },
{ text: "添加方块", link: "/zh_cn/developer/blocks/adding-blocks" },
],
},
{
text: "物品",
collapsed: true,
items: [
{ text: "概述", link: "/zh_cn/developer/items/" },
{ text: "添加物品", link: "/zh_cn/developer/items/adding-items" },
],
},
{
text: "实体",
collapsed: true,
items: [
{ text: "概述与层级", link: "/zh_cn/developer/entities/" },
{ text: "生成与追踪", link: "/zh_cn/developer/entities/spawning-and-tracking" },
{ text: "生物 AI 与目标", link: "/zh_cn/developer/entities/ai-and-mobs" },
],
},
{
text: "命令",
collapsed: true,
items: [
{ text: "概述与调度器", link: "/zh_cn/developer/commands/" },
{ text: "添加命令", link: "/zh_cn/developer/commands/adding-commands" },
{ text: "参数与建议", link: "/zh_cn/developer/commands/arguments-and-suggestions" },
{ text: "执行与上下文", link: "/zh_cn/developer/commands/execution-and-context" },
],
},
{
text: "插件引擎",
collapsed: true,
items: [
{ text: "概述", link: "/zh_cn/developer/plugins/" },
{ text: "添加插件加载器", link: "/zh_cn/developer/plugins/loaders" },
{ text: "WASM 签名与校验", link: "/zh_cn/developer/plugins/wasm-signing" },
],
},
{ text: "世界引擎", link: "/zh_cn/developer/world" },
{ text: "移动端开发", link: "/zh_cn/developer/mobile" }, { text: "移动端开发", link: "/zh_cn/developer/mobile" },
], ],
}, },
@ -69,9 +215,35 @@ export const zhCN = defineConfig({
text: "介绍", text: "介绍",
link: "/zh_cn/plugin-dev/introduction", link: "/zh_cn/plugin-dev/introduction",
}, },
{
text: "从 Bukkit 迁移",
collapsed: true,
items: [
{
text: "概述",
link: "/zh_cn/plugin-dev/migrating-from-bukkit/",
},
{
text: "命令",
link: "/zh_cn/plugin-dev/migrating-from-bukkit/commands",
},
{
text: "事件",
link: "/zh_cn/plugin-dev/migrating-from-bukkit/events",
},
{
text: "物品栏与 GUI",
link: "/zh_cn/plugin-dev/migrating-from-bukkit/inventories",
},
{
text: "配置与数据",
link: "/zh_cn/plugin-dev/migrating-from-bukkit/configuration",
},
],
},
{ {
text: "Rust", text: "Rust",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "创建项目", text: "创建项目",
@ -83,65 +255,117 @@ export const zhCN = defineConfig({
}, },
{ {
text: "事件", text: "事件",
items: [ link: "/zh_cn/plugin-dev/rust/events",
{ text: "加入事件", link: "/zh_cn/plugin-dev/rust/join-event" },
]
}, },
{ {
text: "命令", text: "命令",
items: [ items: [
{ {
text: "第一个命令", text: "首个命令",
link: "/zh_cn/plugin-dev/rust/command/first-command" link: "/zh_cn/plugin-dev/rust/command/first-command",
}, },
{ {
text: "剪刀石头布", text: "剪刀石头布",
link: "/zh_cn/plugin-dev/rust/command/rock-paper-scissors" link: "/zh_cn/plugin-dev/rust/command/rock-paper-scissors",
}, },
] ],
}, },
{ {
text: "背包", text: "许可证与更新",
link: "/zh_cn/plugin-dev/rust/inventories", link: "/zh_cn/plugin-dev/rust/plugin-utils",
}, },
], ],
}, },
{ {
text: "Python", text: "Python",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "Quick Start", text: "快速入门",
link: "/zh_cn/plugin-dev/python/quick-start", link: "/zh_cn/plugin-dev/python/quick-start",
}, },
{ {
text: "Basic Logic", text: "基本逻辑",
link: "/zh_cn/plugin-dev/python/basic-logic", link: "/zh_cn/plugin-dev/python/basic-logic",
}, },
{ {
text: "Events", text: "首个命令",
link: "/zh_cn/plugin-dev/python/first-command",
},
{
text: "事件",
link: "/zh_cn/plugin-dev/python/events", link: "/zh_cn/plugin-dev/python/events",
}, },
], ],
}, },
{ {
text: "C#", text: "C#",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "快速入门", text: "快速入门",
link: "/zh_cn/plugin-dev/csharp/quick-start", link: "/zh_cn/plugin-dev/csharp/quick-start",
}, },
{
text: "首个命令",
link: "/zh_cn/plugin-dev/csharp/first-command",
},
], ],
}, },
{ {
text: "C", text: "C",
collapsed: false, collapsed: true,
items: [ items: [
{ {
text: "快速入门", text: "快速入门",
link: "/zh_cn/plugin-dev/c/quick-start", link: "/zh_cn/plugin-dev/c/quick-start",
}, },
{
text: "首个命令",
link: "/zh_cn/plugin-dev/c/first-command",
},
],
},
{
text: "Go",
collapsed: true,
items: [
{
text: "快速入门",
link: "/zh_cn/plugin-dev/go/quick-start",
},
{
text: "基本逻辑",
link: "/zh_cn/plugin-dev/go/basic-logic",
},
{
text: "首个命令",
link: "/zh_cn/plugin-dev/go/first-command",
},
],
},
{
text: "Kotlin",
collapsed: true,
items: [
{
text: "快速入门",
link: "/zh_cn/plugin-dev/kotlin/quick-start",
},
{
text: "首个命令",
link: "/zh_cn/plugin-dev/kotlin/first-command",
},
],
},
{
text: "D",
collapsed: true,
items: [
{
text: "快速入门",
link: "/zh_cn/plugin-dev/d/quick-start",
},
], ],
}, },
], ],
@ -151,7 +375,7 @@ export const zhCN = defineConfig({
items: [ items: [
{ {
text: "常见问题", text: "常见问题",
link: "/zh_cn/troubleshooting/common_issues.md", link: "/zh_cn/troubleshooting/common_issues",
}, },
], ],
}, },
@ -164,8 +388,8 @@ export const zhCN = defineConfig({
logo: "/assets/favicon.ico", logo: "/assets/favicon.ico",
footer: { footer: {
message: "基于 MIT 许可证发布。", message: "基于 MIT 许可发布。",
copyright: `版权所有 © 2024-${new Date().getFullYear()} Aleksandr Medvedev`, copyright: `Copyright © 2024-${new Date().getFullYear()} Aleksandr Medvedev`,
}, },
editLink: { editLink: {
pattern: pattern:
@ -173,7 +397,7 @@ export const zhCN = defineConfig({
text: "在 GitHub 上编辑此页面", text: "在 GitHub 上编辑此页面",
}, },
lastUpdated: { lastUpdated: {
text: "更新于", text: "最后更新于",
formatOptions: { formatOptions: {
dateStyle: "medium", dateStyle: "medium",
timeStyle: "medium", timeStyle: "medium",

View File

@ -0,0 +1,25 @@
# Administrationsübersicht
Willkommen im **Admin-Bereich** für Pumpkin-Serveradministratoren. Pumpkin ist ein hochperformanter, multithreaded Minecraft-Server, der in Rust geschrieben wurde und darauf ausgelegt ist, riesige Spielerzahlen bei minimalem Ressourcenverbrauch zu unterstützen.
---
## Hauptfunktionen für Server-Admins
- **Extremes Multithreading**: Von Grund auf für moderne Mehrkernprozessoren entwickelt.
- **WASM-Plugin-Architektur**: Sichere, isolierte (sandboxed) Plugin-Ausführung in Rust, Python, Kotlin, C#, Go oder C ohne JVM-Overhead.
- **Nativer Cross-Proxy-Support**: Standardmäßige Unterstützung für Velocity, BungeeCord und moderne Proxy-Weiterleitungen.
- **TOML-basierte Konfiguration**: Übersichtliche, menschenlesbare Konfigurationsdateien in `pumpkin.toml` und funktionsspezifischen TOML-Konfigurationen.
---
## Admin-Leitfäden & Themen
Entdecke die folgenden Administrationsleitfäden:
- [Migration von Bukkit- / Paper- / Spigot-Servern](./migrating-from-bukkit) — Wesentliche Unterschiede in der Serveradministration, bei Plugins, Weltspeicherung und Performance.
- [Serverkonfiguration](../config/introduction) — Detaillierte Übersicht über die Einstellungen in `pumpkin.toml`.
- [Proxy-Einrichtung](../config/proxy) — Konfiguration der Weiterleitung für BungeeCord & Velocity.
- [Befehle & Berechtigungen](../config/commands) — Verwalten von In-Game-Operator-Befehlen und Berechtigungen.
- [Authentifizierung](../config/authentication) — Online-Modus vs. Offline-Modus und Yggdrasil-Einstellungen.
- [Fehlerbehebung & Häufige Probleme](../troubleshooting/common_issues) — Behebung von Port-Bindungs-, Speicher- und Plugin-Ladefehlern.

View File

@ -0,0 +1,126 @@
# Migration von Bukkit / Spigot / Paper zu Pumpkin
Dieser Leitfaden beschreibt die architektonischen und konfigurationsbezogenen Unterschiede beim Wechsel eines Servers von Bukkit, Spigot oder Paper zu Pumpkin.
---
## 1. Architektonische Unterschiede
| Aspekt | Bukkit / Spigot / Paper | Pumpkin |
| :--- | :--- | :--- |
| **Laufzeitumgebung** | Java Virtual Machine (erfordert Java 17/21+) | Native Binärdatei (kompiliertes Rust, kein Java erforderlich) |
| **Startbefehl** | `java [flags] -jar server.jar` | `./pumpkin` |
| **Tick-Loop** | Single-Thread-Tick-Loop mit asynchroner Aufgabenverteilung | Multithreaded Tick-Ausführung über mehrere CPU-Kerne |
| **Plugin-Format** | Java-Bytecode (`.jar`) für die Bukkit-API | WebAssembly (`.wasm`) oder `.jar` via PatchBukkit |
| **Plugin-Sprachen** | Java, Kotlin, Scala | Rust, Python, Kotlin, C#, Go, C |
| **Konfiguration** | `server.properties`, `paper.yml`, `spigot.yml` | `pumpkin.toml` (TOML-Format) |
| **Speicherverwaltung** | JVM Garbage Collection | Native OS-Speicherallokation |
---
## 2. Plugins & Erweiterungen
### WebAssembly-Plugins
Pumpkins primäres Plugin-Format ist WebAssembly (`.wasm`):
- **Isolation**: Plugins laufen in einer isolierten WebAssembly-Laufzeitumgebung (Sandbox).
- **Sprachunterstützung**: Plugins können aus Rust, Python, Go, C#, C oder Kotlin zu WASM kompiliert werden.
- **Eigene Plugins**: Hinweise zur Portierung eigener Bukkit-Plugins findest du im [Entwickler-Migrationsleitfaden](../plugin-dev/migrating-from-bukkit/index).
### Bukkit-Plugin-Kompatibilität: PatchBukkit
Für Server, die auf bestehende Bukkit-/Spigot-`.jar`-Plugins angewiesen sind, bietet das Projekt **PatchBukkit** eine Kompatibilitätsschicht:
- **Architektur**: PatchBukkit bettet eine JVM in Pumpkin ein, implementiert Teile der Bukkit-API nach und vermittelt Aufrufe über JNI und FFI an Pumpkin.
- **Plugin-Verzeichnis**: Kompatible `.jar`-Plugins werden im Verzeichnis `patchbukkit/patchbukkit-plugins/` abgelegt.
- **Status & Einschränkungen**: PatchBukkit befindet sich in aktiver Entwicklung. Standardaufrufe der Bukkit-API werden unterstützt; Plugins, die stark auf NMS-Interna (`net.minecraft.server`), CraftBukkit-Reflexion oder Bytecode-Manipulation angewiesen sind, funktionieren möglicherweise noch nicht wie erwartet.
- **Java-Voraussetzung**: Die Nutzung von PatchBukkit setzt eine installierte Java-Laufzeitumgebung (JRE/JDK) auf dem Hostsystem voraus, um die eingebettete JVM auszuführen.
---
## 3. Konfiguration & Eigenschaften
Pumpkin verwendet TOML-Konfigurationsdateien anstelle von `server.properties` und YAML:
| Paper / Spigot (`server.properties`) | Pumpkin (`pumpkin.toml`) |
| :--- | :--- |
| `server-port=25565` | `server_address = "0.0.0.0:25565"` |
| `motd=...` | `motd = "A Pumpkin Server"` |
| `max-players=20` | `max_players = 20` |
| `online-mode=true` | `online_mode = true` |
| `view-distance=10` | `view_distance = 10` |
| `simulation-distance=8` | `simulation_distance = 8` |
---
## 4. Welt- & Datenspeicherung
- **Formatkompatibilität**: Pumpkin liest das standardmäßige Anvil-Chunk-Format (`.mca`-Dateien).
- **Verzeichnisstruktur**: Achte beim Kopieren von Welten aus bestehenden Paper-/Spigot-Installationen darauf, dass die Dimensionsverzeichnisse (`world`, `world_nether`, `world_the_end`) der erwarteten Pumpkin-Struktur entsprechen.
- **Aktuellstes Welt- & Datapack-Format erforderlich**: Zumindest derzeit unterstützt Pumpkin nur das jeweils aktuellste Weltformat und Datapack-Format der unterstützten Minecraft-Version. Ältere Weltformate oder veraltete Datapack-Versionen werden zur Laufzeit nicht automatisch konvertiert.
- **Welten im Client aktualisieren**: Wenn du eine ältere Welt migrierst, aktualisiere sie vor dem Laden in Pumpkin. Du kannst eine bestehende Welt direkt im offiziellen Minecraft-Client upgraden: Öffne den Client in der passenden aktuellen Version, gehe auf **Einzelspieler**, wähle die Welt aus, klicke auf **Bearbeiten** und wähle **Welt optimieren**. Alternativ kannst du die Welt einmalig auf einem Vanilla-Server der aktuellen Version starten und speichern.
- **Datapacks**: Stelle sicher, dass alle Datapacks unter `world/datapacks` auf das von der Zielversion erwartete Format aktualisiert wurden.
---
## 5. Serverstart & JVM-Flags
### Keine Java-Installation erforderlich
Ein reiner Pumpkin-Server ist eine eigenständige native Binärdatei. Du benötigst keine Java-Laufzeitumgebung (JRE/JDK) auf deinem System oder im Container, um den Server auszuführen.
### Startbefehle
Paper- und Spigot-Server nutzen üblicherweise JVM-Startskripte mit Heap-Allokation und Flags zur Steuerung der Garbage Collection (wie z. B. Aikars Flags):
:::code-group
```bash [Paper (JVM)]
# Typischer Paper-Startbefehl mit Aikars Flags:
java -Xms10G -Xmx10G \
-XX:+UseG1GC \
-XX:+ParallelRefProcEnabled \
-XX:MaxGCPauseMillis=200 \
-XX:+UnlockExperimentalVMOptions \
-XX:+DisableExplicitGC \
-XX:+AlwaysPreTouch \
-XX:G1NewSizePercent=30 \
-XX:G1MaxNewSizePercent=40 \
-XX:G1HeapRegionSize=8M \
-XX:G1ReservePercent=20 \
-XX:G1HeapWastePercent=5 \
-XX:G1MixedGCCountTarget=4 \
-XX:InitiatingHeapOccupancyPercent=15 \
-XX:G1MixedGCLiveThresholdPercent=90 \
-XX:G1RSetUpdatingPauseTimePercent=5 \
-XX:SurvivorRatio=32 \
-XX:+PerfDisableSharedMem \
-XX:MaxTenuringThreshold=1 \
-Dusing.aikars.flags=https://mcflags.emc.gs \
-Daikars.new.flags=true \
-jar paper.jar --nogui
```
```bash [Pumpkin (Nativ)]
# Linux / macOS:
./pumpkin
# Windows:
./pumpkin.exe
# Docker:
docker run -p 25565:25565 -v ./data:/data pumpkinmc/pumpkin:latest
```
:::
### Unterschiede im Speichermodell
- **Keine Garbage Collection**: Pumpkin ist in Rust geschrieben und nutzt deterministisches Speichermanagement zur Kompilierzeit (RAII). Es gibt keinen Laufzeit-Garbage-Collector und keine GC-Pausenoptimierung.
- **Keine feste Heap-Reservierung**: Flags wie `-Xms` und `-Xmx` existieren bei nativen Binärdateien nicht. Speicher wird bei Bedarf dynamisch vom Betriebssystem angefordert und beim Entladen von Chunks und Entities wieder freigegeben.
- **JVM-Flags nicht anwendbar**: Flags zur Steuerung der Garbage Collection, Generationsgrößen oder JVM-Interna sind nicht erforderlich und können dem Programm nicht übergeben werden.
---
## Admin-Checkliste
1. [ ] Sichere deine bestehenden Serverdaten und erstelle ein Backup, wobei Welt und Datapacks auf das aktuellste Format aktualisiert sein sollten (z. B. via „Welt optimieren“ im Client).
2. [ ] Übertrage Einstellungen aus `server.properties` in die `pumpkin.toml`.
3. [ ] Identifiziere benötigte Plugins und prüfe WebAssembly-Alternativen (`.wasm`) oder teste mit [PatchBukkit](#bukkit-plugin-kompatibilitat-patchbukkit).
4. [ ] Konfiguriere Proxy-Einstellungen (`Velocity` / `BungeeCord`) in der `pumpkin.toml`, falls ein Netzwerk betrieben wird.
5. [ ] Passe Startskripte an, um `./pumpkin` direkt ohne JVM-Argumente aufzurufen.
6. [ ] Starte den Server und überprüfe die Verbindung sowie die Protokolle.

50
docs/de/config/bedrock.md Normal file
View File

@ -0,0 +1,50 @@
# Bedrock & NetherNet
Pumpkin bietet native Unterstützung für Minecraft Bedrock Edition-Clients, einschließlich des NetherNet-WebRTC/ICE-Transports und Anpassungen für Benutzernamen.
## Konfiguration
:::code-group
```toml [pumpkin.toml]
[networking.bedrock]
enabled = true
online_mode = true
max_players = 1000
view_distance = 16
simulation_distance = 10
motd = "A blazingly fast Pumpkin server!"
username_prefix = ""
replace_username_spaces = true
chunk_caching = true
[networking.bedrock.nethernet]
enabled = true
address = "0.0.0.0:19132"
identity_key = "nethernet-key.der"
stun_servers = []
```
:::
### Bedrock-Optionen
- **`enabled`**: Gibt an, ob Verbindungen von Bedrock-Edition-Clients akzeptiert werden (Standard: `true`).
- **`online_mode`**: Gibt an, ob die Xbox-Live-Authentifizierung für Bedrock-Spieler erzwungen wird (Standard: `true`).
- **`max_players`**: Maximale Anzahl gleichzeitiger Bedrock-Spieler (`0` deaktiviert das Limit, Standard: `1000`).
- **`view_distance`**: Maximale Chunk-Sichtweite, die an Bedrock-Clients gesendet wird (Standard: `16`).
- **`simulation_distance`**: Maximale Tick-Simulationsdistanz für Bedrock-Spieler (Standard: `10`).
- **`motd`**: „Message of the Day“, die in der Bedrock-Serverliste angezeigt wird.
- **`username_prefix`**: Optionales Präfix, das Bedrock-Spieler-Gamertags vorangestellt wird (z. B. `"."` oder `"*"`), um Namenskollisionen mit Java-Edition-Accounts auf Crossplay-Servern zu verhindern (Standard: `""`).
- **`replace_username_spaces`**: Gibt an, ob Leerzeichen in Bedrock-Gamertags automatisch durch Unterstriche `_` ersetzt werden, damit Spielernamen in Minecraft-Befehlen verwendet werden können (Standard: `true`).
- **`chunk_caching`**: Gibt an, ob clientseitiges Chunk-Blob-Caching aktiviert ist, um Netzwerkbandbreite zu sparen (Standard: `true`).
### NetherNet-Transporteinstellungen
NetherNet ist der moderne WebRTC/ICE-Netzwerktransport von Minecraft Bedrock:
- **`enabled`**: Gibt an, ob sich Clients über NetherNet verbinden dürfen (Standard: `true`).
- **`address`**: Netzwerk-Socket-Adresse für TCP-Signalisierung und UDP-ICE-Multiplexing (Standard: `"0.0.0.0:19132"`).
- **`external_ip`**: Optionale öffentliche IP-Adresse, die angekündigt wird, wenn der Server hinter NAT betrieben wird.
- **`identity_key`**: Dateipfad zur privaten PKCS#8-P-384-Identitätsschlüsseldatei, die über Server-Neustarts hinweg für Trust On First Use (TOFU) des Clients erhalten bleibt (Standard: `"nethernet-key.der"`).
- **`stun_servers`**: Optionale Liste von STUN-Server-URLs für das ICE-NAT-Traversal.

39
docs/de/config/chat.md Normal file
View File

@ -0,0 +1,39 @@
# Chat & Anti-Spam
Pumpkin bietet anpassbare In-Game-Chatformatierung und einen integrierten Anti-Spam-Schutz unter `[chat]` in `pumpkin.toml`.
## Konfiguration
:::code-group
```toml [pumpkin.toml]
[chat]
format = "<{DISPLAYNAME}> {MESSAGE}"
[chat.anti_spam]
enabled = true
spam_threshold = 200
message_cost = 20
decay_per_tick = 1
ops_bypass = true
```
:::
### Chat-Einstellungen
- **`format`**: Das Format für Chatnachrichten (Standard: `"<{DISPLAYNAME}> {MESSAGE}"`).
- `{DISPLAYNAME}`: Anzeigename des Spielers.
- `{MESSAGE}`: Text der Chatnachricht.
> [!NOTE]
> Eine benutzerdefinierte Chatformatierung wird nicht angewendet, wenn sichere Chat-Meldungen (`allow_chat_reports = true`) aktiviert sind.
### Anti-Spam-Schutz
Pumpkin implementiert einen Leaky-Bucket-Spam-Zähler, um den Server vor spammenden Spielern und Bot-Floods zu schützen:
- **`enabled`**: Gibt an, ob der Anti-Spam-Schutz aktiv ist (Standard: `true`).
- **`spam_threshold`**: Der Schwellenwert des Spam-Zählers in Ticks, ab dem ein Spieler gekickt wird (Standard: `200` Ticks).
- **`message_cost`**: Der Wert, der dem Spam-Zähler des Spielers für jede gesendete Chatnachricht oder jeden Befehl hinzugefügt wird (Standard: `20` Ticks).
- **`decay_per_tick`**: Der Wert, um den der Spam-Zähler des Spielers mit jedem Server-Tick abgebaut wird (Standard: `1` Tick).
- **`ops_bypass`**: Gibt an, ob Server-Operatoren von Anti-Spam-Prüfungen ausgenommen sind (Standard: `true`).

View File

@ -0,0 +1,30 @@
# Paket-Begrenzer
Pumpkin verfügt über einen integrierten Paketratenbegrenzer, um den Server vor Paket-Flooding, Spam-Angriffen und clientseitigen Exploits zu schützen. Paketratenlimits können für Java Edition- und Bedrock Edition-Clients unabhängig voneinander konfiguriert werden.
## Konfiguration
:::code-group
```toml [pumpkin.toml]
[networking.java.packet_limiter]
enabled = true
max_packet_rate = 500.0
burst_capacity = 500.0
kick_message = "Kicked for spamming packets"
[networking.bedrock.packet_limiter]
enabled = true
max_packet_rate = 500.0
burst_capacity = 500.0
kick_message = "Kicked for spamming packets"
```
:::
### Konfigurationsoptionen
- **`enabled`**: Gibt an, ob der Paketratenbegrenzer für diese Client-Edition aktiviert ist (Standard: `true`).
- **`max_packet_rate`**: Maximal erlaubte eingehende Pakete pro Sekunde und Client-Verbindung (Standard: `500.0`). Setze den Wert auf `<= 0.0`, um das Ratenlimit zu deaktivieren, ohne das Begrenzungsmodul zu deaktivieren.
- **`burst_capacity`**: Token-Bucket-Burst-Kapazität für kurze Spitzen beim Paketaufkommen des Clients (Standard: `500.0`).
- **`kick_message`**: Die Trennungsnachricht, die dem Spieler angezeigt wird, wenn seine Verbindung das Paketlimit überschreitet (Standard: `"Kicked for spamming packets"`).

View File

@ -0,0 +1,41 @@
# Spielerdaten & Gameplay
Einstellungen zum Speichern persistenter Spielerdaten, Fortschritte (Advancements), Rezept-Synchronisation und saisonaler Späße werden in `pumpkin.toml` vorgenommen.
## Konfiguration
:::code-group
```toml [pumpkin.toml]
[player_data]
save_player_data = true
save_player_cron_interval = 300
[advancement]
save_advancements = true
[recipe]
send_recipes = true
[fun]
april_fools = true
```
:::
### Spielerdaten
- **`save_player_data`**: Gibt an, ob persistente Spielerdaten (Inventar, Position, Gesundheit) auf der Festplatte gespeichert werden (Standard: `true`).
- **`save_player_cron_interval`**: Zeitintervall in Sekunden zwischen automatischen periodischen Speicherungen der Daten von Online-Spielern (Standard: `300` Sekunden / 5 Minuten).
### Fortschritte (Advancements)
- **`save_advancements`**: Gibt an, ob der Fortschritt von Spielern bei Fortschritten/Erfolgen erfasst und auf der Festplatte gespeichert wird (Standard: `true`).
### Rezepte
- **`send_recipes`**: Gibt an, ob Werk- und Schmelzrezepte mit verbundenen Clients synchronisiert werden, wodurch das clientseitige Rezeptbuch aktiviert wird (Standard: `true`).
### Spaßfunktionen
- **`april_fools`**: Gibt an, ob lustige und saisonale Aprilscherz-Easter-Eggs und Features aktiviert sind (Standard: `true`).

59
docs/de/config/plugins.md Normal file
View File

@ -0,0 +1,59 @@
# Plugins
Pumpkin bietet eine WebAssembly (WASM)-Plugin-Laufzeitumgebung mit fähigkeitenbasierter Sicherheit (Capability-based Security). Das Verhalten von Plugins, Signaturverifizierung und Berechtigungen werden unter `[plugins]` in `pumpkin.toml` konfiguriert.
## Konfiguration
:::code-group
```toml [pumpkin.toml]
[plugins]
enabled = true
hot_reload = false
ask_permission_confirmation = true
allow_unsigned = true
allowed_permissions = []
blocked_permissions = []
inherit_env = false
loopback_only = false
verify_signatures = true
# Optional per-plugin overrides
[plugins.overrides.my_plugin]
enabled = true
allow_unsigned = true
max_memory_mb = 128
allowed_permissions = ["fs:read:data"]
blocked_permissions = ["network:outbound"]
loopback_only = true
[plugins.overrides.my_plugin.environment]
API_KEY = "example_secret"
```
:::
### Globale Plugin-Einstellungen
- **`enabled`**: Hauptschalter zum Aktivieren oder Deaktivieren der Plugin-Laufzeitumgebung (Standard: `true`).
- **`hot_reload`**: Überwacht das `plugins/`-Verzeichnis und lädt geänderte Plugins zur Laufzeit automatisch neu (Standard: `false`).
- **`ask_permission_confirmation`**: Fragt in der Serverkonsole nach Bestätigung, wenn ein Plugin nicht vorab genehmigte Berechtigungen anfordert (Standard: `true`).
- **`allow_unsigned`**: Erlaubt das Laden von unsignierten WASM-Plugins (Standard: `true`).
- **`allowed_permissions`**: Liste von Berechtigungen, die global für alle Plugins vorab genehmigt sind, wodurch interaktive Konsolenabfragen übersprungen werden (Standard: `[]`).
- **`blocked_permissions`**: Liste von Berechtigungen, die für alle Plugins global verweigert werden (Standard: `[]`).
- **`inherit_env`**: Gibt an, ob Umgebungsvariablen des Hosts standardmäßig in die WASI-Sandboxen der Plugins vererbt werden (Standard: `false`).
- **`loopback_only`**: Gibt an, ob ausgehende Netzwerkverbindungen von Plugins auf `127.0.0.1` / localhost beschränkt sind (Standard: `false`).
- **`max_memory_mb`**: (Optional) Globales maximales Speicherlimit in Megabyte (MB) pro Plugin-Instanz.
- **`verify_signatures`**: Gibt an, ob Pumpkin kryptografische Signaturen von WASM-Plugins vor dem Laden überprüft (Standard: `true`).
### Plugin-spezifische Überschreibungen
Berechtigungen und Umgebungsvariablen für bestimmte Plugins können unter `[plugins.overrides.<plugin_name>]` fein abgestimmt werden:
- **`enabled`**: Aktiviert oder deaktiviert dieses spezifische Plugin (Standard: `true`).
- **`allow_unsigned`**: Überschreibt, ob dieses spezifische Plugin unsigniert ausgeführt werden darf (`true`/`false`).
- **`max_memory_mb`**: Maximales Speicherlimit in MB, das speziell für dieses Plugin zugewiesen wird.
- **`allowed_permissions`**: Vorab genehmigte Berechtigungen für dieses Plugin.
- **`blocked_permissions`**: Explizit blockierte Berechtigungen für dieses Plugin.
- **`loopback_only`**: Überschreibt die Loopback-Netzwerkbeschränkung für dieses Plugin.
- **`environment`**: Tabelle benutzerdefinierter Umgebungsvariablen, die direkt an die WASI-Umgebung des Plugins übergeben werden.

View File

@ -0,0 +1,50 @@
# Server-Links
Minecraft-Clients können (seit Version 1.21) anklickbare Server-Links im Pausenmenü und in den Spielmenüs anzeigen. Standardmäßige und benutzerdefinierte Server-Links werden unter `[server_links]` in `pumpkin.toml` konfiguriert.
## Konfiguration
:::code-group
```toml [pumpkin.toml]
[server_links]
enabled = true
bug_report = "https://github.com/Pumpkin-MC/Pumpkin/issues"
support = ""
status = ""
feedback = ""
community = ""
website = ""
forums = ""
news = ""
announcements = ""
[server_links.custom]
# "Store" = "https://store.example.com"
# "Discord" = "https://discord.gg/example"
```
:::
### Konfigurationsoptionen
- **`enabled`**: Hauptschalter zum Aktivieren der Übertragung von Server-Links an sich verbindende Clients (Standard: `true`).
- **`bug_report`**: Link zum Bug-Tracker des Servers oder Projekts (Standard: `"https://github.com/Pumpkin-MC/Pumpkin/issues"`).
- **`support`**: Link zum technischen Support oder Helpdesk.
- **`status`**: Link zur Server-Uptime- oder Statusseite.
- **`feedback`**: Link zu einer Seite für Spieler-Feedback oder Vorschläge.
- **`community`**: Link zu Community-Foren oder -Gruppen.
- **`website`**: Link zur offiziellen Webseite.
- **`forums`**: Link zu Diskussionsforen.
- **`news`**: Link zum Server-Blog oder zur News-Seite.
- **`announcements`**: Link zur Ankündigungsseite.
### Benutzerdefinierte Links
Beliebige Key-Value-Links, die in den Client-Menüs angezeigt werden, können unter `[server_links.custom]` definiert werden:
```toml
[server_links.custom]
"Store" = "https://store.example.com"
"Discord" = "https://discord.gg/example"
```

41
docs/de/config/world.md Normal file
View File

@ -0,0 +1,41 @@
# Welt
Pumpkin ermöglicht die Feinabstimmung von Weltspeicherformaten, automatischen Speicherintervallen (Autosave) und Beleuchtungsmodi unter `[world]` in `pumpkin.toml`.
## Konfiguration
:::code-group
```toml [pumpkin.toml]
[world]
lighting = "default"
autosave_ticks = 6000
[world.chunk]
type = "anvil"
write_in_place = false
[world.chunk.compression]
algorithm = "LZ4"
level = 6
```
:::
### Welteinstellungen
- **`lighting`**: Berechnungsmodus für die Lichtausbreitung der Beleuchtungs-Engine.
- `"default"`: Standardmäßige Vanilla-Minecraft-Lichtausbreitung.
- `"full"`: Durchgehend volles Himmelslicht überall ohne Schatten.
- `"dark"`: Vollständig dunkle Beleuchtung überall (kein Licht).
- **`autosave_ticks`**: Anzahl der Server-Ticks zwischen automatischen Weltspeicherungen (Standard: `6000`, entspricht 5 Minuten bei 20 TPS). Ein Wert von `0` deaktiviert das automatische Speichern der Welt.
### Chunk-Speichereinstellungen
- **`type`**: Das zu verwendende Chunk-Speicherformat:
- `"anvil"`: Standardmäßiges Minecraft-Anvil-Region-Dateiformat (`.mca`).
- `"linear"`: Linear-Region-Speicherformat mit schneller Kompression für einen geringeren Speicherplatzbedarf.
- `"pump"`: Pumpkins natives, optimiertes Weltformat.
- **`write_in_place`**: Gibt an, ob Chunks direkt an Ort und Stelle (in-place) in bestehende Regionsdateien überschrieben werden sollen, anstatt freie Chunks neu zuzuweisen (Standard: `false`).
- **`compression.algorithm`**: Kompressionsalgorithmus für Chunk-Daten (`"LZ4"`, `"ZLib"`, `"GZip"`, `"Custom"`).
- **`compression.level`**: Kompressionsstufe für die Chunk-Speicherung (Standard: `6`).

View File

@ -0,0 +1,139 @@
# Pumpkin Architecture & Crates
Pumpkin is organized as a modular Cargo workspace composed of specialized crates. Each crate has distinct responsibilities, strictly defined boundaries, and minimal cross-dependencies.
This architecture enables high parallel compilation speeds, isolated testing, zero-cost data sharing, and clean separation between network protocols, game logic, and world management.
---
## Workspace Crate Overview
### Workspace Architecture at a Glance
| Layer | Crates | Responsibilities |
| :--- | :--- | :--- |
| **Core Runtime** | `pumpkin` | Game loop, world ticking, player sessions, entity management, and event loops |
| **Networking & Protocols** | `pumpkin-protocol`, `pumpkin-auth`, `pumpkin-nbt` | Java/Bedrock packet serialization, Yggdrasil & Xbox Live authentication, SNBT |
| **World & Gameplay** | `pumpkin-world`, `pumpkin-inventory`, `pumpkin-command` | Region I/O (Anvil/Linear), terrain generation, block ticking, containers, Brigadier tree |
| **Extensibility** | `pumpkin-plugin-runtime`, `pumpkin-host-bindings`, `pumpkin-plugin-api`, `pumpkin-plugin-wit` | WebAssembly plugin execution via Wasmtime, WIT host APIs, native and WASM loaders |
| **Foundations** | `pumpkin-data`, `pumpkin-config`, `pumpkin-util` | Code-generated registries, typed configuration files, mathematical vectors, permissions |
---
## Detailed Crate Breakdown
### 1. `pumpkin` (Core Server)
- **Path**: `crates/pumpkin`
- **Purpose**: The main server binary and centralized orchestration engine.
- **Responsibilities**:
- Initializes configuration, logging (`tracing`), and telemetry.
- Spawns Tokio network listeners for Minecraft: Java Edition, Bedrock Edition, RCON, Query, and LAN broadcast.
- Manages the server tick loop (`Server::tick`), coordinating world updates, player actions, entity movements, and chunk broadcasting.
- Dispatches incoming client packets through `crates/pumpkin/src/net/java/` and `net/bedrock/`.
- Integrates the plugin manager, firing event handlers before and after packet processing.
### 2. `pumpkin-protocol` (Network Protocol)
- **Path**: `crates/pumpkin-protocol`
- **Purpose**: High-speed network wire format serialization and deserialization for Minecraft Java and Bedrock editions.
- **Responsibilities**:
- Implements the `ClientPacket` (serialization) and `ServerPacket` (deserialization) traits.
- Handles protocol primitives: `VarInt`, `VarLong`, UUIDs, NBT compounds, and string codecs.
- Implements packets across all states: `Handshake`, `Status`, `Login`, `Config`, and `Play`.
- Provides packet compression (ZLib/Fast compression) and packet encryption (AES-128/CFB8).
- Encapsulates RCON and GameSpy4 Query protocols.
### 3. `pumpkin-world` (World & Chunks)
- **Path**: `crates/pumpkin-world`
- **Purpose**: World loading, saving, terrain generation, and chunk management.
- **Responsibilities**:
- Supports multiple chunk storage formats:
- **Vanilla Anvil (`.mca`)**: Reading and writing standard region files.
- **Linear (`.linear`)**: High-efficiency zstd-compressed region format saving 50–95% disk space.
- **Slime (`.slime`)**: Single-file world format.
- **Pump**: Native Pumpkin chunk storage format.
- Implements world generation pipelines: Perlin noise heightmaps, 3D noise routers, biome climate parameters, placed features, carvers, and superflat terrain.
- Manages block lighting and sky lighting propagation.
- Coordinates chunk loading, unloading, and streaming via cylindrical chunk iterators.
### 4. `pumpkin-data` (Minecraft Datasets & Registries)
- **Path**: `crates/pumpkin-data`
- **Purpose**: Compile-time static registries and data tables generated directly from vanilla Minecraft assets and reports.
- **Responsibilities**:
- Contains complete ID mappings, properties, and definitions for blocks, items, biomes, entities, sounds, particles, enchantments, and recipes.
- Packet ID lookups across multiple Minecraft protocol versions.
- Zero-cost lookup tables generated by `tools/pumpkin-codegen`.
### 5. `pumpkin-config` (Configuration Management)
- **Path**: `crates/pumpkin-config`
- **Purpose**: TOML configuration parsing, serialization, and validation.
- **Responsibilities**:
- Loads and writes `pumpkin.toml`.
- Configures server ports, compression thresholds, proxy modes, resource packs, logging levels, world settings, and Bedrock integration.
- Provides safe defaults and schema validations.
### 6. `pumpkin-inventory` (Inventory & Containers)
- **Path**: `crates/pumpkin-inventory`
- **Purpose**: Server-side container window handlers and inventory mechanics.
- **Responsibilities**:
- Manages player inventory, chest containers, crafting tables, furnaces, and villager trading screens.
- Validates client slot clicks, drag operations, item stacking, and item splitting.
- Coordinates window packet synchronization to ensure client inventory fidelity.
### 7. `pumpkin-command` (Command Dispatcher)
- **Path**: `crates/pumpkin-command`
- **Purpose**: Brigadier-inspired hierarchical command tree dispatcher and parser.
- **Responsibilities**:
- Constructs modular command trees with typed arguments (`Integer`, `Float`, `Entity`, `BlockPos`, etc.).
- Executes permission-checked commands.
- Provides real-time autocompletion suggestions sent to connected clients.
### 8. `pumpkin-auth` (Authentication & Session Verification)
- **Path**: `crates/pumpkin-auth`
- **Purpose**: Cryptographic authentication and player identity verification.
- **Responsibilities**:
- Validates client sessions with Mojang's Yggdrasil authentication servers.
- Handles RSA keypair generation and shared secret exchange during the Login state.
- Supports offline-mode UUID generation and custom authentication endpoints.
- Implements proxy forwarding protocols: [BungeeCord](https://github.com/SpigotMC/BungeeCord), [BungeeGuard](https://github.com/lucko/BungeeGuard), and [Velocity](https://github.com/PaperMC/Velocity) modern forwarding with HMAC-SHA256 signatures.
### 9. `pumpkin-nbt` (Named Binary Tag Codec)
- **Path**: `crates/pumpkin-nbt`
- **Purpose**: High-throughput binary NBT parser and serializer.
- **Responsibilities**:
- Parses and encodes all standard NBT tag types (`Byte`, `Short`, `Int`, `Long`, `Float`, `Double`, `ByteArray`, `String`, `List`, `Compound`, `IntArray`, `LongArray`).
- Supports compression layers: Gzip, Zlib, and uncompressed Network NBT.
### 10. `pumpkin-plugin-*` (Extensibility Infrastructure)
- **Paths**:
- `crates/pumpkin-plugin-api`: The Rust developer SDK for compiling native plugins.
- `crates/pumpkin-plugin-runtime`: Wasmtime-powered WebAssembly execution host.
- `crates/pumpkin-plugin-wit`: WebAssembly Interface Type (WIT) specifications.
- `crates/pumpkin-host-bindings`: Auto-generated host bindings connecting Wasmtime and the server core.
- **Purpose**: Enables safe, polyglot plugin execution (Rust, Python, C#, C, Go, Kotlin) with sandboxed memory and near-native performance.
### 11. `pumpkin-util` & `pumpkin-macros` (Foundations)
- **Paths**: `crates/pumpkin-util`, `crates/pumpkin-macros`, `crates/pumpkin-api-macros`
- **Purpose**: Foundational types, shared algorithms, and procedural macros.
- **Responsibilities**:
- Mathematical utilities: `Vector2`, `Vector3`, `BoundingBox`, and angle conversions.
- Text and chat formatting: `TextComponent` and JSON component serialization.
- Procedural macros such as `#[java_packet(...)]` that bind packet structs to protocol IDs and packet traits.
### 12. `tools/` (Developer Tooling)
- **`tools/pumpkin-codegen`**: Automated code generator that parses Minecraft version jars, data reports, and asset archives to emit Rust source files into `pumpkin-data`.
- **`tools/pumpkin-fuzzer`**: Fuzz testing suites for network packet parsers, NBT readers, and region file decoders to identify potential crash vectors or memory anomalies.
---
## Concurrency & Threading Model
| Component | Runtime / Pool | Primary Workload | Communication Mechanism |
| :--- | :--- | :--- | :--- |
| **Network & Socket I/O** | Tokio Async Runtime | TCP packet reads, Bedrock UDP packets, framing, session handshakes | Async tasks (`tokio::spawn`), non-blocking reactors |
| **Heavy Compute** | Rayon Thread Pool | Terrain generation, noise routers, light propagation, chunk compression | Worker threads via crossbeam / Rayon iterators |
| **Inter-Thread Bridge** | Tokio Channels | Dispatching completed chunks and encoded packets back to network tasks | Non-blocking `tokio::sync::mpsc` channels |
Pumpkin strictly adheres to this separation of concerns:
- **I/O Bound**: Managed on Tokio asynchronous tasks.
- **CPU Bound**: Managed on Rayon thread pools.
- **Communication**: Coordinated via cross-thread channels (`tokio::sync::mpsc`) without ever blocking the Tokio reactor loop.

View File

@ -0,0 +1,182 @@
# Adding a Block Behavior
This guide walks through implementing interactive behavior for a block in Pumpkin.
---
## When Is a Behavior Needed?
- **Non-Interactive Blocks** (e.g., stone, dirt, terracotta): Do **not** require any custom Rust code. Their breaking speeds, hardness, and placement properties are automatically derived from `pumpkin-data`.
- **Interactive or Functional Blocks** (e.g., doors, chests, levers, crops, campfires, TNT): Require an implementation of the `BlockBehaviour` trait to respond to player clicks, redstone signals, physics steps, or timer ticks.
---
## Step 1: Create the Behavior Struct
Create a new file under `crates/pumpkin/src/block/blocks/<category>/<block_name>.rs` (or directly in `crates/pumpkin/src/block/blocks/`).
Use the `#[pumpkin_block(...)]` macro to associate your behavior struct with one or more vanilla block identifiers:
```rust
use std::sync::Arc;
use pumpkin_data::Block;
use pumpkin_data::block_properties::{DoorLikeProperties, Facing};
use pumpkin_macros::pumpkin_block;
use pumpkin_util::math::position::BlockPos;
use crate::block::registry::BlockActionResult;
use crate::block::{
BlockBehaviour, NormalUseArgs, OnNeighborUpdateArgs, PlacedArgs, UseWithItemArgs,
};
use crate::world::World;
/// Associates this behavior struct with one or multiple block IDs.
#[pumpkin_block([
"minecraft:oak_door",
"minecraft:iron_door",
"minecraft:spruce_door",
"minecraft:birch_door"
])]
pub struct DoorBlock;
impl BlockBehaviour for DoorBlock {
fn normal_use(&self, args: NormalUseArgs<'_>) -> BlockActionResult {
let state_id = args.world.get_block_state(args.location).await;
// Iron doors require redstone power and cannot be opened manually by hand
if args.block.id == pumpkin_data::Block::IRON_DOOR.id {
return BlockActionResult::Pass;
}
// Toggle open state
let is_open = DoorLikeProperties::open(state_id);
let new_state = DoorLikeProperties::with_open(state_id, !is_open);
args.world.set_block_state(args.location, new_state).await;
BlockActionResult::Consume
}
fn on_neighbor_update(&self, args: OnNeighborUpdateArgs<'_>) {
// Handle neighbor redstone signals or support block destruction
}
}
```
---
## Step 2: `BlockBehaviour` Hook Reference
The `BlockBehaviour` trait exposes lifecycle hooks modeled on vanilla mechanics:
### Player & Item Interaction Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `normal_use` | `(&self, args: NormalUseArgs<'_>) -> BlockActionResult` | Triggered when right-clicking the block with an empty hand. |
| `use_with_item` | `(&self, args: UseWithItemArgs<'_>) -> BlockActionResult` | Triggered when right-clicking the block while holding an item. |
| `get_screen_handler_factory` | `(&self, args: GetScreenHandlerFactoryArgs<'_>) -> Option<Box<dyn ScreenHandlerFactory>>` | Returns an inventory container factory to open a UI screen (e.g., Chests, Crafting Tables). |
### World Lifecycle & Physics Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `placed` | `(&self, args: PlacedArgs<'_>)` | Triggered immediately after the block is placed in the world. |
| `broken` | `(&self, args: BrokenArgs<'_>)` | Triggered when broken by a player or game mechanics. |
| `on_entity_collision` | `(&self, args: OnEntityCollisionArgs<'_>)` | Triggered when an entity walks inside, steps on, or falls into the block. |
| `on_neighbor_update` | `(&self, args: OnNeighborUpdateArgs<'_>)` | Triggered when an adjacent block state updates or is destroyed. |
| `on_projectile_hit` | `(&self, args: OnProjectileHitArgs<'_>)` | Triggered when an arrow, snowball, or projectile strikes the block. |
### Redstone & Power Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `emits_redstone_power` | `(&self, state_id: BlockStateId) -> bool` | Declares whether the block emits redstone power to neighbors. |
| `get_weak_redstone_power` | `(&self, ...) -> u8` | Returns emitted weak power level (0–15). |
| `get_strong_redstone_power` | `(&self, ...) -> u8` | Returns emitted strong direct power level (0–15). |
### Foliage & Bonemeal Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `is_valid_bonemeal_target` | `(&self, args: BonemealArgs<'_>) -> bool` | Checks if bone meal can be applied (e.g., crop not fully grown). |
| `is_bonemeal_success` | `(&self, args: BonemealArgs<'_>) -> bool` | Evaluates random chance roll for bone meal success. |
| `perform_bonemeal` | `(&self, args: BonemealArgs<'_>)` | Advances growth stages or spawns adjacent flora. |
---
## Step 3: Modifying Block States
All block properties are strongly typed in `pumpkin_data::block_properties`:
```rust
use pumpkin_data::block_properties::{BedLikeProperties, Part};
// 1. Read typed properties from the numeric BlockStateId
let part = BedLikeProperties::part(state_id); // Part::Head or Part::Foot
let is_occupied = BedLikeProperties::occupied(state_id);
// 2. Generate a new BlockStateId with updated properties
let updated_state = BedLikeProperties::with_occupied(state_id, true);
// 3. Commit the updated state to the world
world.set_block_state(pos, updated_state).await;
```
---
## Step 4: Adding a Block Entity (Tile Entity)
If your block needs to store persistent custom state (inventories, custom text, timers):
1. Create a block entity struct in `crates/pumpkin/src/block/entities/`:
```rust
use pumpkin_util::math::position::BlockPos;
use crate::block::entities::BlockEntity;
pub struct CustomBlockEntity {
pub pos: BlockPos,
pub custom_counter: u32,
}
impl BlockEntity for CustomBlockEntity {
fn to_nbt(&self) -> pumpkin_nbt::compound::NbtCompound {
let mut compound = pumpkin_nbt::compound::NbtCompound::new();
compound.put_int("Counter", self.custom_counter as i32);
compound
}
fn from_nbt(&mut self, tag: &pumpkin_nbt::compound::NbtCompound) {
if let Some(val) = tag.get_int("Counter") {
self.custom_counter = val as u32;
}
}
fn tick(&mut self, world: &std::sync::Arc<crate::world::World>, pos: &BlockPos) {
// Periodic logic per game tick
}
}
```
2. Link the block entity in your `BlockBehaviour`:
```rust
impl BlockBehaviour for CustomBlock {
fn create_block_entity(&self, pos: BlockPos) -> Option<Arc<Mutex<dyn BlockEntity>>> {
Some(Arc::new(Mutex::new(CustomBlockEntity::new(pos))))
}
}
```
---
## Step 5: Registering the Block
1. Export your module in `crates/pumpkin/src/block/blocks/mod.rs`:
```rust
pub mod doors;
```
2. Register the behavior struct in `crates/pumpkin/src/block/registry.rs`:
```rust
manager.register(DoorBlock);
```
At startup, `manager.register` automatically reads the block IDs declared in `#[pumpkin_block(...)]` and routes interactions to your implementation.

View File

@ -0,0 +1,104 @@
# Block Architecture & State System
Blocks form the static and dynamic foundation of Minecraft worlds. In Pumpkin, block handling is cleanly bifurcated into two distinct layers:
1. **Static Data Layer ([`pumpkin-data`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-data))**: Compile-time generated metadata including numeric block IDs, block state IDs, hardness, blast resistance, light emission, opacity, collision shapes, and block state properties generated by [`pumpkin-codegen`](/developer/codegen).
2. **Dynamic Behavior Layer ([`pumpkin::block`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin/src/block))**: Server-side behavioral hooks—such as opening containers, toggling redstone signals, growing crops, breaking triggers, and collision effects—handled via the `BlockBehaviour` trait.
---
## Static Blocks vs. Interactive Behaviors
Because Minecraft contains thousands of block state combinations, Pumpkin avoids allocating runtime behavior structs for simple, non-interactive blocks:
| Category | Description | Examples | Runtime Behavior Required? |
| :--- | :--- | :--- | :--- |
| **Static Blocks** | Rigid solid voxels without interactive logic or custom physics | `stone`, `dirt`, `cobblestone`, `bedrock`, `obsidian` | No — Placement, breaking times, and tool requirements are handled entirely by `pumpkin-data`. |
| **Interactive Blocks** | Blocks triggered by right-clicks or tool actions | `door`, `trapdoor`, `lever`, `button`, `crafting_table` | Yes — Implements `BlockBehaviour::normal_use` or `use_with_item`. |
| **Collision Blocks** | Blocks that modify entity movement or apply forces | `honey_block`, `slime_block`, `soul_sand`, `powder_snow` | Yes — Implements `on_entity_collision` or `on_landed_upon`. |
| **Redstone Components** | Power sources, conductors, and logic gates | `redstone_wire`, `repeater`, `comparator`, `observer` | Yes — Implements `emits_redstone_power` and `on_neighbor_update`. |
| **Block Entities** | Blocks with persistent, serialized custom states | `chest`, `furnace`, `sign`, `decorated_pot`, `spawner` | Yes — Implements `create_block_entity` and links a `BlockEntity`. |
---
## Block IDs, States, and Properties
Minecraft distinguishes between a **Block** type and a specific **Block State**:
### 1. `BlockId` and `BlockStateId`
- **`BlockId`**: An identifier representing a base block type (e.g., `minecraft:oak_door`).
- **`BlockStateId`**: A 16-bit integer representing a unique combination of block properties (e.g., `minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]`).
In Pumpkin, block data is looked up from precomputed lookup tables in `pumpkin-data`:
```rust
use pumpkin_data::Block;
use pumpkin_data::BlockStateId;
// Access static properties directly from generated data
let door_block = Block::OAK_DOOR;
let default_state_id: BlockStateId = door_block.default_state_id;
let hardness = door_block.hardness;
let blast_resistance = door_block.blast_resistance;
let is_air = door_block.is_air;
```
### 2. Generated State Property Helpers
Rather than parsing raw strings or bitmasks manually, [`pumpkin-codegen`](/developer/codegen) generates strongly typed property helpers in `pumpkin_data::block_properties`:
```rust
use pumpkin_data::block_properties::{DoorLikeProperties, DoubleBlockHalf, Facing};
// Read typed properties from a numeric BlockStateId
let is_open = DoorLikeProperties::open(state_id);
let half = DoorLikeProperties::half(state_id);
let facing = DoorLikeProperties::facing(state_id);
// Generate a new BlockStateId with mutated properties
let toggled_state_id = DoorLikeProperties::with_open(state_id, !is_open);
```
---
## Physics, Bounding Boxes & Raycasting
Pumpkin calculates collision and raycasting bounding boxes directly using pre-baked shapes in `pumpkin-data`:
- **Solid Collisions**: During physics ticks, an entity's axis-aligned bounding box (AABB) is tested against surrounding block collision voxels.
- **Raycasting**: When a player targets a block to place or break, client raycasts are validated against the server-side block outline shapes.
- **Custom Movement Hooks**: Blocks like slime blocks or honey blocks override vertical rebound or horizontal velocity:
- `bounce_entity_after_fall`: Dampens fall damage and multiplies rebound velocity.
- `stop_vertical_movement_after_fall`: Zeros fall velocity upon contact.
---
## Block Entities (Tile Entities)
When a block must store arbitrary dynamic data that cannot fit into standard block state bits (such as container inventories, custom sign text, brewing timers, or mob spawner delays), it uses a **Block Entity**:
| Component | Responsibility | Implementation File |
| :--- | :--- | :--- |
| `BlockEntity` Trait | Defines NBT serialization (`to_nbt`, `from_nbt`) and tick execution | [`crates/pumpkin/src/block/entities/`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin/src/block/entities) |
| `create_block_entity` | Hook in `BlockBehaviour` called when placing the block | Attached to relevant block behaviors |
| Chunk Entity Storage | Manages active block entities and coordinates within chunk sections | [`crates/pumpkin-world`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-world) |
---
## The Block Registry & Dispatch System
Block interaction events are routed through the central `BlockRegistry` in [`crates/pumpkin/src/block/registry.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/block/registry.rs):
1. **Registration**: At server initialization, all behavior structs are registered into the `BlockManager`.
2. **Mapping**: The manager maps numeric `BlockId` keys to thread-safe behavior instances (`Arc<dyn BlockBehaviour>`).
3. **Dispatch**: When the network layer receives block action packets (such as `CUseItemOn` or block dig packets), the server looks up the behavior in $O(1)$ time and invokes the relevant hook.
---
## Next Steps
To implement a new interactive block behavior, continue to the practical guide:
- **[Adding a Block](/developer/blocks/adding-blocks)**: Complete walk-through of declaring attributes, implementing interaction hooks, creating block entities, and registering behaviors.

View File

@ -0,0 +1,66 @@
# Code Generation (`pumpkin-codegen`)
Minecraft is a massive game with thousands of block states, items, packet IDs, sound events, recipes, and biome parameters. These registries frequently change between Minecraft updates.
To maintain 100% fidelity without manually maintaining tens of thousands of error-prone constants, Pumpkin utilizes an automated code generation tool: [`tools/pumpkin-codegen`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/tools/pumpkin-codegen).
---
## Purpose & Workflow
`pumpkin-codegen` parses official Minecraft server data generator reports, asset files, and version specifications, and outputs zero-cost, strongly-typed Rust files directly into [`crates/pumpkin-data`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-data).
The pipeline operates in three distinct stages:
1. **Ingestion**: Reads raw JSON assets and vanilla server reports from `assets/` and `assets/datapacks/`.
2. **Transformation**: Normalizes states, calculates bitsets, processes ViaVersion remappings, and optimizes lookup tables.
3. **Emission**: Emits compiled Rust constants and structs into [`crates/pumpkin-data/src/generated`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-data/src/generated).
---
## Generated Datasets
`pumpkin-codegen` generates the following components in `pumpkin-data`:
| Category | Description | Generated Source |
| :--- | :--- | :--- |
| **Packets** | Serverbound and clientbound packet IDs for all protocol states across supported Minecraft versions. | `packet.rs` |
| **Blocks** | Block definitions, default states, state properties (facing, powered, waterlogged, etc.), and block collision boxes. | `block.rs` |
| **Items** | Item definitions, stack sizes, durability, data components, food properties, and equipment slots. | `item.rs` |
| **Registries** | Dynamic registries for biomes, dimensions, chat types, damage types, trim materials, and banner patterns. | `registry.rs` |
| **Biomes & Noise** | Climate parameters, noise router configurations, 3D noise settings, and surface rules. | `biome.rs`, `noise_router.rs` |
| **Entities** | Entity types, default bounding boxes, attributes, and tracked entity metadata schemas. | `entity_type.rs`, `tracked_data.rs` |
| **Recipes & Crafting** | Shaped, shapeless, smelting, blasting, smoking, and stonecutting recipes. | `recipes.rs` |
| **Tags** | Block tags, item tags, fluid tags, and entity type tags (e.g., `#minecraft:mineable/pickaxe`). | `tag.rs` |
| **Enchantments & Potions** | Enchantment definitions, potion effects, and brewing stand recipes. | `enchantments.rs`, `potion.rs` |
| **Translations** | Official localization keys for chat messages and item names. | `translations.rs` |
| **Plugin WIT** | WebAssembly Component Model WIT files defining plugin interfaces. | `wit/` |
---
## Running Code Generation
To run the code generator locally:
```bash
# Navigate to the workspace root
cd Pumpkin
# Run the codegen tool
cargo run -p pumpkin-codegen
```
### When Should You Run Codegen?
- **Upgrading to a New Minecraft Version**: When porting Pumpkin to a new minor or major Minecraft release.
- **Adding Protocol Mappings**: When adding support for an older or newer client protocol version.
- **Updating WIT Definitions**: When adding new functions or types to the WebAssembly plugin API.
---
## Data Sources
`pumpkin-codegen` reads data from several primary sources:
1. **Minecraft Data Generator Reports**: Generated by running `java -DbundlerMainClass=net.minecraft.data.Main -jar server.jar --reports`.
2. **Minecraft Client Assets**: Extracted from client `.jar` files for translation keys, model shapes, and sound mappings.
3. **Minecraft Protocol Wiki**: Cross-referenced with protocol specifications for packet IDs.

View File

@ -0,0 +1,246 @@
# Adding a Command
This guide explains how to implement and register a new command in the Pumpkin server codebase.
Commands in Pumpkin are implemented in the `crates/pumpkin/src/command/commands/` directory and registered into the central [`CommandDispatcher`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/node/dispatcher.rs) during server initialization.
---
## Anatomy of a Pumpkin Command
A typical command file contains:
1. **Metadata Constants**: Command description, permission node identifier, and argument names.
2. **Permission Registration**: Declaring default OP requirements in the server's [`PermissionRegistry`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-util/src/permission.rs).
3. **Command Executors**: Structs implementing the [`CommandExecutor`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/node/mod.rs) trait for each terminal node or subcommand.
4. **Registration Function**: Constructing the argument tree using fluent builders (`command`, `literal`, `argument`).
---
## Step-by-Step Implementation: Creating `/heal`
Let's implement a complete `/heal` command that can heal either the executing player or a set of target players:
```
/heal -> Heals the executing sender
/heal <targets> -> Heals target player(s)
/heal <targets> <amount> -> Heals target player(s) by a specified amount
```
### 1. Create the File
Create `crates/pumpkin/src/command/commands/heal.rs`:
```rust
use std::sync::Arc;
use crate::command::argument_builder::{ArgumentBuilder, argument, command};
use crate::command::argument_types::core::float::FloatArgumentType;
use crate::command::argument_types::entity::EntityArgumentType;
use crate::command::context::command_context::CommandContext;
use crate::command::errors::error_types::CommandErrorType;
use crate::command::node::dispatcher::CommandDispatcher;
use crate::command::node::{CommandExecutor, CommandExecutorResult};
use crate::entity::EntityBase;
use pumpkin_data::translation;
use pumpkin_util::PermissionLvl;
use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry};
use pumpkin_util::text::TextComponent;
const DESCRIPTION: &str = "Restores health to target entities.";
const PERMISSION: &str = "pumpkin:command.heal";
const ARG_TARGETS: &str = "targets";
const ARG_AMOUNT: &str = "amount";
const ERROR_NOT_PLAYER: CommandErrorType<0> = CommandErrorType::new(
translation::java::PERMISSIONS_REQUIRES_PLAYER,
translation::java::PERMISSIONS_REQUIRES_PLAYER,
);
```
### 2. Implement the Executors
Command execution logic is encapsulated in structs implementing [`CommandExecutor`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/node/mod.rs):
```rust
/// Heals the executing player to full health.
struct SelfHealExecutor;
impl CommandExecutor for SelfHealExecutor {
fn execute(&self, context: &CommandContext) -> CommandExecutorResult {
let player = context
.source
.output
.as_player()
.ok_or_else(|| ERROR_NOT_PLAYER.create_without_context())?;
// Restore player health
player.living_entity.set_health(20.0);
context.source.send_feedback(
TextComponent::text("Fully restored your health!"),
true, // Broadcast to operators if configured
);
// Return number of affected entities
Ok(1)
}
}
/// Heals specified target players.
struct TargetsHealExecutor {
has_amount: bool,
}
impl CommandExecutor for TargetsHealExecutor {
fn execute(&self, context: &CommandContext) -> CommandExecutorResult {
let targets = EntityArgumentType::get_players(context, ARG_TARGETS)?;
let amount = if self.has_amount {
FloatArgumentType::get(context, ARG_AMOUNT)?
} else {
20.0
};
let count = targets.len();
for target in &targets {
let current = target.living_entity.health.load();
target.living_entity.set_health((current + amount).min(20.0));
}
let msg = if count == 1 {
TextComponent::text(format!("Healed {} by {} HP", targets[0].gameprofile.name, amount))
} else {
TextComponent::text(format!("Healed {} players by {} HP", count, amount))
};
context.source.send_feedback(msg, true);
Ok(count as i32)
}
}
```
### 3. Build the Command Tree
Use the fluent builder functions `command`, `literal`, and `argument` to assemble the syntax tree and register the permission:
```rust
pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
// 1. Register permission node with default requirement (OP level 2)
registry.register_permission_or_panic(Permission::new(
PERMISSION,
DESCRIPTION,
PermissionDefault::Op(PermissionLvl::Two),
));
// 2. Assemble command tree
dispatcher.register(
command("heal", DESCRIPTION)
.requires(PERMISSION)
.executes(SelfHealExecutor)
.then(
argument(ARG_TARGETS, EntityArgumentType::Players)
.executes(TargetsHealExecutor { has_amount: false })
.then(
argument(ARG_AMOUNT, FloatArgumentType::new(1.0, 100.0))
.executes(TargetsHealExecutor { has_amount: true }),
),
),
);
}
```
---
## Command Structure Patterns
### Adding Subcommand Literals
Use `literal("subcommand_name")` to create keyword branches:
```rust
use crate::command::argument_builder::{argument, command, literal};
dispatcher.register(
command("weather", "Set the world weather")
.requires("minecraft:command.weather")
.then(literal("clear").executes(ClearWeatherExecutor))
.then(literal("rain").executes(RainWeatherExecutor))
.then(literal("thunder").executes(ThunderWeatherExecutor))
);
```
### Cross-Platform Translation Feedback
Pumpkin servers serve both Java and Bedrock Edition players simultaneously. Whenever possible, use vanilla translation keys with `TextComponent::translate_cross` so messages render localized on the client:
```rust
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
let msg = TextComponent::translate_cross(
translation::java::COMMANDS_KILL_SUCCESS_SINGLE,
translation::bedrock::COMMANDS_KILL_SUCCESSFUL,
[target.get_display_name()],
);
context.source.send_feedback(msg, true);
```
### Error Handling in Executors
Executors must return `CommandExecutorResult`, which resolves to `Result<i32, CommandSyntaxError>`. If validation fails, return an error cleanly without panicking:
```rust
use crate::command::errors::error_types::CommandErrorType;
const ERROR_INVALID_VALUE: CommandErrorType<0> = CommandErrorType::new(
"Amount must be greater than zero.",
"Amount must be greater than zero.",
);
if amount <= 0.0 {
return Err(ERROR_INVALID_VALUE.create_without_context());
}
```
---
## Registering in `default_dispatcher`
Once your command is implemented, register it in `crates/pumpkin/src/command/commands/mod.rs`:
1. **Declare the Module**:
```rust
// In crates/pumpkin/src/command/commands/mod.rs
mod heal;
```
2. **Invoke `register` in `default_dispatcher`**:
```rust
pub fn default_dispatcher(
permission_manager: &PermissionManager,
commands_config: &CommandsConfig,
) -> CommandDispatcher {
let registry = &permission_manager.registry;
let mut dispatcher = CommandDispatcher::new();
// ... existing registrations ...
heal::register(&mut dispatcher, registry);
dispatcher
}
```
---
## Best Practices Checklist
- [ ] **No Panics or Unwraps**: Use `?` or return descriptive `CommandSyntaxError`s when arguments are invalid.
- [ ] **Permission Nodes**: Prefix permission strings with appropriate namespaces (`minecraft:command.<name>` for vanilla commands, `pumpkin:command.<name>` for server-specific commands).
- [ ] **Return Success Counts**: The returned `i32` represents the command's exit code or number of affected objects for redstone command blocks and `/execute store result`.
- [ ] **Respect GameRules**: When notifying players other than the sender, check if `send_command_feedback` is enabled:
```rust
let server = context.source.server();
if server.level_info.load().game_rules.send_command_feedback {
target.send_system_message(&feedback);
}
```

View File

@ -0,0 +1,159 @@
# Argument Types & Suggestions
Pumpkin provides a comprehensive suite of type-safe command arguments through `pumpkin-command` and the main `pumpkin` server crate. Arguments deserialize raw token streams into structured Rust types, validate ranges, and furnish tab-completion suggestions to clients.
---
## Standard Argument Types
Argument parsers implement the [`ArgumentType<S>`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/argument_types/argument_type.rs) trait. The following built-in types are available for command builders:
### 1. Primitive & Scalar Types
| Argument Type | Import Path | Deserialized Type | Description |
| :--- | :--- | :--- | :--- |
| **`IntegerArgumentType`** | `...::core::integer` | `i32` | Standard 32-bit integer with optional `[min, max]` bounds. |
| **`FloatArgumentType`** | `...::core::float` | `f32` | 32-bit floating point number with bounds. |
| **`DoubleArgumentType`** | `...::core::double` | `f64` | 64-bit floating point number with bounds. |
| **`LongArgumentType`** | `...::core::long` | `i64` | 64-bit integer with bounds. |
| **`BoolArgumentType`** | `...::core::bool` | `bool` | Boolean value (`true` or `false`). |
| **`StringArgumentType`** | `...::core::string` | `String` | String tokens based on quoting rules. |
#### String Argument Behaviors
- **`StringArgumentType::Word`**: Parses a single word without whitespace.
- **`StringArgumentType::Quotable`**: Parses either a single word or a quoted phrase (`"hello world"`).
- **`StringArgumentType::Greedy`**: Consumes all remaining characters in the input stream (ideal for chat/broadcast commands like `/say` and `/me`).
---
## Coordinate Argument Types
Minecraft coordinates support absolute positions, relative offsets (`~`), and local caret directions (`^`):
```rust
use crate::command::argument_builder::argument;
use crate::command::argument_types::coordinates::block_pos::BlockPosArgumentType;
use crate::command::argument_types::coordinates::vec3::Vec3ArgumentType;
// Block position (integer BlockPos)
argument("pos", BlockPosArgumentType)
// Precise entity coordinates (f64 Vector3)
argument("location", Vec3ArgumentType)
```
### Retrieving Parsed Coordinates
Inside an executor, coordinate arguments resolve relative offsets against the sender's current position and orientation in the [`CommandSource`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/command/context/command_source.rs):
```rust
// Extracts centered f64 coordinates (handling ~ and ^ relative to sender)
let pos: Vector3<f64> = Vec3ArgumentType::get_coordinates(context, "location")?;
// Extracts integer block position
let block_pos: BlockPos = BlockPosArgumentType::get_block_pos(context, "pos")?;
```
---
## Entity Selectors (`EntityArgumentType`)
Entity selectors allow players and command blocks to target entities using player names, UUIDs, or vanilla target selectors (`@p`, `@r`, `@a`, `@e`, `@s`).
In Pumpkin, entity selectors are accessed via [`EntityArgumentType`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/command/argument_types/entity.rs):
```rust
pub enum EntityArgumentType {
/// Matches exactly one player
Player,
/// Matches zero or more players
Players,
/// Matches exactly one entity
Entity,
/// Matches zero or more entities
Entities,
}
```
### Resolution in Executors
```rust
// 1. Target single player
let player: Arc<Player> = EntityArgumentType::get_player(context, "target")?;
// 2. Target multiple players
let players: Vec<Arc<Player>> = EntityArgumentType::get_players(context, "targets")?;
// 3. Target single living entity or mob
let entity: Arc<dyn EntityBase> = EntityArgumentType::get_entity(context, "target")?;
// 4. Target multiple entities
let entities: Vec<Arc<dyn EntityBase>> = EntityArgumentType::get_entities(context, "targets")?;
```
### Supported Selector Syntaxes
Pumpkin's entity selector parser (`crates/pumpkin/src/command/argument_types/entity_selector/`) parses and validates:
- `@p`: Nearest player relative to execution coordinates.
- `@r`: Random player.
- `@a`: All online players.
- `@e`: All entities in loaded world chunks.
- `@s`: Executing entity (`context.source.entity`).
- **Bracket Arguments**: Filter queries like `@e[type=zombie,distance=..10,limit=5,sort=nearest]`.
---
## Registry & Game Mechanic Types
Pumpkin provides specialized argument parsers for Minecraft data types:
- **`GameModeArgumentType`**: Resolves `survival`, `creative`, `adventure`, `spectator` or numeric IDs `0`–`3`.
- **`BlockArgumentType`**: Parses block identifiers and block states (e.g., `minecraft:chest[facing=north]`).
- **`ItemArgumentType`**: Parses item identifiers and optional data components (e.g., `minecraft:diamond_sword`).
- **`NbtArgumentType`**: Parses SNBT (Stringified NBT) tags into Pumpkin's NBT representation.
- **`TimeArgumentType`**: Parses durations with suffixes (e.g., `10s`, `20t`, `1d`).
---
## Suggestion Providers & Tab Completion
Arguments can supply dynamic tab-completion candidates to connected players using the [`SuggestionProvider`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/suggestion/mod.rs) trait:
```rust
use crate::command::context::command_context::CommandContext;
use crate::command::suggestion::provider::SuggestionProvider;
use pumpkin_command::suggestion::suggestions::{Suggestions, SuggestionsBuilder};
struct CustomSuggestionProvider;
impl SuggestionProvider for CustomSuggestionProvider {
fn suggest(
&self,
context: &CommandContext,
mut builder: SuggestionsBuilder,
) -> Suggestions {
// Retrieve already typed token prefix
let remaining = builder.remaining();
let candidates = ["alpha", "bravo", "charlie"];
for candidate in candidates {
if candidate.starts_with(remaining) {
builder.suggest(candidate);
}
}
builder.build()
}
}
```
### Attaching Suggestions to Arguments
Use the `.suggests(...)` method on `RequiredArgumentBuilder`:
```rust
argument("code", StringArgumentType::Word)
.suggests(CustomSuggestionProvider)
.executes(MyExecutor)
```
### Client Completion Protocol
- **Java Edition**: When a player presses `Tab`, the client transmits a `ServerboundCommandSuggestion` packet. Pumpkin matches the cursor position within the `CommandDispatcher`, executes the target node's `SuggestionProvider`, and responds with `ClientboundCommandSuggestions` containing completion ranges and tooltip tooltips.
- **Bedrock Edition**: Suggestion options for literals and enums are serialized ahead of time in the `CAvailableCommands` packet as dynamic enum value tables.

View File

@ -0,0 +1,118 @@
# Execution & Context
In Pumpkin, command execution separates the **physical origin** of a command from its **runtime context**. This design enables complex command routing, dimension shifts, conditional execution, and vanilla-compliant `/execute` chaining.
---
## `CommandSender` vs. `CommandSource`
Understanding the distinction between `CommandSender` and `CommandSource` is fundamental to developing commands in Pumpkin:
| Attribute | `CommandSender` | `CommandSource` |
| :--- | :--- | :--- |
| **Concept** | The physical origin and network destination | The mutable runtime execution environment |
| **Mutability** | Immutable throughout command execution | Cloned and modified across `/execute` branches |
| **Key Fields** | Terminal socket, connection handle, RCON buffer | World, position coordinates, rotation, entity, silent flag |
| **Creation** | Instantiated on network connection or terminal input | Constructed via `sender.into_source(&server)` |
### 1. `CommandSender` (Physical Caller)
Represents the entity or socket that initiated the command and receives its output:
```rust
pub enum CommandSender {
Console,
Rcon(Arc<std::sync::Mutex<Vec<String>>>),
Player(Arc<Player>),
CommandBlock(Arc<CommandBlockEntity>, Arc<World>),
Dummy,
}
```
- **Output Target**: Determines where messages formatted with `send_message` are routed (e.g., standard out, RCON buffer, player packet, or block entity NBT).
- **Hard Permissions**: Holds fixed base permissions (e.g., Console has level 4 bypass; Command Blocks have level 2).
### 2. `CommandSource` (Execution Environment)
Represents the mutable runtime state during command evaluation:
```rust
pub struct CommandSource {
pub output: CommandSender,
pub world: Option<Arc<World>>,
pub entity: Option<Arc<dyn EntityBase>>,
pub position: Vector3<f64>,
pub rotation: Vector2<f32>,
pub name: String,
pub display_name: TextComponent,
pub server: Option<Arc<Server>>,
pub silent: bool,
pub command_result_taker: ResultValueTaker,
pub entity_anchor: EntityAnchor,
}
```
A sender converts into a `CommandSource` via `sender.into_source(&server)`.
---
## The `/execute` Command & Context Redirection
The `/execute` command manipulates `CommandSource` properties before passing control to a downstream command.
### Branching Modifiers
- **`as <targets>`**: Changes `context.source.entity` to target entities without altering position or rotation.
- **`at <targets>`**: Updates `context.source.world`, `position`, and `rotation` to match the target entity.
- **`positioned <pos>`**: Modifies `context.source.position` to new coordinates.
- **`in <dimension>`**: Changes `context.source.world` to the specified dimension (Overworld, Nether, The End).
- **`anchored (feet|eyes)`**: Adjusts coordinate offsets for line-of-sight and facing checks.
### Context Forking & Chaining
When `/execute` matches multiple targets (e.g., `/execute as @e run ...`), `pumpkin-command` uses **forking**:
1. The dispatcher forks the execution context once per matched target.
2. The child command executes independently for each cloned `CommandSource`.
3. The cumulative success count is aggregated across all executions.
---
## Result Values & Success Counts
Vanilla commands communicate results back through integer exit codes and return values.
### The Return Value Callback
Executors return `CommandExecutorResult` (`Result<i32, CommandSyntaxError>`). The returned integer signifies:
- **0**: Failure or zero entities affected.
- **> 0**: Number of entities affected, blocks changed, or items cleared.
For Command Blocks, this value is persisted into the block entity's `SuccessCount`:
```rust
pub fn set_success_count(&self, count: u32) {
if let Self::CommandBlock(c, _) = self {
c.success_count.store(count, Ordering::SeqCst);
}
}
```
### `/execute store`
When chained with `/execute store (result|success) ...`, Pumpkin intercepts the return value via `ReturnValueCallback` and writes it to scoreboards, bossbars, or entity NBT tags.
---
## Feedback & GameRules Integration
Sending output to the command sender is governed by server configuration and world game rules:
```rust
context.source.send_feedback(
TextComponent::text("Command executed successfully!"),
true, // Broadcast to server operators
);
```
### Output Rules Matrix
| Condition | Feedback Behavior |
| :--- | :--- |
| `silent == true` | Output is suppressed completely. |
| `send_command_feedback == false` | Player senders do not receive success feedback (errors are still displayed). |
| `command_block_output == false` | Command block execution output is not broadcast to online operators. |
| `broadcast_console_to_ops == true` | Server console and RCON commands emit a copy of their feedback to all online OP level 2+ players. |

View File

@ -0,0 +1,142 @@
# Commands Architecture & Dispatcher
Pumpkin features a high-performance, pure-Rust implementation of the **Brigadier** command tree specification through the dedicated `pumpkin-command` crate. It coordinates command parsing, requirement resolution, type-safe argument deserialization, execution branching, and dual-edition client tree synchronization for both **Minecraft: Java Edition** and **Minecraft: Bedrock Edition**.
### Command Processing Pipeline
Every command executed in Pumpkin flows through the following discrete stages:
1. **Input Normalization**: Strips single leading slashes while preserving plugin multi-slash conventions (such as `//set`).
2. **Availability Check**: Rejects commands disabled via server configuration with standard `unknown command` syntax errors.
3. **Permission Evaluation**: Validates requirements (`PermissionLvl` or custom registry nodes) against the executing sender.
4. **Tokenization & Parsing**: `StringReader` recursively walks the `Tree<S>`, matching literal keywords and parsing typed argument parameters.
5. **Context Dispatch**: Invokes the matched `CommandExecutor` callback with a typed `CommandContext<S>`.
6. **Feedback & Result Consumption**: Formats cross-platform translation components, notifies observers, and writes exit codes back to the caller.
---
## The `pumpkin-command` Crate
Pumpkin decouples command parsing and tree representation from the main server runtime into the modular `pumpkin-command` crate (`crates/pumpkin-command`).
Key components of `pumpkin-command` include:
- **`Tree<S>`**: Contiguous vector-backed storage of attached command nodes (`AttachedNode`).
- **`CommandDispatcher<S>`**: The central registry and dispatch engine. It processes raw command strings, parses tokens with `StringReader`, traverses the command tree, and executes target callbacks.
- **`ArgumentBuilder`**: Fluent builder API (`command`, `literal`, `argument`) modeled after Mojang's Brigadier library.
- **`CommandSource`**: Generic execution state representing the current position, rotation, dimension, entity, and feedback output stream.
---
## The Command Node Hierarchy
Commands in Pumpkin are modeled as directed graphs of nodes. To optimize memory allocations and avoid circular reference issues during building, the system separates nodes into **detached** and **attached** states:
### 1. Detached Nodes (`DetachedNode`)
Constructed using fluent builders (`CommandArgumentBuilder`, `LiteralArgumentBuilder`, `RequiredArgumentBuilder`) before registration:
- **`CommandDetachedNode`**: Represents a root command entrypoint with an identifier and a description.
- **`LiteralDetachedNode`**: Represents a literal keyword in a subcommand branch (e.g., `set` in `/gamemode creative`).
- **`ArgumentDetachedNode`**: Represents a typed parameter parsed by an `ArgumentType` (e.g., coordinates, entity selectors, integer ranges).
### 2. Attached Nodes (`AttachedNode`)
Once registered into the `CommandDispatcher`, detached trees are flattened into an indexed `Tree<S>` structure:
```rust
pub enum AttachedNode<S: CommandSource = DummySource> {
Root(RootAttachedNode<S>),
Literal(LiteralAttachedNode<S>),
Argument(ArgumentAttachedNode<S>),
Command(CommandAttachedNode<S>),
}
```
Each attached node has:
- **`NodeId`**: A zero-cost typed index (`NonZero<usize>`) into the contiguous node arena.
- **`children`**: Fast lookup map (`FxHashMap<String, NodeId>`) for literals and child arguments.
- **`requirements`**: Predicates determining whether a sender has permission to view or execute the node.
- **`command`**: Optional `CommandExecutor` callback invoked when parsing terminates on this node.
- **`redirect`**: Optional `Redirection` pointer to loop back or redirect to another sub-tree (used heavily by `/execute`).
---
## Dispatch & Execution Pipeline
When a command arrives at the server, `CommandDispatcher::handle_command` processes it through several stages:
```rust
pub fn handle_command<'a>(&'a self, source: &S, mut input: &'a str) {
// 1. Strip single leading slash (preserving double-slash commands like //set)
if let Some(sliced) = input.strip_prefix('/') {
let first_token = input.split_whitespace().next().unwrap_or("");
let sliced_token = sliced.split_whitespace().next().unwrap_or("");
if !self.has_command(first_token)
&& (self.has_command(sliced_token) || !first_token.starts_with("//"))
{
input = sliced;
}
}
// 2. Check disabled commands from configuration
if self.is_disabled(Self::command_name(input)) {
let reader = StringReader::new(input);
Self::send_error_to_source(source, DISPATCHER_UNKNOWN_COMMAND.create(&reader), input);
return;
}
// 3. Parse and execute
let output = self.execute_input(input, source);
if let Err(error) = output {
Self::send_error_to_source(source, error, input);
}
}
```
### Syntax Error Formatting
When parsing encounters invalid syntax, unexpected tokens, or out-of-range arguments, Pumpkin constructs a `CommandSyntaxError`. If context is available, the dispatcher formats a visual pointer highlighting exactly where the parser failed:
```
Unknown or incomplete command, see below for error
/gamemode creatve<--[HERE]
```
In the Java Edition client, this error text is annotated with a `ClickEvent::SuggestCommand`, allowing the player to click the error in chat to copy the failed command into their input box for quick editing.
---
## Dual-Edition Network Synchronization
Unlike vanilla servers which only serialize command graphs for Java Edition, Pumpkin dynamically synchronizes the registered command tree across both Java and Bedrock clients:
### 1. Java Edition: `CCommands` Packet
When a player joins or their permission level updates (e.g., via `/op` or `/deop`), Pumpkin builds and sends a `CCommands` packet (`pumpkin_protocol::java::client::play::CCommands`):
- Converts `AttachedNode`s into a flat array of `ProtoNode` entries.
- Filters out disabled commands and nodes where `requirements.evaluate(source)` returns `false`.
- Serializes argument parsers (`brigadier:string`, `brigadier:integer`, `minecraft:entity`, etc.) and client-side suggestion identifiers.
### 2. Bedrock Edition: `CAvailableCommands` Packet
Bedrock Edition uses an overload-and-enum format rather than Brigadier's recursive graph. In `client_suggestions.rs`, Pumpkin traverses the `AttachedNode` tree to synthesize:
- **`CommandData`**: Root command name, description, permission flags, and aliases.
- **`OverloadData`**: Flattened permutations of argument chains leading to executable endpoints.
- **`ParamData`**: Bedrock parameter types, bitflags (`ARG_FLAG_VALID`, `ARG_FLAG_ENUM`), and dynamically collected enum value tables.
---
## Universal Execution Targets
Pumpkin commands can be executed across diverse senders:
| Sender | Source Representation | Output Destination | Default Permission |
| :--- | :--- | :--- | :--- |
| **Player** | `CommandSender::Player(Arc<Player>)` | Client system chat packet | Loaded from permission level / permissions file |
| **Server Console** | `CommandSender::Console` | Standard stdout (`tracing::info!`) | Level 4 (Full administrative bypass) |
| **RCON Console** | `CommandSender::Rcon(Arc<Mutex<Vec<String>>>)` | Network response packet payload | Level 4 |
| **Command Block** | `CommandSender::CommandBlock(Arc<CommandBlockEntity>, Arc<World>)` | NBT `LastOutput` field | Level 2 |
| **Datapack Function** | `CommandSender` inherited from caller | Inherited | Inherited |
| **WASM Plugin** | Invoked through WIT `execute_command` host call | Captured via `ResultDeferrer` | Configurable |
---
## Command Configuration & Disabling
Pumpkin allows server administrators to disable individual commands via `config/commands.toml` (`CommandsConfig`). When a command is disabled:
1. It is omitted from the `CCommands` packet for Java clients.
2. It is omitted from the `CAvailableCommands` packet for Bedrock clients.
3. Tab completion ignores the command entirely.
4. Any attempt to invoke the command returns `DISPATCHER_UNKNOWN_COMMAND`.

View File

@ -0,0 +1,111 @@
# Mob AI & Goal System
Pumpkin implements a modular, priority-driven Artificial Intelligence (AI) goal system for computer-controlled mobs, located in [`crates/pumpkin/src/entity/ai/`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin/src/entity/ai) and [`crates/pumpkin/src/entity/mob/`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin/src/entity/mob).
---
## The Goal System Architecture
Mob behaviors are decomposed into independent modular tasks called **Goals**. Each mob possesses a **GoalSelector** that maintains an ordered collection of goals evaluated on every server tick.
### Goal Priority Hierarchy
Goals are assigned an integer priority (where lower numbers represent higher precedence). During each tick, higher-priority actions preempt lower-priority background tasks:
| Priority | Goal Type | Evaluation Condition | Behavior |
| :--- | :--- | :--- | :--- |
| **1 (Highest)** | `SwimGoal` | Entity is submerged in water | Jump repeatedly to swim to the water surface and avoid drowning. |
| **2** | `MeleeAttackGoal` | Valid hostile target in sight/range | Navigate towards target entity and execute melee attacks. |
| **3** | `WanderAroundGoal` | No active combat target | Pick a random nearby navigable voxel and walk to it. |
| **4 (Lowest)** | `LookAtEntityGoal` | Player or mob within observation radius | Rotate head and body pitch/yaw towards the target entity. |
### Execution Flow
1. **Evaluation**: On every game tick, `GoalSelector::tick()` iterates through registered goals in order of priority.
2. **Activation**: If an inactive goal satisfies `can_start()`, it is activated via `start()`.
3. **Execution**: Active goals run their per-tick logic in `tick()`.
4. **Preemption & Termination**: If `should_continue()` returns `false`, or a mutually exclusive goal with higher priority activates, `stop()` is called and the goal resets.
### The `Goal` Lifecycle
Every AI behavior implements the `Goal` trait:
```rust
pub trait Goal: Send + Sync {
/// Evaluates preconditions to determine if this goal can activate.
fn can_start(&self) -> bool;
/// Called once when the goal transitions from inactive to active.
fn start(&mut self) {}
/// Evaluates whether the goal should continue executing on subsequent ticks.
fn should_continue(&self) -> bool {
self.can_start()
}
/// Executes the continuous behavior on each server tick.
fn tick(&mut self) {}
/// Called when the goal completes, fails, or is preempted by a higher priority goal.
fn stop(&mut self) {}
}
```
---
## Standard Built-in Goals
Pumpkin provides standard vanilla AI behaviors in `crates/pumpkin/src/entity/ai/`:
| Goal | Description | Target Mobs |
| :--- | :--- | :--- |
| **`SwimGoal`** | Jumps repeatedly while submerged in water to prevent drowning. | Almost all land mobs |
| **`MeleeAttackGoal`** | Navigates towards an attack target and executes a strike when within reach. | Zombies, Spiders, Iron Golems |
| **`RangedAttackGoal`** | Stays at range and shoots projectiles (arrows, snowballs). | Skeletons, Pillagers, Blazes |
| **`FleeSunGoal`** | Seeks shade or water during daytime to prevent combustion. | Zombies, Skeletons |
| **`PanicGoal`** | Sprints in random directions when taking damage. | Cows, Pigs, Sheep, Chickens |
| **`WanderAroundGoal`** | Selects random accessible coordinates nearby when idle. | Passive & neutral mobs |
| **`LookAtEntityGoal`** | Rotates head to face nearby players within sensory range. | Villagers, Mobs |
---
## Navigation & Pathfinding
Mobs navigate the block world using Pumpkin's 3D grid pathfinder:
1. **Path Calculation**: Resolves a path from the mob's origin to target coordinates using an A* algorithm optimized for Minecraft block geometries.
2. **Obstacle Avoidance**:
- Avoids hazardous blocks (lava, fire, sweet berry bushes).
- Prevents walking off ledges higher than the mob's fall threshold.
- Computes jumping steps over 1-block obstacles.
3. **Waypoint Steering**: The navigation engine updates the mob's velocity vectors per tick to smoothly guide the entity along waypoints.
---
## Entity Attributes System
Mob capabilities and stats are governed by the **Attributes** system in [`crates/pumpkin/src/entity/attributes.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/entity/attributes.rs):
```rust
use pumpkin_data::entity::attribute::EntityAttribute;
// Common vanilla attributes
EntityAttribute::GENERIC_MAX_HEALTH; // Base hit points (e.g. 20.0 for Zombies)
EntityAttribute::GENERIC_MOVEMENT_SPEED; // Base walking velocity (e.g. 0.23)
EntityAttribute::GENERIC_ATTACK_DAMAGE; // Melee attack damage (e.g. 3.0)
EntityAttribute::GENERIC_FOLLOW_RANGE; // Sensory detection range in blocks (e.g. 35.0)
EntityAttribute::GENERIC_KNOCKBACK_RESISTANCE; // Resistance against knockback (0.0 to 1.0)
```
### Modifiers
Attributes support dynamic modifiers with additive or multiplicative calculations (e.g., speed bonuses from Swiftness potions or armor attribute boosts).
---
## Ageable & Passive Entities
Passive animals (cows, sheep, pigs) implement the `Ageable` trait:
- **Baby State**: Renders with smaller collision boxes and oversized heads.
- **Growing Age**: A negative tick timer counting upward to `0`. When it reaches `0`, the entity matures into an adult.
- **Breeding Cooldown**: Positive tick timer tracking cooldowns between successful matings.

View File

@ -0,0 +1,77 @@
# Entity Architecture & Hierarchy
Entities in Minecraft represent all dynamic, living and non-living objects that exist within a world—ranging from dropped item stacks and arrows to zombies, villagers, and players.
In Pumpkin, entity systems are implemented in [`crates/pumpkin/src/entity/`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin/src/entity). The architecture leverages object-oriented trait composition on top of concurrency-safe, cache-friendly data structures.
---
## Entity Trait Hierarchy
Pumpkin structures entities into an inheritance hierarchy using Rust traits:
| Trait / Type | Parent Trait | Core Capabilities & State |
| :--- | :--- | :--- |
| `Entity` | *(None / Base Struct)* | Entity ID, UUID, atomic position and velocity vectors, bounding box, pose |
| `EntityBase` | *(Root Trait)* | Dynamic runtime downcasting (`get_living_entity`, etc.), world tick, damage, teleportation |
| `LivingEntity` | `EntityBase` | Health, absorption, potion effects, equipment slots, attribute containers |
| `Mob` | `LivingEntity` | AI goal selector, navigation, pathfinding, target tracking, death loot |
| `Player` | `LivingEntity` | Network client session, inventory, crafting screens, hunger, advancements |
### 1. `Entity` (Base Struct)
Contains fundamental physics, geometry, and spatial state common to all entities:
- **`entity_id`**: Fast 32-bit unique integer identifier used across network packets.
- **`uuid`**: 128-bit persistent UUID.
- **`position` & `velocity`**: Thread-safe vectors (`AtomicCell<Vector3<f64>>`) allowing concurrent reading without lock contention.
- **`bounding_box`**: 3D axis-aligned bounding box (AABB) used for collision resolution and raycast targeting.
- **`pose`**: Current pose (`Standing`, `Crouching`, `Sleeping`, `FallFlying`, etc.).
### 2. `EntityBase` (Foundation Trait)
The root dynamic trait implemented by every entity in the server:
- Supports safe runtime downcasting via helper methods (`get_living_entity()`, `get_mob()`, `get_player()`).
- Provides hooks for world interaction: `tick()`, `damage()`, `teleport()`, `on_lightning_strike()`, `is_immune_to_explosion()`.
### 3. `LivingEntity` (Biological Trait)
Extends `EntityBase` for entities with health, combat, and animation states:
- Manages health bars, absorption, invulnerability ticks, and fall damage.
- Tracks active potion effects (`crates/pumpkin/src/entity/effect/`).
- Handles equipment slots (`MainHand`, `OffHand`, `Helmet`, `Chestplate`, `Leggings`, `Boots`).
- Encapsulates attribute containers (max health, movement speed, knockback resistance).
### 4. `Mob` (AI Trait)
Extends `LivingEntity` for computer-controlled mobs:
- Manages AI goal selectors (attacking, wandering, fleeing, looking around).
- Controls navigation and pathfinding over blocks.
- Spawns configured loot tables upon death.
### 5. `Player` (Human Client)
Represents a human player connected through a game client:
- Links to network socket handlers (`JavaClient` or `BedrockClient`).
- Manages container screen handlers, ender chests, player inventory, and crafting.
- Tracks hunger, saturation, exhaustion, experience levels, and advancement criteria.
---
## Physics & Movement Simulation
On every server tick, Pumpkin simulates entity physics through a deterministic sequence:
1. **Apply Velocity & Gravity**: Evaluates current velocity and adds downward gravitational acceleration unless `has_gravity()` is false or the entity is flying.
2. **Resolve Block Collisions**: Checks the entity's 3D axis-aligned bounding box (`bounding_box`) against solid block voxels in the surrounding chunk; velocity along colliding axes is dampened or zeroed.
3. **Apply Fluid Drag & Buoyancy**: Evaluates whether the entity intersects water or lava fluids, applying drag coefficients and buoyant upward force.
4. **Synchronize & Broadcast**: Persists the updated coordinates in atomic position cells and broadcasts relative delta movement packets to observing players.
5. **Void Death**: Non-player entities falling below $Y = -128$ are automatically despawned.
---
## Combat & Damage System
Damage calculations reside in [`crates/pumpkin/src/entity/combat.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/entity/combat.rs):
1. **Damage Types**: Damage is categorized by `DamageType` (e.g., `GENERIC`, `PLAYER_ATTACK`, `FALL`, `FIRE`, `MAGIC`, `EXPLOSION`, `LIGHTNING_BOLT`).
2. **Damage Scaling**:
- Armor defense points mitigate incoming physical damage according to the vanilla formula:
$$\text{damage} = \text{damage} \times \left(1 - \frac{\min(20, \max(\text{armor} / 5, \text{armor} - \frac{\text{damage}}{2 + \text{toughness} / 4}))}{25}\right)$$
- Resistance status effects and Protection enchantments apply secondary reductions.
3. **Knockback**: When damage is dealt, a directional impulse vector is added to the victim's velocity, modulated by their knockback resistance attribute.
4. **Hurt Animations**: Triggers hurt sounds and broadcasts red-tint flash metadata to all observers.

View File

@ -0,0 +1,95 @@
# Spawning & Network Tracking
To maintain high tick rates with hundreds of active entities, Pumpkin utilizes a chunk-based entity tracking and streaming system.
Entities are held in chunk-level collections inside [`crates/pumpkin-world`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-world) and synchronized across clients via edition-specific network packets.
---
## The Spawning Pipeline
Spawning an entity involves creating an instance, allocating its network IDs, registering it with the world, and broadcasting spawn packets to chunk observers:
1. **Construct Entity Instance**: Instantiate the specific entity struct (such as `ZombieEntity`, `ArrowEntity`, or `ItemEntity`) initialized with its starting world and spatial coordinates.
2. **Allocate Unique Network Identifiers**: Assign an atomic 32-bit `entity_id` for network protocol packets and a 128-bit persistent UUID.
3. **Register in World & Chunk Map**: Insert the entity into the world's entity storage and index it within its corresponding chunk coordinate entry.
4. **Query Chunk Observers**: Look up all connected players within tracking range whose view distance includes the containing chunk.
5. **Broadcast Edition-Specific Spawn Packets**: Transmit the relevant spawn and metadata packets tailored to each observing client's edition (Java or Bedrock).
### Spawning via the World API
```rust
use std::sync::Arc;
use pumpkin_data::entity::EntityType;
use pumpkin_util::math::vector3::Vector3;
use crate::entity::Entity;
use crate::entity::mob::zombie::ZombieEntity;
// 1. Create base entity with target world and position
let position = Vector3::new(100.5, 64.0, -200.5);
let base_entity = Entity::new(world.clone(), position, &EntityType::ZOMBIE);
// 2. Wrap in specific entity implementation
let zombie = Arc::new(ZombieEntity::new(base_entity));
// 3. Register into the world
world.spawn_entity(zombie);
```
---
## Network Packet Synchronization
When a player enters a chunk containing entities—or when an entity moves into an observed chunk—Pumpkin dispatches spawn packets tailored to the client's edition:
### Java Edition Spawning
1. **`CSpawnEntity`**: Declares the entity ID, UUID, entity type, position, and initial pitch/yaw.
2. **`CSetEntityMetadata`**: Sends initial visual states (custom name tags, burning flags, baby/adult state).
3. **`CEntityVelocity`**: Synchronizes initial momentum.
4. **`CUpdateEntityRot` & `CHeadRot`**: Synchronizes head orientation independently from body yaw.
### Bedrock Edition Spawning
1. **`CAddActor`**: Declares the runtime ID, actor type identifier, position, rotation, and embedded `SyncedActorDataList`.
2. **`CSetActorMotion`**: Sets initial velocity vector.
---
## Movement & Position Synchronization
Transmitting absolute 64-bit coordinates every tick would congest network bandwidth. Instead, Pumpkin dynamically switches between compact relative delta updates and authoritative full synchronization based on movement distance:
| Metric / Scenario | Threshold | Java Protocol Packet | Bedrock Protocol Packet | Bandwidth Impact |
| :--- | :--- | :--- | :--- | :--- |
| **Incremental Movement** | $\Delta < 8$ blocks per tick | `CUpdateEntityPos` / `CUpdateEntityPosRot` | `CMoveActorDelta` | Minimal (fixed-point byte deltas) |
| **Teleport / Long Distance** | $\Delta \ge 8$ blocks or chunk warp | `CTeleportEntity` / `CEntityPositionSync` | `CMoveActorAbsolute` | Full 64-bit float coordinate payload |
| **Rotation Only** | Position unchanged | `CUpdateEntityRot` & `CHeadRot` | `CMoveActorDelta` (rot flags only) | Minimal (byte angles) |
### 1. Relative Delta Movement
If the entity moved less than 8 blocks in a single tick, Pumpkin sends delta packets using fixed-point encoded increments:
- **Java**: `CUpdateEntityPos` (XYZ delta), `CUpdateEntityRot` (yaw/pitch delta), or `CUpdateEntityPosRot` (both).
- **Bedrock**: `CMoveActorDelta` with bitflags indicating which coordinates changed (`MOVE_ACTOR_DELTA_FLAG_HAS_X`, `HAS_Y`, `HAS_Z`).
### 2. Full Position Synchronization
When an entity teleports, crosses chunk boundaries, or accumulates floating-point drift:
- **Java**: Sends `CEntityPositionSync` containing absolute coordinates, velocities, and on-ground flags.
- **Bedrock**: Sends `CMoveActorAbsolute`.
---
## Passenger & Vehicle Mounting
When an entity mounts another entity (e.g., a player mounting a horse, boat, or minecart):
- **Java Edition**: Sends `CSetPassengers` containing the vehicle's `VarInt` entity ID and an array of passenger entity IDs.
- **Bedrock Edition**: Sends `CSetActorLink` defining the rider and vehicle runtime IDs and link type (`Rider`, `Passenger`).
---
## Despawning & Entity Removal
When an entity dies, is removed from the world, or steps out of a player's tracking radius:
- **Java Edition**: Sends `CRemoveEntities` with an array of entity IDs.
- **Bedrock Edition**: Sends `CRemoveActor` with the entity's runtime ID.
The client immediately frees its local rendering and audio memory for the removed entity.

View File

@ -0,0 +1,144 @@
# Vanilla Data Extractor
The [Pumpkin Extractor](https://github.com/Pumpkin-MC/Extractor) is a dedicated Fabric mod written in Kotlin that introspects a running vanilla Minecraft server or client to dump authoritative game registries and runtime metadata into structured JSON files.
These JSON dumps are consumed by [`pumpkin-codegen`](/developer/codegen) to generate strongly-typed Rust code in `pumpkin-data` and `pumpkin-world`.
---
## Datapacks vs. Extractor: Our Data Philosophy
Before creating a new extractor, it is crucial to understand Pumpkin's data hierarchy:
> [!IMPORTANT]
> **We preferably use vanilla datapacks whenever possible.**
> If vanilla Minecraft already exposes a registry or system through official datapack JSON files, we consume the datapack directly rather than writing custom extractor code.
### When to Use Datapacks vs. When to Use the Extractor
| Source | When to Use | Examples |
| :--- | :--- | :--- |
| **Vanilla Datapacks** *(Preferred)* | Any data officially serialized as JSON by Mojang in `data/minecraft/`. | Recipes, tags (`blocks`, `items`, `fluids`), biomes, dimension types, damage types, trim materials, worldgen noise parameters. |
| **Fabric Extractor** *(Only when necessary)* | Game data **hardcoded in Java bytecode** that cannot be exported from raw datapack files. | Block collision shapes, AABB bounding boxes, block hardness, packet ID-to-state mappings, entity tracked data IDs, fuel burn durations, composter chances, and flower pot conversion tables. |
---
## Extractor Mod Architecture
The Extractor runs on top of the Fabric loader using official Fabric Yarn mappings:
- **Mod Entry Point (`src/main/kotlin/de/snowii/extractor/Extractor.kt`)**: Registers with Fabric's `ServerLifecycleEvents.SERVER_STARTED` event. When the headless server finishes booting, it invokes all registered extractors and dumps files to `run/pumpkin_extractor_output/`.
- **Extractor Interface**: Every data extractor implements the `Extractor.Extractor` interface:
```kotlin
interface Extractor {
fun fileName(): String
@Throws(Exception::class)
fun extract(server: MinecraftServer): JsonElement
// Returns true if output belongs in tests/ rather than the root output folder
fun isTest(): Boolean = false
}
```
- **Output Directory**: JSON files are saved to `pumpkin_extractor_output/` encoded in UTF-8 without HTML escaping.
---
## How to Add a New Extractor
Follow this step-by-step workflow when you need to extract new hardcoded vanilla mechanics:
### Step 1: Verify the Data Cannot Be Sourced from Datapacks
Inspect the official Minecraft client/server JAR or Mojang's data reports:
- Check `data/minecraft/` for existing registries, tags, or JSON definitions.
- If the data is present in the datapack, add it directly to `Pumpkin/assets/datapacks/` instead of writing an extractor.
### Step 2: Create the Extractor Class
If the data is hardcoded in Java methods, create a new Kotlin class in:
```text
src/main/kotlin/de/snowii/extractor/extractors/<ExtractorName>.kt
```
Implement the `Extractor.Extractor` interface:
```kotlin
package de.snowii.extractor.extractors
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import de.snowii.extractor.Extractor
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.server.MinecraftServer
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
class Fuels : Extractor.Extractor {
override fun fileName(): String {
return "fuels.json"
}
override fun extract(server: MinecraftServer): JsonElement {
val fuelsJson = JsonObject()
// Query vanilla runtime methods
server.fuelValues().fuelItems().forEach { fuel ->
val itemId = BuiltInRegistries.ITEM.getKey(fuel).toString()
val burnDuration = server.fuelValues().burnDuration(ItemStack(fuel))
fuelsJson.add(itemId, JsonPrimitive(burnDuration))
}
return fuelsJson
}
}
```
### Step 3: Register the Extractor
Open `src/main/kotlin/de/snowii/extractor/Extractor.kt` and add an instance of your class to the `extractors` array:
```kotlin
val extractors = arrayOf(
// ... existing extractors ...
Blocks(),
Items(),
Entities(),
Fuels(), // [!code ++]
)
```
### Step 4: Run the Extractor
Execute the headless server task in the Extractor repository:
```bash
./gradlew runServer
```
Once the extraction finishes, locate your new JSON file in:
```text
run/pumpkin_extractor_output/<your_file>.json
```
### Step 5: Integrate with `pumpkin-codegen`
1. Move the generated JSON file into Pumpkin:
```bash
cp run/pumpkin_extractor_output/fuels.json ../Pumpkin/assets/
```
2. In the `Pumpkin` repository, open `tools/pumpkin-codegen`:
- Create a parser for `<your_file>.json`.
- Write a code generation template to produce the corresponding Rust structs or static lookup tables in `crates/pumpkin-data`.
3. Run code generation:
```bash
cargo run -p pumpkin-codegen
```
4. Verify that `pumpkin-data` compiles and passes all unit tests:
```bash
cargo test -p pumpkin-data
```
---
## Best Practices for Extractor Contributions
- **Sort Keys Deterministically**: When generating JSON objects or lists, sort entries by numeric registry ID or alphabetically by identifier (`minecraft:stone`, `minecraft:dirt`). This prevents noisy git diffs when re-running extraction across updates.
- **Prefer Standard Types**: Use vanilla identifiers (`net.minecraft.resources.Identifier`) as string keys instead of arbitrary integers where possible.
- **Access Wideners**: If private vanilla fields or methods need to be accessed, declare an access widener in `src/main/resources/extractor.accesswidener` rather than resorting to brittle runtime reflection.

View File

@ -0,0 +1,121 @@
# Adding an Item Behavior
This guide details how to implement custom interactive mechanics for an item in Pumpkin.
---
## When Is an Item Behavior Needed?
- **Passive Items** (e.g., diamonds, gold ingots, sticks): Do **not** require custom Rust code. Their stack sizes, tool categories, and crafting recipes are handled automatically by `pumpkin-data` and `pumpkin-inventory`.
- **Interactive Items** (e.g., snowballs, ender pearls, hoes, bows, potions): Require an implementation of `ItemBehaviour` to handle right-click events, cooldowns, animations, and entity spawns.
---
## Step 1: Define the Item Struct & Metadata
Create a new file under `crates/pumpkin/src/item/items/<item_name>.rs` (e.g., `items/snowball.rs`):
```rust
use std::sync::Arc;
use pumpkin_data::entity::EntityType;
use pumpkin_data::item::Item;
use pumpkin_data::sound::{Sound, SoundCategory};
use crate::entity::Entity;
use crate::entity::player::Player;
use crate::entity::projectile::snowball::SnowballEntity;
use crate::item::{ItemBehaviour, ItemMetadata};
pub struct SnowBallItem;
// 1. Declare the associated numeric Item ID(s)
impl ItemMetadata for SnowBallItem {
fn ids() -> Box<[u16]> {
[Item::SNOWBALL.id].into()
}
}
// 2. Implement the interaction behavior
impl ItemBehaviour for SnowBallItem {
fn normal_use(&self, _item: &Item, player: &Player) {
let position = player.position();
let world = player.world();
// Play throw sound effect
world.play_sound(
Sound::EntitySnowballThrow,
SoundCategory::Neutral,
&position,
);
// Construct and launch the projectile entity
let entity = Entity::new(world.clone(), position, &EntityType::SNOWBALL);
let snowball = SnowballEntity::new_shot(entity, player.get_entity());
let (yaw, pitch) = player.rotation();
snowball.thrown.set_velocity_from(pitch, yaw, 0.0, 1.5, 1.0);
world.spawn_entity(Arc::new(snowball));
// Safely decrement held item unless in Creative mode
let mut held = player.inventory.held_item();
held.decrement_unless_creative(player.gamemode.load(), 1);
player.inventory.set_held_item(held);
}
}
```
---
## Step 2: `ItemBehaviour` Hook Reference
The `ItemBehaviour` trait provides comprehensive hooks for different interaction models:
### Instant Single-Use Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `normal_use` | `(&self, item: &Item, player: &Player)` | Triggered on right-clicking into open air. |
| `normal_use_with_rotation` | `(&self, item: &Item, player: &Player, yaw: f32, pitch: f32)` | Provides client-reported view angles for precise raycasting and aiming. |
| `use_on_block` | `(&self, item: &mut ItemStack, player: &Player, location: BlockPos, face: BlockDirection, cursor_pos: Vector3<f32>, block: &Block, server: &Server) -> BlockActionResult` | Triggered when right-clicking a block face (e.g., stripping logs with an axe, tilling farmland with a hoe). |
| `use_on_entity` | `(&self, item: &mut ItemStack, player: &Player, entity: Arc<dyn EntityBase>)` | Triggered when right-clicking another living entity (e.g., shearing sheep, nametags). |
### Channeled & Timed Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `get_use_duration` | `(&self) -> i32` | Duration in game ticks required to complete the action (e.g., `32` ticks for food, `72000` ticks for bows). |
| `on_use_tick` | `(&self, stack: &ItemStack, player: &Player, remaining_use_ticks: i32)` | Executed on each tick while right-click is held. |
| `on_stopped_using` | `(&self, stack: &ItemStack, player: &Player)` | Triggered when the player releases right-click (e.g., firing a charged bow). |
---
## Step 3: Durability & Cooldowns
### Decrementing Stacks Safely
Always use `decrement_unless_creative` to ensure survival players consume items while creative players retain them:
```rust
item_stack.decrement_unless_creative(player.gamemode.load(), 1);
```
### Applying Cooldowns
To prevent action spamming (e.g., Ender Pearls, Chorus Fruit):
```rust
// Start a 20-tick (1-second) cooldown on Ender Pearls
player.start_cooldown(Item::ENDER_PEARL.registry_key.to_string(), 20);
```
---
## Step 4: Registering the Item
1. Export your module in `crates/pumpkin/src/item/items/mod.rs`:
```rust
pub mod snowball;
```
2. Register the struct in `crates/pumpkin/src/item/registry.rs`:
```rust
items.register(SnowBallItem);
```
When the server initializes, `items.register` maps the IDs declared in `ItemMetadata::ids()` to your behavior instance.

View File

@ -0,0 +1,71 @@
# Item Architecture & Data Components
Items represent portable game objects held in player inventories, hotbars, armor slots, and world containers. In Pumpkin, item handling is divided into two primary subsystems:
1. **Static Data Layer ([`pumpkin-data`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-data))**: Compile-time generated metadata including item IDs, max stack sizes, max durability, tool tier properties, food nutrition, and data components generated by [`pumpkin-codegen`](/developer/codegen).
2. **Dynamic Behavior Layer ([`pumpkin::item`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin/src/item))**: Interactive right-click actions, projectile launching, eating durations, bow charging, and block interactions handled via the `ItemBehaviour` trait.
---
## Static Items vs. Actionable Items
| Item Type | Description | Examples | Runtime Behavior Struct Needed? |
| :--- | :--- | :--- | :--- |
| **Passive Items** | Items without active right-click effects | `diamond`, `stick`, `iron_ingot`, `feather` | No — Stacking, moving, crafting, and dropping are handled automatically by `pumpkin-inventory`. |
| **Standard Block Items** | Items corresponding directly to placeable blocks | `stone`, `oak_planks`, `glass` | No — Placement logic queries the target block's data. |
| **Projectiles & Throwables** | Items spawned into physical entities when thrown | `snowball`, `egg`, `ender_pearl`, `splash_potion` | Yes — Implements `ItemBehaviour::normal_use`. |
| **Channeled / Charged Items** | Items with use durations or charging animations | `bow`, `crossbow`, `spyglass`, `trident` | Yes — Implements `get_use_duration`, `on_use_tick`, `on_stopped_using`. |
| **Tools with Block Interactions**| Items modifying existing blocks in the world | `hoe` (tilling), `axe` (stripping), `shovel` (pathmaking) | Yes — Implements `ItemBehaviour::use_on_block`. |
---
## The `ItemStack` Structure
An `ItemStack` represents an instance of an item in an inventory container. It encapsulates:
- **`item`**: Reference to the static [`Item`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-data/src/item.rs) definition.
- **`item_count`**: Current stack size ($1 \le \text{count} \le \text{max\_stack\_size}$).
- **Data Components**: Dynamic properties attached to the item stack (custom names, lore, damage values, enchantments, potion effects).
```rust
use pumpkin_data::item::Item;
use pumpkin_data::item_stack::ItemStack;
// Create a new item stack
let mut stack = ItemStack::new(1, Item::DIAMOND_SWORD);
// Safely decrement stack count, respecting creative mode
stack.decrement_unless_creative(player.gamemode.load(), 1);
```
---
## Data Components System
Modern Minecraft represents item properties via modular **Data Components**:
| Component | Responsibility | Description |
| :--- | :--- | :--- |
| `FoodImpl` | Nutrition & Saturation | Controls hunger points restored and saturation ratio. |
| `ConsumableImpl` | Consumption Mechanics | Controls eating duration, sound effects, and animation types. |
| `Damageable` | Durability | Tracks current damage points and breaks when max durability is reached. |
| `UseCooldown` | Cooldown Group | Prevents item re-use for a specified duration in game ticks. |
| `Enchantments` | Enchantment Levels | Key-value mapping of applied enchantments and levels. |
---
## The Item Registry & Dispatch Architecture
Item interactions are managed by the `ItemRegistry` in [`crates/pumpkin/src/item/registry.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/item/registry.rs):
1. **Registration**: At server startup, all `ItemBehaviour` implementations are registered along with their target numeric item IDs.
2. **Interaction Routing**: When a client sends use packets (`CUseItem`, `CUseItemOn`), Pumpkin evaluates cooldowns and routes execution to the registered `ItemBehaviour`.
3. **Cooldown System**: Players track active cooldowns keyed by cooldown group strings. If an item is on cooldown, interactions are canceled before calling the behavior.
---
## Next Steps
To implement interactive mechanics for a new item, proceed to the practical guide:
- **[Adding an Item](/developer/items/adding-items)**: Step-by-step instructions for implementing `ItemMetadata`, `ItemBehaviour`, managing cooldowns, and registering items.

View File

@ -0,0 +1,182 @@
# Adding a Bedrock Edition Packet
This guide explains how to implement, encode, decode, and handle a new Minecraft: Bedrock Edition packet in Pumpkin.
---
## Naming Conventions
- **Clientbound packets** (Server → Client) must start with **`C`** (e.g., `CChunkRadiusUpdated`, `CContainerOpen`).
- **Serverbound packets** (Client → Server) must start with **`S`** (e.g., `SRequestChunkRadius`, `SPlayerAction`).
---
## Step 1: Identifying the Packet ID
In the Bedrock protocol, packet IDs are fixed integer constants assigned by Mojang. Verify the numeric ID from the official protocol documentation or network packet traces.
For example:
- `Disconnect` packet ID: `5`
- `RequestChunkRadius` packet ID: `69`
---
## Step 2: Implementing a Clientbound Packet
Clientbound packets implement the `PacketWrite` trait from `pumpkin-protocol::serial`.
### 1. Create the Packet File
Place the file in `crates/pumpkin-protocol/src/bedrock/client/<packet_name>.rs`:
```rust
use std::io::{Error, Write};
use pumpkin_macros::packet;
use crate::{codec::var_int::VarInt, serial::PacketWrite};
#[packet(5)]
pub struct CDisconnect {
pub reason: VarInt,
pub skip_message: bool,
pub message: String,
pub filtered_message: String,
}
impl CDisconnect {
#[must_use]
pub const fn new(reason: i32, message: String) -> Self {
Self {
reason: VarInt(reason),
skip_message: message.is_empty(),
message,
filtered_message: String::new(),
}
}
}
impl PacketWrite for CDisconnect {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.reason.write(writer)?;
self.skip_message.write(writer)?;
if !self.skip_message {
self.message.write(writer)?;
self.filtered_message.write(writer)?;
}
Ok(())
}
}
```
### 2. Export the Module
In `crates/pumpkin-protocol/src/bedrock/client/mod.rs`:
```rust
pub mod disconnect;
pub use disconnect::*;
```
---
## Step 3: Implementing a Serverbound Packet
Serverbound packets implement the `PacketRead` trait. Pumpkin provides a procedural derive macro `#[derive(PacketRead)]` for automatic deserialization when fields implement `PacketRead`.
### 1. Create the Packet File
Place the file in `crates/pumpkin-protocol/src/bedrock/server/<packet_name>.rs`:
```rust
use pumpkin_macros::packet;
use crate::{codec::var_int::VarInt, serial::PacketRead};
#[derive(PacketRead, Debug)]
#[packet(69)]
pub struct SRequestChunkRadius {
pub chunk_radius: VarInt,
pub max_chunk_radius: u8,
}
```
If a packet requires custom parsing logic, implement `PacketRead` manually:
```rust
use std::io::{Error, Read};
use crate::serial::PacketRead;
impl PacketRead for SMyCustomPacket {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let chunk_radius = VarInt::read(reader)?;
let max_chunk_radius = u8::read(reader)?;
Ok(Self { chunk_radius, max_chunk_radius })
}
}
```
### 2. Export the Module
In `crates/pumpkin-protocol/src/bedrock/server/mod.rs`:
```rust
pub mod request_chunk_radius;
pub use request_chunk_radius::*;
```
---
## Step 4: Dispatching Incoming Packets in `pumpkin`
Incoming packets are dispatched in `crates/pumpkin/src/net/bedrock/mod.rs`:
```rust
// Inside BedrockClient::handle_game_packet
match packet.id {
SRequestChunkRadius::PACKET_ID => {
let packet = SRequestChunkRadius::read(reader)?;
self.handle_request_chunk_radius(player, &packet);
}
_ => {}
}
```
---
## Step 5: Implementing the Handler Function
Implement the handler logic in `crates/pumpkin/src/net/bedrock/play/<packet_name>.rs`:
```rust
use super::*;
use pumpkin_protocol::bedrock::server::request_chunk_radius::SRequestChunkRadius;
impl BedrockClient {
pub fn handle_request_chunk_radius(&self, player: &Arc<Player>, packet: &SRequestChunkRadius) {
let requested_radius = packet.chunk_radius.0;
// Clamp view distance within server configuration limits
let clamped = requested_radius.clamp(2, 16);
// Notify client that view radius was accepted
self.try_enqueue_client_packet(&CChunkRadiusUpdated {
chunk_radius: VarInt(clamped),
});
}
}
```
Remember to register the new module in `crates/pumpkin/src/net/bedrock/play/mod.rs`:
```rust
pub mod request_chunk_radius;
```
---
## Step 6: Sending Outgoing Packets
To send a Bedrock packet to a connected client:
```rust
// Enqueues the packet into the client's outgoing batch queue
self.try_enqueue_client_packet(&CChunkRadiusUpdated {
chunk_radius: VarInt(view_distance),
});
```
Batched packets are automatically compressed, framed with `0xfe`, and transmitted over the RakNet/NetherNet socket.

View File

@ -0,0 +1,61 @@
# Bedrock Edition Authentication
Minecraft: Bedrock Edition implements a certificate chain authentication protocol based on JSON Web Tokens (JWT) cryptographically anchored to Microsoft / Xbox Live root public keys.
Authentication handling is powered by the [`pumpkin-auth`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-auth) crate and processed during the Bedrock login handshake in `crates/pumpkin/src/net/bedrock/login/`.
---
## The Handshake Flow
When a Bedrock client initiates connection, it sends an `SLogin` packet containing the client's protocol version, an **Identity Chain**, and **Client Data**:
1. **Token Acquisition**: The Bedrock client signs into Xbox Live, obtaining a chained JSON Web Token (JWT) certificate signed by Microsoft's CA.
2. **Login Transmission**: The client packages this identity chain alongside a separate `ClientData` JWT into `SLogin`.
3. **Chain Validation**: Pumpkin walks the certificate chain, verifying each token's signature against Mojang's public root keys and extracting the player's Xbox User ID (XUID), Gamertag, and ephemeral session public key.
4. **Hardware Verification**: Pumpkin verifies the `ClientData` payload using the client's ephemeral public key, extracting geometry, skins, and device OS telemetry.
5. **Session Authorization**: Once validated, Pumpkin emits `CPlayStatus` (Login Success) and progresses to resource pack negotiation.
---
## Token Payloads
### 1. Identity Chain (`Chain`)
An array of JWT tokens forming an unbroken chain of trust:
- **Root Token**: Cryptographically signed by Mojang's official public root certificate authority.
- **Intermediate Tokens**: Issued by Xbox Live services, verifying the player's Xbox Live User ID (**XUID**), gamertag, and generating an ephemeral ECDSA public key for the session.
- **Claims**: Includes `extraData` with `displayName`, `identity` (UUID), `XUID`, and `titleId`.
### 2. Client Data (`ClientData`)
A separate JWT signed with the client's ephemeral private key corresponding to the public key in the identity chain:
- **Hardware & Environment**: `DeviceOS`, `DeviceModel`, `CurrentInputMode`, `DefaultInputMode`, `ClientRandomId`.
- **Game Version**: `GameVersion` string.
- **Player Cosmetics**: Full skin texture bitmaps, cape data, geometry names, and persona definitions.
---
## Verification in `pumpkin-auth`
Pumpkin verifies token signatures using **NIST P-384 ECDSA** cryptography:
```rust
// In crates/pumpkin/src/net/bedrock/login/mod.rs
match AuthPayload::verify(&jwt_payload) {
Ok(profile) => {
// Successfully verified against Mojang public keys
info!("Authenticated Bedrock player: {} (XUID: {})", profile.name, profile.xuid);
}
Err(LoginError::ChainValidationFailed(err)) => {
warn!("Bedrock JWT chain validation failed: {err}");
self.try_kick(DisconnectReason::Kicked, "Authentication failed".into());
}
Err(LoginError::SelfSignedNotAllowed) => {
warn!("Rejected unauthenticated self-signed Bedrock client");
self.try_kick(DisconnectReason::Kicked, "Server enforces Xbox Live authentication".into());
}
}
```
### Online vs. Offline Mode
- **Online Mode** (`online_mode = true` in `pumpkin.toml`): The chain must successfully validate against Mojang's public keys. Self-signed or unsigned tokens are immediately rejected.
- **Offline Mode** (`online_mode = false`): Pumpkin accepts self-signed client chains, generating offline UUIDs while extracting cosmetic skins and device metadata.

View File

@ -0,0 +1,61 @@
# NetherNet WebRTC Transport
**NetherNet** is Mojang's modern, WebRTC-based transport protocol for Minecraft: Bedrock Edition. Designed for high-resilience peer-to-peer and relayed communication, NetherNet enables seamless cross-platform multiplayer (mobile, console, desktop) without requiring server operators or players to configure router port-forwarding.
Pumpkin provides a native, zero-dependency NetherNet implementation in [`crates/pumpkin/src/net/bedrock/nethernet.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/net/bedrock/nethernet.rs).
---
## Architectural Layers
| Layer | Implementation | Responsibility |
| :--- | :--- | :--- |
| **HTTP Signaling** | Axum HTTP Router (`ice_router.rs`) | Handles SDP Offer (`POST /offer`), SDP Answer (`GET /answer`), and ICE Candidates (`POST /candidate`) |
| **NAT Traversal** | ICE Agent | Coordinates STUN/TURN binding discovery and hole punching |
| **Transport Security** | DTLS Handshake | Generates ephemeral session keys and secures the WebRTC transport using ECDSA P-384 keys |
| **Data Delivery** | WebRTC DataChannels | Unordered/ordered datagram channels streaming standard Bedrock game batches to the dispatcher |
---
## Core Components in Pumpkin
Pumpkin's NetherNet subsystem is divided into four distinct modules:
### 1. Cryptographic Identity (`nethernet-key.der`)
- Pumpkin generates and loads a **NIST P-384 ECDSA private key** (`nethernet-key.der`).
- Used to cryptographically sign session descriptions (SDP offers and answers), authenticating the server's identity to connecting clients.
- Encoded using standard PKCS#8 DER formatting.
### 2. HTTP Signaling Router (`ice_router.rs`)
Signaling is handled over HTTP via an [Axum](https://github.com/tokio-rs/axum) router:
- **`POST /offer`**: The client submits an SDP offer describing its WebRTC codecs, transport profiles, and network interfaces.
- **`GET /answer`**: Pumpkin generates a corresponding local SDP answer containing its negotiated capabilities.
- **`POST /candidate`**: Both endpoints exchange trickle ICE candidates to discover the fastest direct network path (host, server-reflexive, or relay).
### 3. Local Network Discovery (`discovery.rs`)
- Listens and broadcasts availability on the local subnet via UDP multicast.
- Allows Bedrock clients on the same Wi-Fi or LAN to discover and connect to the Pumpkin server automatically without entering an IP address.
### 4. DataChannel Packet Streaming
- Once the WebRTC peer connection transitions to the `Connected` state, an ordered, reliable **WebRTC DataChannel** is opened.
- Bedrock batch packets (`0xfe`) flow bidirectionally through the DataChannel directly into Pumpkin's `incoming_game_packet_send` channel.
---
## Configuration in `pumpkin.toml`
NetherNet is configured under `[networking.bedrock.nethernet]` in `pumpkin.toml`:
```toml
[networking.bedrock]
enabled = true
address = "0.0.0.0:19132"
[networking.bedrock.nethernet]
enabled = true
signaling_address = "0.0.0.0:19133"
ice_servers = [
"stun:stun.l.google.com:19302"
]
```

View File

@ -0,0 +1,80 @@
# Bedrock Edition Networking Overview
Pumpkin features native support for **Minecraft: Bedrock Edition** clients (iOS, Android, Windows, Xbox, PlayStation, Switch).
Bedrock protocol structures and wire codecs reside in `pumpkin-protocol::bedrock`, while connection management and gameplay handlers reside in `pumpkin::net::bedrock`.
---
## Transport Layers: RakNet & NetherNet
Unlike Java Edition, which communicates exclusively over TCP streams, Bedrock Edition operates over UDP using two primary transport layers:
1. **RakNet (Port 19132)**:
- A reliable, sequenced UDP networking library originally developed by Jenkins Software.
- Provides connection handshakes, packet acknowledgment (ACK/NACK), MTU negotiation, and packet splitting for payloads larger than the network MTU.
2. **NetherNet**:
- Modern peer-to-peer and relayed transport protocol used by modern Bedrock versions.
- Integrated in Pumpkin via `crates/pumpkin/src/net/bedrock/nethernet.rs`.
---
## Packet Framing & Batching (`0xfe`)
Bedrock does not send individual game packets over the network directly. Instead, multiple game packets are bundled into a single **batch packet**:
1. **Header Byte**: Every Bedrock game packet batch starts with `0xfe`.
2. **Compression**: The payload following `0xfe` is compressed using **Deflate** (or ZLib) above a negotiated threshold.
3. **Sub-packet Framing**: When decompressed, the batch contains one or more sequential game packets, each prefixed by its length encoded as a `VarUInt`.
In Pumpkin, batch decoding and assembly are managed by `BedrockBatchDecoder` and `BedrockBatchEncoder` in `crates/pumpkin-protocol/src/bedrock/`.
---
## Connection Lifecycle & State Progression
Bedrock does not have explicit protocol states like Java Edition. Instead, it follows a strict sequence of packets:
| Step | Packet Exchanged | Purpose |
| :--- | :--- | :--- |
| **1. Network Settings** | `SRequestNetworkSettings` -> `CNetworkSettings` | Negotiates compression algorithm (Deflate/Snappy) and payload threshold |
| **2. Authentication** | `SLogin` -> `CPlayStatus` | Transmits JWT identity chain and client hardware data; verifies Xbox Live tokens |
| **3. Resource Negotiation** | `CResourcePacksInfo` -> `SResourcePackClientResponse` | Negotiates server resource packs and download behavior |
| **4. World Initialization** | `CStartGame` + `CItemRegistry` + `CCreativeContent` | Streams world spawn position, dimension settings, runtime player entity ID, and item palettes |
| **5. Ready to Spawn** | `SSetLocalPlayerAsInitialized` -> `CPlayStatus` | Signals client loading completion and transitions to active in-game play |
---
## Packet Dispatching in `pumpkin`
Inside `crates/pumpkin/src/net/bedrock/mod.rs`, decompressed sub-packets are dispatched based on their numeric packet ID:
```rust
match packet.id {
SPlayerAuthInput::PACKET_ID => {
let packet = SPlayerAuthInput::read(reader)?;
self.handle_player_auth_input(player, packet, server);
}
SRequestChunkRadius::PACKET_ID => {
let packet = SRequestChunkRadius::read(reader)?;
self.handle_request_chunk_radius(player, &packet);
}
SInventoryTransaction::PACKET_ID => {
let packet = SInventoryTransaction::read(reader)?;
self.handle_inventory_action(player, packet);
}
_ => {
trace!("Unhandled Bedrock packet ID: {}", packet.id);
}
}
```
---
## Authentication & NetherNet
- **JWT Authentication**: Bedrock verifies player identities via certificate chains signed by Microsoft / Xbox Live root authorities.
- **NetherNet WebRTC**: High-performance peer-to-peer transport using WebRTC DataChannels, ICE NAT traversal, and P-384 ECDSA keys.
For complete implementation details, see **[Bedrock Authentication & NetherNet](/developer/networking/bedrock/authentication)**.

View File

@ -0,0 +1,49 @@
# Networking Overview
Pumpkin is built with a high-performance, asynchronous networking stack capable of servicing both **Minecraft: Java Edition** and **Minecraft: Bedrock Edition** clients simultaneously.
All protocol definitions, serialization traits, and wire-level codecs are isolated in the [`pumpkin-protocol`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-protocol) crate, while client connection management, session state machines, and gameplay packet dispatching are managed in [`pumpkin/src/net`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin/src/net).
---
## Supported Editions
Pumpkin separates network implementations by edition due to their fundamentally distinct transport layers, packet encodings, and state models:
| Feature | Minecraft: Java Edition | Minecraft: Bedrock Edition |
| :--- | :--- | :--- |
| **Transport Layer** | TCP socket streams | UDP via RakNet & NetherNet |
| **Framing** | VarInt length-prefixed frames | Batched packets encapsulated in `0xfe` headers |
| **Encryption** | AES-128 / CFB8 stream cipher | Cryptographic session handshake |
| **Compression** | Per-packet ZLib (above configurable threshold) | Per-batch Deflate / ZLib compression |
| **State Model** | Explicit states: Handshake, Status, Login, Config, Play | Packet-driven state progression |
| **Protocol Crate** | `pumpkin-protocol::java` | `pumpkin-protocol::bedrock` |
| **Server Net Module** | `pumpkin::net::java` | `pumpkin::net::bedrock` |
---
## Networking Architecture
The networking pipeline routes incoming connections through specialized transport and codec layers before delegating to the unified server game loop:
1. **Transport Listeners**: Independent listeners bind to their respective ports—Tokio TCP for Java Edition (`:25565`) and UDP/RakNet/NetherNet for Bedrock Edition (`:19132`).
2. **Session Abstraction**: Each accepted connection spawns an isolated session task (`JavaClient` or `BedrockClient`) managing wire framing and encryption.
3. **Codec Deserialization**: Wire bytes are deserialized into typed packet structs via `pumpkin-protocol::java` (`ClientPacket`/`ServerPacket`) and `pumpkin-protocol::bedrock` (`PacketWrite`/`PacketRead`).
4. **Unified Gameplay Dispatch**: Decoded packets are dispatched into the unified game loop, updating player entity states and streaming world chunks.
---
## Navigating the Networking Docs
Explore the documentation for each edition:
- **[Entity Metadata & Synced Data](/developer/networking/metadata)**: Synchronization of visual entity states (DataWatchers in Java, Actor Data in Bedrock).
- **[Java Edition](/developer/networking/java/overview)**:
- **[Architecture & Lifecycle](/developer/networking/java/overview)**: State machine, `JavaClient` vs. `Player`, and multi-version negotiation.
- **[How to Add a Packet](/developer/networking/java/adding-packets)**: Guide to defining, serializing, and dispatching Java Edition packets.
- **[Authentication](/developer/networking/java/authentication)**: Mojang Yggdrasil validation, GameProfiles, and proxy forwarding.
- **[Bedrock Edition](/developer/networking/bedrock/overview)**:
- **[Architecture & Transports](/developer/networking/bedrock/overview)**: RakNet and NetherNet integration, batching, and session handling.
- **[How to Add a Packet](/developer/networking/bedrock/adding-packets)**: Guide to defining and handling Bedrock Edition packets.
- **[Authentication & NetherNet](/developer/networking/bedrock/authentication)**: JWT certificate chain verification, WebRTC DataChannels, P-384 keys, and signaling.
- **[RCON](/developer/networking/rcon)**: Implementation of Valve's Remote Console protocol for administrative management.

View File

@ -0,0 +1,205 @@
# Adding a Java Edition Packet
This guide walks you through implementing, serializing, dispatching, and sending a new Java Edition packet in Pumpkin.
---
## Naming Conventions
To keep packet definitions uniform across the codebase, follow these naming conventions:
- **Clientbound packets** (Server → Client) must start with **`C`** (e.g., `CBlockUpdate`, `CPlayDisconnect`).
- **Serverbound packets** (Client → Server) must start with **`S`** (e.g., `SChatCommand`, `SPlayerPosition`).
- If a packet exists in multiple states, prefix the state name before the packet action (e.g., `CLoginDisconnect`, `CConfigDisconnect`, and `CPlayDisconnect`).
---
## Step 1: Find the Packet ID in `pumpkin-data`
Packet IDs across all supported Minecraft versions are maintained in `pumpkin-data`. Import the corresponding constant:
```rust
// Clientbound Play state disconnect
use pumpkin_data::packet::clientbound::play::DISCONNECT;
// Serverbound Play state player position
use pumpkin_data::packet::serverbound::play::MOVE_PLAYER_POS;
```
---
## Step 2: Implementing a Clientbound Packet
Clientbound packets are sent from Pumpkin to the Minecraft client. They implement the `ClientPacket` trait from `pumpkin-protocol`.
### 1. Create the Struct File
Place the file in `crates/pumpkin-protocol/src/java/client/<state>/<packet_name>.rs` (e.g., `play/disconnect.rs`):
```rust
use std::io::Write;
use pumpkin_data::packet::clientbound::play::DISCONNECT;
use pumpkin_macros::java_packet;
use pumpkin_protocol::ClientPacket;
use pumpkin_protocol::ser::{NetworkWriteExt, WritingError};
use pumpkin_util::text::TextComponent;
use pumpkin_util::version::JavaMinecraftVersion;
/// Displays a disconnect screen with a message to the player in Play state.
#[java_packet(DISCONNECT)]
pub struct CPlayDisconnect<'a> {
pub reason: &'a TextComponent,
}
impl<'a> CPlayDisconnect<'a> {
#[must_use]
pub const fn new(reason: &'a TextComponent) -> Self {
Self { reason }
}
}
impl ClientPacket for CPlayDisconnect<'_> {
fn write_packet_data(
&self,
mut write: impl Write,
version: &JavaMinecraftVersion,
) -> Result<(), WritingError> {
// Use NetworkWriteExt methods to serialize fields
write.write_component(self.reason, version)
}
}
```
### 2. Export the Module
In `crates/pumpkin-protocol/src/java/client/<state>/mod.rs`:
```rust
mod disconnect;
pub use disconnect::*;
```
---
## Step 3: Implementing a Serverbound Packet
Serverbound packets are received by Pumpkin from the game client. They implement the `ServerPacket` trait from `pumpkin-protocol`.
### 1. Create the Struct File
Place the file in `crates/pumpkin-protocol/src/java/server/<state>/<packet_name>.rs` (e.g., `play/player_position.rs`):
```rust
use pumpkin_data::packet::serverbound::play::MOVE_PLAYER_POS;
use pumpkin_macros::java_packet;
use pumpkin_protocol::ServerPacket;
use pumpkin_protocol::ser::{NetworkReadExt, ReadingError};
use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(MOVE_PLAYER_POS)]
pub struct SPlayerPosition {
pub position: Vector3<f64>,
pub collision: u8,
}
impl<'a> ServerPacket<'a> for SPlayerPosition {
fn read(bytebuf: &mut &'a [u8], version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
let x = bytebuf.get_f64_be()?;
let y = bytebuf.get_f64_be()?;
// Handle version-specific fields if necessary
if *version <= JavaMinecraftVersion::V_1_7_6 {
let _stance = bytebuf.get_f64_be()?;
}
let z = bytebuf.get_f64_be()?;
let collision = bytebuf.get_u8()?;
Ok(Self {
position: Vector3::new(x, y, z),
collision,
})
}
}
```
### 2. Export the Module
In `crates/pumpkin-protocol/src/java/server/<state>/mod.rs`:
```rust
mod player_position;
pub use player_position::*;
```
---
## Step 4: Network Codec Extension Helpers
`NetworkWriteExt` and `NetworkReadExt` provide helper methods for standard Minecraft types:
| Data Type | Reading Method | Writing Method |
| :--- | :--- | :--- |
| **`VarInt`** | `bytebuf.get_var_int()?` | `write.write_var_int(val)?` |
| **`VarLong`** | `bytebuf.get_var_long()?` | `write.write_var_long(val)?` |
| **`String`** | `bytebuf.get_string()?` | `write.write_string(val)?` |
| **`UUID`** | `bytebuf.get_uuid()?` | `write.write_uuid(&val)?` |
| **`TextComponent`** | `bytebuf.get_component()?` | `write.write_component(val, version)?` |
| **`Position`** | `bytebuf.get_block_pos()?` | `write.write_block_pos(val)?` |
| **`NBT`** | `bytebuf.get_nbt()?` | `write.write_nbt(&val)?` |
---
## Step 5: Handling Incoming Packets in `pumpkin`
Incoming serverbound packets must be handled in the appropriate state handler in `crates/pumpkin/src/net/java/`.
For packets in the **Play state**, open `crates/pumpkin/src/net/java/mod.rs` and update `handle_play_packet`:
```rust
// In crates/pumpkin/src/net/java/mod.rs
pub fn handle_play_packet(
&self,
player: &Arc<Player>,
server: &Arc<Server>,
packet: &RawPacket,
) -> Result<(), Box<dyn PumpkinError>> {
let version = self.version.load();
let mut payload = &packet.payload[..];
match packet.id {
// Match against version-specific packet ID
id if id == SPlayerPosition::to_id(version) => {
let packet = SPlayerPosition::read(&mut payload, &version)?;
self.handle_player_position(player, &packet);
}
_ => {}
}
Ok(())
}
```
Then implement the handler function:
```rust
impl JavaClient {
pub fn handle_player_position(&self, player: &Arc<Player>, packet: &SPlayerPosition) {
// Validate coordinates, update player position, check collisions
player.set_position(packet.position);
}
}
```
---
## Step 6: Sending Outgoing Packets
To send a clientbound packet to a player:
```rust
// 1. Send directly to a player's connection
player.client.send_packet(&CPlayDisconnect::new(&reason));
// 2. Broadcast to all players watching a chunk
world.broadcast_packet_except(
&[player.gameprofile.id],
&CBlockUpdate::new(block_pos, block_id),
).await;
```

View File

@ -0,0 +1,83 @@
# Java Edition Authentication
Authentication verifies the identity of players connecting to Pumpkin to prevent username spoofing and account impersonation.
Pumpkin handles authentication in the [`pumpkin-auth`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-auth) crate and orchestrates it during the `Login` state in `crates/pumpkin/src/net/java/login/`.
---
## Why Authentication Matters
Offline (non-authenticated) accounts generate player UUIDs strictly based on their offline username string (`UUID::new_v3(...)`). Without verification, any user can join using the username of an operator or administrator and gain privileged access.
In online mode (`online_mode = true` in `pumpkin.toml`), Pumpkin cryptographically verifies with Mojang's session servers that the connecting client owns the requested account.
---
## How Yggdrasil Authentication Works
The authentication exchange between the client, Pumpkin, and Mojang's Yggdrasil servers follows these steps:
1. **Initiation**: The client sends `SLoginStart` declaring its desired username and optional offline UUID.
2. **Key Exchange**: Pumpkin replies with `CEncryptionBegin`, providing a random 4-byte verify token, the server ID string, and Pumpkin's 1024-bit RSA public key.
3. **Session Join**: The client generates a random 16-byte shared secret (`AES-128`), computes a SHA-1 server hash, and calls Mojang's session server (`POST /session/minecraft/join`) using its authenticated Microsoft access token.
4. **Verification**: The client sends `SEncryptionResponse` containing the RSA-encrypted shared secret and encrypted verify token. Pumpkin decrypts the token with its RSA private key, recalculates the SHA-1 digest, and queries Mojang (`GET /session/minecraft/hasJoined`).
5. **Profile Retrieval**: Mojang validates that the client and server hashes match, returning the authenticated player's UUID, username, and signed skin/cape texture properties (`GameProfile`).
6. **Encryption Activation**: Pumpkin activates full-stream symmetric encryption (`AES-128/CFB8`) and completes the login sequence by sending `CLoginSuccess`.
---
## Game Profile Structure
When Mojang's `hasJoined` endpoint validates a session, it returns a `GameProfile` containing the player's authenticated UUID, username, and signed texture properties:
```rust
pub struct GameProfile {
pub id: Uuid,
pub name: String,
pub properties: Vec<Property>,
pub profile_actions: Option<Vec<ProfileAction>>,
}
pub struct Property {
pub name: String,
pub value: String, // Base64 encoded texture data
pub signature: Option<String>, // Cryptographic signature verifying authenticity
}
```
Pumpkin verifies that skin and cape signatures are cryptographically signed with Mojang's public key to prevent clients from injecting malicious payloads or unauthorized textures.
---
## Custom Authentication Endpoints
For private networks or enterprise environments running custom Yggdrasil-compatible authentication servers, endpoints can be customized in `pumpkin.toml`:
```toml
[networking.java.authentication]
enabled = true
fallbacks = []
connect_timeout = 5000
read_timeout = 5000
prevent_proxy_connections = false
[networking.java.authentication.player_profile]
allow_banned_players = false
allowed_actions = ["FORCED_NAME_CHANGE", "USING_BANNED_SKIN"]
[networking.java.authentication.textures]
enabled = true
allowed_url_schemes = ["http", "https"]
allowed_url_domains = [".minecraft.net", ".mojang.com"]
```
---
## Proxy Authentication Forwarding
When running Pumpkin behind proxies, client connections terminate at the proxy. Pumpkin supports the three primary proxy forwarding standards:
- **Velocity Modern Forwarding**: Validates player data forwarded with HMAC-SHA256 secret tokens (`[networking.proxy.velocity]`).
- **BungeeGuard**: Token-based authentication header validation for BungeeCord setups.
- **Legacy BungeeCord**: Handshake forwarding appending IP, UUID, and properties to the server host string.

View File

@ -0,0 +1,74 @@
# Java Edition Networking Overview
The Java Edition network stack handles standard Minecraft PC clients connecting over TCP. Wire-level structures and serialization logic reside in `pumpkin-protocol::java`, while connection management and gameplay packet handlers reside in `pumpkin::net::java`.
---
## The Five Protocol States
The Minecraft Java protocol operates as an explicit finite state machine. Every connection begins in the `Handshake` state and transitions according to client requests and server responses:
| State | Transition Trigger | Purpose & Next State |
| :--- | :--- | :--- |
| **Handshake** | Client initiates connection | Inspects protocol version and transitions to `Status`, `Login`, or `Transfer` |
| **Status** | `NextState = 1` | Streams MOTD, active player counts, favicon, and ping response |
| **Login** | `NextState = 2` | Authenticates account (Yggdrasil), negotiates encryption (AES-128), transitions to `Config` |
| **Transfer** | `NextState = 3` | Modern proxy / server-transfer negotiation |
| **Config** | Authentication success | Exchanges dynamic registries, data tags, feature flags, and resource packs |
| **Play** | Configuration acknowledged | Primary bidirectional gameplay loop (chunks, movement, combat, chat) |
1. **Handshake (`0x00`)**: Always the first packet sent by the client. It declares the client's protocol version, server address, port, and desired next state (`Status`, `Login`, or `Transfer`).
2. **Status**: Lightweight query state. The client requests a server list ping, and Pumpkin responds with the server version, player counts, favicon, and MOTD.
3. **Login**: Authenticates the player. If `online_mode` is enabled, Pumpkin performs an encryption handshake (AES-128/CFB8) and verifies the player's account with Mojang's Yggdrasil session servers.
4. **Config**: Introduced in modern Minecraft (1.20.2+). The server sends feature flags, known registries, resource packs, and custom server links before the player joins the physical world.
5. **Play**: The primary gameplay state. Used for all in-game actions including block breaking, entity movement, combat, chat, and chunk streaming.
---
## Connection Representation: `JavaClient` vs. `Player`
To keep memory usage minimal and prevent unnecessary allocations, Pumpkin cleanly separates pre-play connections from active players:
### `JavaClient`
- **Scope**: Exists across `Handshake`, `Status`, `Login`, and `Config` states.
- **Location**: `crates/pumpkin/src/net/java/mod.rs`.
- **Characteristics**:
- Contains connection metadata: client protocol version, remote address, encryption/compression state.
- Has no world coordinates, no physics, no inventory, and no living entity.
- Very low memory footprint.
### `Player`
- **Scope**: Exists solely during the `Play` state.
- **Location**: `crates/pumpkin/src/entity/player/`.
- **Characteristics**:
- Implements `EntityBase`, representing a living entity inside a `World` and `Level`.
- Holds inventory screens, health, hunger, velocities, and chunk view subscription queues.
- Contains an `Arc<JavaClient>` reference for network transmission.
---
## Multi-Version Support (`JavaMinecraftVersion`)
Pumpkin supports multiple Minecraft client versions. Protocol differences are handled cleanly via `pumpkin_util::version::JavaMinecraftVersion`:
- Packet IDs may differ across Minecraft versions. The `#[java_packet(ID)]` macro works with `pumpkin-data` to resolve the correct ID for the target version.
- When reading or writing packets, methods accept a `&JavaMinecraftVersion` reference to conditionally include or omit fields that changed in specific Minecraft updates.
```rust
if *version <= JavaMinecraftVersion::V_1_7_6 {
// Read legacy stance coordinate present in early Minecraft versions
let _stance = bytebuf.get_f64_be()?;
}
```
---
## The Packet Pipeline
Incoming Java packets pass through a structured pipeline:
1. **Length Framing**: `tokio_util::codec` decodes VarInt frame lengths.
2. **Decompression & Decryption**: If enabled, the raw buffer is decrypted via AES/CFB8 and decompressed via ZLib.
3. **Plugin Event Interception**: A `PacketReceivedEvent` is dispatched to the plugin manager. Plugins can inspect or cancel the packet before server processing.
4. **ID Dispatching**: The packet ID is matched against version-specific constants in `crates/pumpkin/src/net/java/mod.rs` (or the respective state module).
5. **Handling**: The packet struct is deserialized and processed by state-specific handler functions.

View File

@ -0,0 +1,123 @@
# Entity Metadata & Synced Data
Minecraft synchronizes persistent entity visual states, animation flags, poses, and properties via **Entity Metadata** (historically called *DataWatchers* in Java Edition and *Actor Data* in Bedrock Edition).
Instead of transmitting full state packets whenever an entity crouches, catches fire, or takes damage, the server broadcasts compact metadata updates to nearby observers.
---
## Edition Comparison
| Feature | Minecraft: Java Edition | Minecraft: Bedrock Edition |
| :--- | :--- | :--- |
| **Packet Name** | `CSetEntityMetadata` (`SET_ENTITY_DATA`) | `CSetActorData` (Packet ID `39`) |
| **Storage Structure** | `TrackedData` list terminating with `0xFF` | `SyncedActorDataList` (`HashMap<u32, MetadataValue>`) |
| **Key Type** | Index (`u8`) mapped to typed `MetaDataType` | Enum keys (`entity_data_key::*`) |
| **Flags** | Bitfield byte (fire, crouching, sprinting, glowing) | Bitfield int64 (`entity_data_flag::*`) |
| **Dynamic Properties** | N/A (baked into tracked indices) | `PropertySyncData` (client/server sync) |
| **Crate Location** | `crates/pumpkin-protocol/src/java/client/play/entity_metadata.rs` | `crates/pumpkin-protocol/src/bedrock/client/set_actor_data.rs` |
---
## 1. Java Edition: `CSetEntityMetadata`
In Java Edition, entity metadata consists of numbered index entries. Each entry defines an index, a `MetaDataType` ID, and the encoded value. The list terminates with a single `0xFF` byte.
### Key Index Hierarchy
Entity metadata follows an object-oriented inheritance model:
1. **Entity (Base)**:
- `0`: State bitfield (flags: bit `0` = on fire, bit `1` = crouching, bit `3` = sprinting, bit `5` = invisible, bit `6` = glowing).
- `1`: Air supply (`VarInt`).
- `2`: Custom name (optional `TextComponent`).
- `3`: Custom name visible (`bool`).
- `4`: Silent (`bool`).
- `5`: No gravity (`bool`).
- `6`: Pose (`Standing`, `FallFlying`, `Sleeping`, `Swimming`, `SpinAttack`, `Crouching`, `Dying`).
2. **LivingEntity (extends Entity)**:
- `8`: Hand states (using item, active hand).
- `9`: Health (`f32`).
- `10`: Potion effect ambient color.
3. **Player (extends LivingEntity)**:
- Additional hearts, skin customization bitmask, main hand indicator.
### Sending Metadata Updates in Pumpkin
Pumpkin encodes entity metadata in `pumpkin-protocol`:
```rust
use pumpkin_protocol::VarInt;
use pumpkin_protocol::java::client::play::CSetEntityMetadata;
// Construct metadata update for entity with ID 42
let packet = CSetEntityMetadata::new(
VarInt(entity.entity_id),
serialized_metadata_bytes,
);
// Broadcast to chunk observers
world.broadcast_packet_all(&packet).await;
```
---
## 2. Bedrock Edition: `CSetActorData`
Bedrock Edition uses `CSetActorData` (`packet(39)`), storing properties in a dictionary mapping `u32` keys to strongly-typed `MetadataValue` variants.
### Key & Flag Constants
Bedrock exposes flags as a 64-bit integer bitfield under `entity_data_key::FLAGS`:
- `entity_data_flag::ON_FIRE` (`0`): Entity is burning.
- `entity_data_flag::SNEAKING` (`1`): Player is sneaking.
- `entity_data_flag::RIDING` (`2`): Entity is mounted on a vehicle.
- `entity_data_flag::SPRINTING` (`3`): Player is sprinting.
- `entity_data_flag::USING_ITEM` (`4`): Player is actively charging a bow, eating food, or using a shield.
- `entity_data_flag::INVISIBLE` (`5`): Entity is invisible.
- `entity_data_flag::GLOWING` (`26`): Entity has the glowing effect outline.
### Constructing and Updating Actor Data in Pumpkin
In `crates/pumpkin/src/entity/living.rs`:
```rust
use pumpkin_protocol::bedrock::client::set_actor_data::{
CSetActorData, MetadataValue, PropertySyncData, SyncedActorDataList,
entity_data_flag, entity_data_key,
};
let mut actor_data = SyncedActorDataList::new();
// Set entity flags (e.g. actively using an item)
let mut flags: i64 = 0;
if is_using_item {
flags |= 1i64 << entity_data_flag::USING_ITEM;
}
actor_data.set(entity_data_key::FLAGS, MetadataValue::Int64(flags));
// Set air supply
actor_data.set(entity_data_key::AIR_SUPPLY, MetadataValue::Short(air as i16));
// Set custom name tag
actor_data.set(entity_data_key::NAME, MetadataValue::String(name));
let packet = CSetActorData {
target_runtime_id: VarULong(entity_id),
actor_data,
synced_properties: PropertySyncData::default(),
tick: VarULong(current_tick),
};
client.try_enqueue_client_packet(&packet);
```
---
## Multi-Version Compatibility
Because Mojang frequently shifts metadata indices between Minecraft releases, `pumpkin-protocol` leverages translation tables from `pumpkin-data`:
- For Java Edition, `pumpkin_data::meta_data_type::MetaDataType` remaps indices dynamically based on the client's `JavaMinecraftVersion`.
- For Bedrock Edition, `SyncedActorDataList` validates keys against the active Bedrock protocol version to prevent client crashes.

View File

@ -0,0 +1,73 @@
# BungeeCord Forwarding
Pumpkin provides native support for BungeeCord and Waterfall proxy networks, including **BungeeGuard** authentication token verification.
Implementation is located in [`crates/pumpkin/src/net/proxy/bungeecord.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/net/proxy/bungeecord.rs).
---
## How BungeeCord Forwarding Operates
Unlike modern protocols that use custom login channels, BungeeCord operates by encoding client metadata directly into the `server_address` field of the initial `SHandshake` packet.
The string uses null character (`\0`) delimiters:
```text
[original_host]\0[player_ip:port]\0[player_uuid]\0[properties_json]
```
1. **`original_host`**: The domain name the player originally typed into their client.
2. **`player_ip:port`**: The genuine IP address and ephemeral source port of the client.
3. **`player_uuid`**: The player's Mojang UUID (32 hex characters without hyphens or 36 characters with hyphens).
4. **`properties_json`**: A JSON array containing skin textures, cape textures, and Mojang cryptographic signatures.
---
## The Security Risk: Proxy Bypasses
Because BungeeCord's handshake string is unauthenticated plain text, an attacker could connect directly to an exposed backend port, inject an arbitrary UUID and operator username, and gain full server control.
Traditionally, this required strict Linux firewall rules (`iptables` / `ufw`) to restrict port access exclusively to the proxy IP.
---
## BungeeGuard Protection
To eliminate proxy bypasses without relying solely on network firewalls, Pumpkin integrates **BungeeGuard** token verification:
1. The BungeeCord proxy injects a shared secret into the player's profile properties under the key `bungeeguard-token`.
2. When Pumpkin processes the handshake in `bungeecord_login`:
- It checks whether `secret` is configured in `pumpkin.toml`.
- It inspects the forwarded properties for `bungeeguard-token`.
- If the token matches, Pumpkin **strips the secret property** from the player's profile (so other plugins cannot read it) and completes the login.
- If the token is missing or incorrect, Pumpkin rejects the connection with `BungeeCordError::MissingToken` or `BungeeCordError::InvalidToken`.
```rust
// In crates/pumpkin/src/net/proxy/bungeecord.rs
if !secret.is_empty() {
let Some(token_index) = properties.iter().position(|p| p.name == BUNGEEGUARD_TOKEN_PROPERTY) else {
return Err(BungeeCordError::MissingToken);
};
if properties[token_index].value != secret {
return Err(BungeeCordError::InvalidToken);
}
properties.remove(token_index);
}
```
---
## Configuration in `pumpkin.toml`
To enable BungeeCord forwarding with BungeeGuard:
```toml
[networking.proxy]
enabled = true
[networking.proxy.bungeecord]
enabled = true
# Optional: Configure the BungeeGuard shared secret to block direct connections
secret = "YOUR_BUNGEEGUARD_SECRET_HERE"
```

View File

@ -0,0 +1,46 @@
# Proxy Forwarding Overview
In multi-server Minecraft networks, players connect through a front-facing reverse proxy (such as Velocity, BungeeCord, or Vine) that routes connections between lobbies and sub-servers without requiring players to reconnect.
Because backend servers receive TCP connections directly from the proxy machine rather than the player, the server must be informed of the player's genuine **IP address**, **UUID**, **username**, and **skin properties**.
Pumpkin provides native support for all three major proxy forwarding protocols in [`crates/pumpkin/src/net/proxy/`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin/src/net/proxy).
---
## The Proxy Forwarding Problem
Without secure proxy forwarding:
1. **IP Loss**: Every connected player appears with the proxy's loopback or internal IP (breaking IP bans and geo-location).
2. **UUID Spoofing & Bypasses**: Malicious users could connect directly to the backend server's port with any spoofed username or operator identity.
To prevent proxy bypasses, Pumpkin validates cryptographic secrets, tokens, or digital signatures sent by the proxy.
---
## Comparison of Supported Protocols
| Protocol | Protocol Transport | Security / Cryptography | Replay Protection | Crate Module |
| :--- | :--- | :--- | :--- | :--- |
| **[BungeeCord](/developer/networking/proxy/bungeecord)** | `SHandshake` server address string | Optional token in profile properties (`bungeeguard-token`) | None | `pumpkin::net::proxy::bungeecord` |
| **[Velocity](/developer/networking/proxy/velocity)** | Login plugin message (`velocity:player_info`) | Symmetric HMAC-SHA256 signature | None | `pumpkin::net::proxy::velocity` |
| **[Vine](/developer/networking/proxy/vine)** | Login plugin message (`vine:player_info`) | Asymmetric **Ed25519** digital signatures | 16-byte nonce challenge + 30s timestamp window | `pumpkin::net::proxy::vine` |
---
## Lifecycle Architecture
1. **Player Authentication**: The player connects to the proxy (BungeeCord, Velocity, or Vine) and authenticates against Mojang's session servers.
2. **Backend Connection**: The proxy connects to Pumpkin over TCP and sends `SHandshake`.
3. **Data Forwarding**:
- **BungeeCord Mode**: The proxy injects the player's remote IP, UUID, and properties directly into the `SHandshake` hostname string (separated by null bytes `\0`).
- **Modern Mode (Velocity / Vine)**: Pumpkin sends `CLoginPluginRequest` on a dedicated channel (`velocity:player_info` or `vine:player_info`). The proxy signs the player profile using HMAC-SHA256 (Velocity) or Ed25519 (Vine) and replies with `SLoginPluginResponse`.
4. **Validation & Session Initialization**: Pumpkin validates the signature, binds the real IP and GameProfile to the `JavaClient`, and sends `CLoginSuccess`.
---
## Proxy Documentation
- **[BungeeCord](/developer/networking/proxy/bungeecord)**: Legacy host string injection and optional BungeeGuard token validation.
- **[Velocity Modern Forwarding](/developer/networking/proxy/velocity)**: HMAC-SHA256 signed player info during the Login state.
- **[Vine Modern Forwarding](/developer/networking/proxy/vine)**: Next-generation proxy forwarding with Ed25519 signatures and replay attack prevention.

View File

@ -0,0 +1,88 @@
# Velocity Modern Forwarding
[Velocity](https://papermc.io/software/velocity) is a high-performance proxy created by PaperMC. It uses modern plugin messaging during the `Login` state to securely transmit player data with **HMAC-SHA256** message authentication codes.
Pumpkin implements Velocity modern forwarding in [`crates/pumpkin/src/net/proxy/velocity.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/net/proxy/velocity.rs).
---
## How Velocity Forwarding Operates
Unlike BungeeCord, which injects unauthenticated data into the handshake string, Velocity operates during the **Login** state over a dedicated plugin channel:
1. **Handshake & Login**: The player authenticates with Velocity. Velocity initiates a standard TCP connection to Pumpkin and transmits `SHandshake` and `SLoginStart`.
2. **Channel Query**: Recognizing that Velocity modern forwarding is enabled, Pumpkin pauses the login sequence and dispatches a `CLoginPluginRequest` on channel `velocity:player_info`.
3. **Payload Generation**: Velocity bundles the player's remote address, UUID, username, and skin textures. It calculates a 32-byte HMAC-SHA256 signature across this payload using the shared secret.
4. **Signature Verification**: Velocity sends `SLoginPluginResponse`. Pumpkin validates the HMAC-SHA256 digest against its configured secret. If valid, Pumpkin overwrites the connection's network address and GameProfile and transitions to `Config` / `Play`.
---
## Wire Payload Structure
The payload in `SLoginPluginResponse` is structured as follows:
```text
┌─────────────────────────────────────────────────────────────┐
│ 32-byte HMAC-SHA256 Signature │
├─────────────────────────────────────────────────────────────┤
│ Forwarding Protocol Version (VarInt: 1 - 4) │
├─────────────────────────────────────────────────────────────┤
│ Client Remote IP Address (String / IPv4 / IPv6) │
├─────────────────────────────────────────────────────────────┤
│ Player UUID (128-bit / UUID) │
├─────────────────────────────────────────────────────────────┤
│ Player Username (String) │
├─────────────────────────────────────────────────────────────┤
│ Profile Properties Count (VarInt) │
│ ├─ Property Name (String) │
│ ├─ Property Value (String) │
│ └─ Optional Signature (String) │
└─────────────────────────────────────────────────────────────┘
```
---
## Cryptographic Validation in Pumpkin
Inside `crates/pumpkin/src/net/proxy/velocity.rs`:
```rust
use hmac::{Hmac, KeyInit, Mac};
use sha2::Sha256;
type HmacSha256 = Hmac<Sha256>;
// Extract signature and payload
let (signature, data_to_verify) = data.split_at(32);
// Initialize HMAC with secret from pumpkin.toml
let mut mac = HmacSha256::new_from_slice(secret.as_bytes())
.map_err(|_| VelocityError::FailedVerifyIntegrity)?;
mac.update(data_to_verify);
// Constant-time verification prevents timing attacks
mac.verify_slice(signature)
.map_err(|_| VelocityError::FailedVerifyIntegrity)?;
```
If the signature does not match (e.g., if an attacker attempts to connect directly to the backend without knowing the secret), Pumpkin drops the connection immediately.
---
## Configuration in `pumpkin.toml`
1. Open `velocity.toml` on your Velocity proxy and set:
```toml
player-info-forwarding-mode = "modern"
forwarding-secret-file = "forwarding.secret"
```
2. Copy the generated secret string from `forwarding.secret` into `pumpkin.toml`:
```toml
[networking.proxy]
enabled = true
[networking.proxy.velocity]
enabled = true
secret = "YOUR_VELOCITY_FORWARDING_SECRET_HERE"
```

View File

@ -0,0 +1,112 @@
# Vine Modern Forwarding
**Vine** is a next-generation, high-performance Minecraft proxy written in Rust. Designed for ultra-low latency, multi-threading, and enterprise-grade security, Vine introduces modern cryptographic forwarding based on **Ed25519 asymmetric signatures** and **replay attack protection**.
Pumpkin provides native support for Vine forwarding in [`crates/pumpkin/src/net/proxy/vine.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/net/proxy/vine.rs).
---
## Why Vine Forwarding?
While Velocity's HMAC-SHA256 forwarding represents an improvement over legacy BungeeCord, it relies on a **symmetric shared secret**. If one backend server in a network is compromised, an attacker obtains the shared secret and can forge authenticated player logins across the entire server cluster.
Vine solves this with:
1. **Asymmetric Public-Key Cryptography (Ed25519)**: The proxy signs player data using its private key. Backend servers only store the proxy's **Public Key** (`public_key`). Even if a backend server is compromised, the attacker cannot forge identities to other servers.
2. **Replay Attack Protection (16-byte Challenge Nonce)**: Pumpkin generates a cryptographic random 16-byte nonce for each connection. The proxy must sign and return this nonce. Replaying a captured login packet is impossible.
3. **Timestamp Drift Window**: Transmits a Unix timestamp that must be within ±30 seconds of the backend's system clock (`MAX_TIMESTAMP_DRIFT_SECS = 30`).
---
## The Handshake Sequence
1. **Connection**: The player connects and authenticates with Vine. Vine opens a backend connection to Pumpkin and sends `SHandshake` and `SLoginStart`.
2. **Challenge Query**: Pumpkin generates a cryptographically random 16-byte nonce and sends `CLoginPluginRequest` on the `vine:player_info` channel.
3. **Asymmetric Signing**: Vine serializes the version, timestamp, the returned 16-byte nonce, the client IP address, and the player GameProfile. It signs this byte stream with its Ed25519 private key.
4. **Tri-fold Validation**: Vine replies with `SLoginPluginResponse`. Pumpkin verifies:
- **Clock Skew**: The embedded timestamp is within ±30 seconds of UTC time.
- **Nonce Check**: The signed nonce exactly matches the 16-byte challenge generated in step 2.
- **Ed25519 Signature**: The signature is cryptographically valid against the configured `public_key`.
5. **Session Success**: If all three checks pass, Pumpkin applies the verified identity and emits `CLoginSuccess`.
---
## Wire Payload Structure
The `SLoginPluginResponse` data layout:
```text
┌─────────────────────────────────────────────────────────────┐
│ 64-byte Ed25519 Digital Signature │
├─────────────────────────────────────────────────────────────┤
│ Forwarding Protocol Version (i32: 1) │
├─────────────────────────────────────────────────────────────┤
│ Unix Timestamp in Seconds (i64) │
├─────────────────────────────────────────────────────────────┤
│ 16-byte Challenge Nonce │
├─────────────────────────────────────────────────────────────┤
│ Client Remote IP Address (String / IPv4 / IPv6) │
├─────────────────────────────────────────────────────────────┤
│ Player UUID (128-bit / UUID) │
├─────────────────────────────────────────────────────────────┤
│ Player Username (String) │
├─────────────────────────────────────────────────────────────┤
│ Profile Properties Count (VarInt) │
│ ├─ Property Name (String) │
│ ├─ Property Value (String) │
│ └─ Optional Signature (String) │
└─────────────────────────────────────────────────────────────┘
```
---
## Verification in Pumpkin
In `crates/pumpkin/src/net/proxy/vine.rs`:
```rust
use ed25519_dalek::{Signature, Verifier, VerifyingKey};
// 1. Validate payload length (64-byte signature + 25-byte headers minimum)
if data.len() < 89 {
return Err(VineError::DataTooShort);
}
// 2. Extract signature and signed payload
let (sig_bytes, signed_data) = data.split_at(64);
let signature = Signature::from_slice(sig_bytes)
.map_err(|_| VineError::InvalidSignature)?;
// 3. Verify timestamp skew (30 second maximum drift)
let skew = (server_now - timestamp).abs();
if skew > MAX_TIMESTAMP_DRIFT_SECS {
return Err(VineError::TimestampExpired(skew, MAX_TIMESTAMP_DRIFT_SECS));
}
// 4. Verify challenge nonce matches connection state
if received_nonce != expected_nonce {
return Err(VineError::ChallengeMismatch);
}
// 5. Verify Ed25519 signature with proxy's public key
verifying_key.verify(signed_data, &signature)
.map_err(|_| VineError::InvalidSignature)?;
```
---
## Configuration in `pumpkin.toml`
Configure Vine forwarding in `pumpkin.toml`:
```toml
[networking.proxy]
enabled = true
[networking.proxy.vine]
enabled = true
# 64-character hex-encoded Ed25519 public key of the Vine proxy
public_key = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
# Alternatively, if secret is supplied, the public key is derived automatically
secret = ""
```

View File

@ -0,0 +1,97 @@
# GameSpy4 Query Protocol
Pumpkin includes native support for the **GameSpy4 Query** protocol over UDP. External monitoring systems, Discord bots, and server listing platforms use Query to poll real-time player counts, MOTD, server versions, and active player lists with minimal network overhead.
Query wire encoding is implemented in [`crates/pumpkin-protocol/src/query.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-protocol/src/query.rs), and the asynchronous UDP listener is implemented in [`crates/pumpkin/src/net/query.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/net/query.rs).
---
## Why Query? (UDP vs. Status Ping)
While standard Minecraft clients ping servers via the TCP `Status` state (SLP), Query operates over stateless **UDP**:
- **No TCP Handshake**: Avoids TCP connection overhead and connection state tables.
- **Detailed Server State**: Returns comprehensive key-value metadata and a full list of connected player usernames (not available via basic TCP ping).
- **Amplification Attack Protection**: Enforces cryptographic challenge tokens so malicious actors cannot abuse the UDP port for denial-of-service reflection attacks.
---
## The Handshake & Challenge Token Flow
To prevent UDP spoofing and reflection DDoS attacks, Query requires a two-step handshake:
1. **Handshake Challenge**: The client transmits `SHandshake` (`0xFEFD`, type `0x09`, and a 32-bit session ID). Pumpkin generates a cryptographic 32-bit integer challenge token tied to the client's `SocketAddr` and responds with `CHandshake`.
2. **Status Query**: The client sends `SStatusRequest` containing the received challenge token:
- **Basic Status** (no padding): Returns MOTD, game type (`SMP`), map name, online player count, and max player capacity.
- **Full Status** (4-byte padding): Returns detailed server metadata key-value pairs (`hostname`, `gametype`, `game_id`, `version`, `plugins`, `map`, `numplayers`, `maxplayers`, `hostport`, `hostip`) followed by an array of online player usernames.
### Challenge Token Invalidation
In `crates/pumpkin/src/net/query.rs`, challenge tokens are stored in a thread-safe map (`Arc<RwLock<HashMap<SocketAddr, i32>>>`). A background Tokio timer purges all challenge tokens every 30 seconds to prevent replay abuse:
```rust
// Tokens are strictly bound to the client's IP and port
let valid_challenge_tokens = Arc::new(RwLock::new(HashMap::new()));
// Background expiration loop
tokio::spawn(async move {
let mut interval = time::interval(Duration::from_secs(30));
loop {
interval.tick().await;
valid_challenge_tokens.write().await.clear();
}
});
```
---
## Packet Formats
Every incoming Query packet starts with the 2-byte magic header `0xFEFD` followed by a 1-byte packet type:
| Type Byte | Name | Direction | Description |
| :--- | :--- | :--- | :--- |
| `0x09` | Handshake Request | Client → Server | Client asks for a challenge token. |
| `0x09` | Handshake Response | Server → Client | Returns the numeric token encoded as an ASCII string. |
| `0x00` | Stat Request | Client → Server | Requests basic or full status with challenge token. |
| `0x00` | Basic Stat Response | Server → Client | 11-byte short summary. |
| `0x00` | Full Stat Response | Server → Client | Key-value dictionary + null-separated player list. |
---
## Response Payloads
### 1. Basic Status (`CBasicStatus`)
Contains essential server fields:
- **`motd`**: Server message of the day (stripped of color codes).
- **`gametype`**: Fixed string `"SMP"`.
- **`map`**: Active world/level name (e.g., `"world"`).
- **`numplayers`**: Online player count.
- **`maxplayers`**: Maximum configured player capacity.
- **`hostport`**: Port number (`u16` Little Endian).
- **`hostip`**: Server IP string.
### 2. Full Status (`CFullStatus`)
Returns two null-terminated sections:
1. **Key-Value Metadata Map**:
- `hostname`: Server description / MOTD.
- `gametype`: `"SMP"`.
- `game_id`: `"MINECRAFT"`.
- `version`: Server protocol / Minecraft version string.
- `plugins`: Installed server software and plugin names.
- `map`: Level name.
- `numplayers` / `maxplayers`: Capacity stats.
- `hostport` / `hostip`: Network bindings.
2. **Player List**:
- An array of null-terminated UTF-8 strings containing the usernames of all currently connected players.
- Concludes with a terminal null byte (`\0`).
---
## Configuration in `pumpkin.toml`
```toml
[networking.query]
enabled = true
address = "0.0.0.0:25565"
```

View File

@ -0,0 +1,56 @@
# Plugin Engine Architecture
Pumpkin features a modular, multi-runtime plugin engine designed for performance, safety, and cross-language interoperability.
Unlike traditional Minecraft servers that rely on a single JVM class loader, Pumpkin isolates plugin execution through dedicated loaders supporting both **native high-performance Rust binaries** and **sandboxed WebAssembly components** compiled from Rust, Python, C#, C, Go, or Kotlin.
---
## Architectural Overview
### Architectural Breakdown
| Subsystem | Primary Crate | Responsibility |
| :--- | :--- | :--- |
| **Plugin Manager** | `crates/pumpkin/src/plugin` | Lifecycle orchestration (load, enable, disable), event dispatching, and loader registration |
| **Native Loader** | `crates/pumpkin/src/plugin/loader/native` | Direct dynamic library loading (`.so`, `.dll`, `.dylib`) for zero-overhead Rust extensions |
| **WASM Loader** | `crates/pumpkin/src/plugin/loader/wasm` | Wasmtime execution engine for sandboxed components compiled from Rust, Python, Go, C#, C, and Kotlin |
| **Interface Specifications** | `crates/pumpkin-plugin-wit` | WebAssembly Interface Types (WIT) defining typed functions, types, and host imports |
| **Security & Verification** | `crates/pumpkin/src/plugin/loader/wasm/sign` | Cryptographic signature verification via W3C wasmsign2 / Ed25519 public keys |
---
## The Dual Execution Model
| Feature | Native Plugins | WebAssembly (Wasmtime) Plugins |
| :--- | :--- | :--- |
| **File Extension** | `.so` (Linux), `.dll` (Windows), `.dylib` (macOS) | `.wasm` (Component Model) |
| **Languages** | Rust (compiled dynamically) | Rust, Python, C#, C, Go, Kotlin |
| **Performance** | Native CPU execution (zero overhead) | JIT-compiled with near-native speed |
| **Sandboxing** | None (runs in host address space) | Memory-isolated sandboxed execution |
| **Security & Signing** | OS-level permissions | Cryptographic W3C Wasm-Sign verification |
| **Hot Unloading** | Limited (OS shared library constraints) | Fully supported memory reclamation |
---
## Event Lifecycle & Dispatching
Plugins interact with Pumpkin primarily through events:
1. **Event Dispatch**:
- `server.plugin_manager.fire_blocking(&server, &mut event)`: Dispatches events synchronously on the executing thread (e.g., cancelling player block placement or modifying packet payloads).
- Asynchronous events run on non-blocking Tokio tasks.
2. **Cancellable Events**:
- Handlers can set `event.cancelled = true` to abort the default game logic (such as cancelling player movement, interactions, or packet processing).
---
## Plugin Engine Documentation
Explore the internal mechanics of Pumpkin's plugin system:
- **[Adding a Plugin Loader](/developer/plugins/loaders)**: Step-by-step guide on implementing the `PluginLoader` trait for new scripting languages and runtimes.
- **[WASM Signing & Verification](/developer/plugins/wasm-signing)**: Detailed specification of Ed25519 cryptographic signing, W3C `wasmsign2` custom sections, and marketplace license verification.
> [!NOTE]
> Looking to develop third-party plugins rather than working on Pumpkin's internal plugin engine? Check out the **[Plugin Development Guide](/plugin-dev/introduction)**.

View File

@ -0,0 +1,161 @@
# Adding a Plugin Loader
Pumpkin's plugin architecture is runtime-agnostic. The server does not assume all plugins run in WebAssembly or native shared libraries; instead, all execution runtimes implement the unified [`PluginLoader`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/plugin/loader/mod.rs) trait.
This guide explains how `PluginLoader` operates and demonstrates how to implement a custom loader for new script runtimes or virtual machines (such as Lua, JavaScript/Boa, or GraalVM).
---
## The `PluginLoader` Trait
All plugin loaders implement the `PluginLoader` trait located in `crates/pumpkin/src/plugin/loader/mod.rs`:
```rust
use std::{any::Any, path::Path, pin::Pin, sync::Arc};
use crate::plugin::{PluginMetadata, api::Plugin};
pub type PluginLoadFuture<'a> = Pin<
Box<
dyn Future<
Output = Result<
(Arc<dyn Plugin>, PluginMetadata, Box<dyn Any + Send + Sync>),
LoaderError,
>,
> + Send
+ 'a,
>,
>;
pub type PluginUnloadFuture<'a> =
Pin<Box<dyn Future<Output = Result<(), LoaderError>> + Send + 'a>>;
pub trait PluginLoader: Send + Sync {
/// Determines whether this loader handles the target file.
fn can_load(&self, path: &Path) -> bool;
/// Loads, parses, and initializes a plugin instance asynchronously.
fn load<'a>(&'a self, path: &'a Path) -> PluginLoadFuture<'a>;
/// Unloads the plugin and reclaims associated resources.
fn unload(&self, data: Box<dyn Any + Send + Sync>) -> PluginUnloadFuture<'_>;
/// Indicates whether the runtime supports safe unloading without memory leaks.
fn can_unload(&self) -> bool;
}
```
---
## Existing Loaders in Pumpkin
Pumpkin currently provides two official loaders:
1. **`NativePluginLoader` (`loader/native.rs`)**:
- Matches dynamic library files (`.so` on Linux, `.dll` on Windows, `.dylib` on macOS).
- Dynamically links the library using [`libloading`](https://docs.rs/libloading/).
- Locates and invokes the extern entrypoint function (`pumpkin_plugin_init`).
- `can_unload()` returns `false` due to OS-level shared library unloading hazards.
2. **`WasmPluginLoader` (`loader/wasm/mod.rs`)**:
- Matches `.wasm` files.
- Verifies cryptographic signatures (see [WASM Signing](/developer/plugins/wasm-signing)).
- JIT-compiles WebAssembly components using [Wasmtime](https://wasmtime.dev/).
- Links host WIT exports (`pumpkin-host-bindings`).
- `can_unload()` returns `true` because Wasmtime safely drops guest memory.
---
## Step-by-Step: Adding a Custom Plugin Loader
Here is how to create a custom loader (e.g., for a scripting runtime):
### Step 1: Define the Loader Struct
Create a new file in `crates/pumpkin/src/plugin/loader/my_loader.rs`:
```rust
use std::{any::Any, path::Path, sync::Arc};
use crate::plugin::loader::{LoaderError, PluginLoadFuture, PluginLoader, PluginUnloadFuture};
use crate::plugin::{PluginMetadata, api::Plugin};
pub struct MyCustomLoader;
impl MyCustomLoader {
#[must_use]
pub fn new() -> Self {
Self
}
}
```
### Step 2: Implement File Recognition (`can_load`)
Check the file extension or inspect header bytes:
```rust
impl PluginLoader for MyCustomLoader {
fn can_load(&self, path: &Path) -> bool {
path.extension()
.and_then(|ext| ext.to_str())
.is_some_and(|ext| ext.eq_ignore_ascii_case("script"))
}
```
### Step 3: Implement Asynchronous Loading (`load`)
The `load` method reads the script, initializes the VM, registers server host callbacks, and returns a tuple containing:
1. `Arc<dyn Plugin>`: The generic plugin handle.
2. `PluginMetadata`: Name, author, version, description.
3. `Box<dyn Any + Send + Sync>`: Loader-specific context (e.g., VM state) retained for unloading.
```rust
fn load<'a>(&'a self, path: &'a Path) -> PluginLoadFuture<'a> {
Box::pin(async move {
let script_content = tokio::fs::read_to_string(path).await
.map_err(|e| LoaderError::InitializationFailed(e.to_string()))?;
// 1. Parse plugin metadata from header or accompanying manifest
let metadata = PluginMetadata {
name: "ExampleScript".into(),
version: "1.0.0".into(),
authors: vec!["Author".into()],
description: Some("Custom script plugin".into()),
};
// 2. Initialize runtime instance
let plugin_instance = Arc::new(MyScriptPluginWrapper::new(script_content));
let runtime_state: Box<dyn Any + Send + Sync> = Box::new(());
Ok((plugin_instance, metadata, runtime_state))
})
}
```
### Step 4: Implement Clean Unloading (`unload` & `can_unload`)
If your runtime can cleanly terminate without leaking resources:
```rust
fn can_unload(&self) -> bool {
true
}
fn unload(&self, data: Box<dyn Any + Send + Sync>) -> PluginUnloadFuture<'_> {
Box::pin(async move {
// Drop runtime state and disconnect event listeners
drop(data);
Ok(())
})
}
}
```
### Step 5: Register the Loader in `PluginManager`
Open `crates/pumpkin/src/plugin/mod.rs` and register your loader in `PluginManager::new()`:
```rust
// In crates/pumpkin/src/plugin/mod.rs
let mut loaders: Vec<Box<dyn PluginLoader>> = Vec::new();
loaders.push(Box::new(NativePluginLoader::new()));
loaders.push(Box::new(WasmPluginLoader::new()));
loaders.push(Box::new(MyCustomLoader::new())); // Add custom loader
```
During server startup, Pumpkin iterates through all registered loaders in sequence when scanning the `plugins/` folder, dispatching each file to the first loader whose `can_load` returns `true`.

View File

@ -0,0 +1,86 @@
# WASM Plugin Signing & Verification
Pumpkin implements a cryptographic signing and license verification system for WebAssembly plugins. This ensures plugin integrity, authenticates author identity, and protects verified or marketplace plugins against unauthorized tampering.
The signing subsystem is implemented in [`crates/pumpkin/src/plugin/loader/wasm/wasm_host/signature.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/plugin/loader/wasm/wasm_host/signature.rs) based on the **W3C `wasmsign2`** specification using custom WebAssembly sections.
---
## Why Sign WebAssembly Plugins?
- **Tamper Protection**: Ensures that compiled bytecode has not been injected with malicious logic after compilation.
- **Author Identity**: Authenticates that a plugin was built and released by a verified developer.
- **Marketplace Licensing**: Validates license keys and entitlements for plugins distributed through the official [Pumpkin Marketplace](https://market.pumpkinmc.org).
---
## Custom Sections in the WASM Binary
Pumpkin embeds signing and verification metadata directly into two standard WebAssembly custom sections:
- **`pumpkin.metadata`**: Stores developer, publication, and license claims in JSON format.
- **`wasm_signature`**: Stores the cryptographic signature envelope compliant with the W3C `wasmsign2` standard.
### 1. `pumpkin.metadata` Section
Contains a JSON string holding publication and license claims:
```json
{
"marketplace_url": "https://market.pumpkinmc.org",
"plugin_id": 1024,
"plugin_name": "EconomyPlus",
"version": "1.2.0",
"dev_id": 42,
"dev_name": "DevName",
"is_paid": true,
"user_id": 1001,
"license_key": "XXXX-XXXX-XXXX-XXXX",
"issued_at": "2026-09-14T05:00:00Z"
}
```
### 2. `wasm_signature` Section
Follows the W3C `wasmsign2` envelope structure:
```json
{
"version": 1,
"algorithm": "Ed25519",
"public_key_hex": "4a7b...",
"signature_hex": "8e1c..."
}
```
---
## The Signing Pipeline
The signing process guarantees integrity by hashing and signing the clean WebAssembly bytecode combined with the metadata claims:
### Signing Algorithm Steps
1. **Sanitization (`strip_pumpkin_sections`)**: Uses [`wasmparser`](https://docs.rs/wasmparser/) to strip any preexisting `pumpkin.metadata` or `wasm_signature` custom sections to avoid recursion.
2. **Payload Construction**:
```rust
let mut sign_payload = Vec::new();
sign_payload.extend_from_slice(&clean_wasm);
sign_payload.extend_from_slice(&metadata_json);
```
3. **Ed25519 Signature**: The payload is signed using [`ed25519-dalek`](https://docs.rs/ed25519-dalek/) with the developer's 32-byte secret key.
4. **Encoding**: Uses [`wasm-encoder`](https://docs.rs/wasm-encoder/) to append the `pumpkin.metadata` and `wasm_signature` custom sections to the clean binary.
---
## The Verification Pipeline
When Pumpkin boots and loads a WebAssembly plugin, the verification sequence executes before the plugin is instantiated:
1. **Custom Section Extraction**: The `WasmPluginLoader` scans the binary for `pumpkin.metadata` and `wasm_signature`.
2. **Key Retrieval**:
- If the plugin is marked as marketplace-verified, Pumpkin verifies the public key against the Marketplace Public Key Endpoint (`https://market.pumpkinmc.org/api/v1/rest/public-key`).
- If signed by an independent developer, the key is matched against trusted developer keys configured in `pumpkin.toml`.
3. **Bytecode Verification**:
- Pumpkin strips the custom sections from the loaded binary to recover the original `clean_wasm`.
- Reconstructs the payload `(clean_wasm + metadata_json)`.
- Verifies the signature using `verifying_key.verify(&payload, &signature)`.
4. **License & Integrity Validation**:
- If verification succeeds, Wasmtime instantiates the plugin safely.
- If verification fails or the signature is invalid, loading is aborted with an error, protecting the server from running compromised code.

View File

@ -0,0 +1,287 @@
# Porting to Newer Minecraft Versions
Upgrading Pumpkin to support a newer Minecraft release—whether a minor patch (e.g., `1.21.4` to `1.21.5`) or a major update (e.g., `1.21` to `26.1`/`26.2`)—is a structured, multi-step process.
> [!IMPORTANT]
> **The Extractor mod must be ported first!**
> Pumpkin cannot be ported in isolation. The primary source for Pumpkin's assets (`blocks.json`, `items.json`, `entities.json`, `packets.json`, `tracked_data.json`, `synced_registries.json`, etc.) is our dedicated Fabric mod: [Pumpkin-MC/Extractor](https://github.com/Pumpkin-MC/Extractor). You **must first port and run the Extractor on the target Minecraft version** before running `pumpkin-codegen` or updating server crates.
### Porting Lifecycle at a Glance
| Stage | Responsibility | Primary Crates / Tools |
| :--- | :--- | :--- |
| **1. Port Extractor** | Extract vanilla block states, entities, items, packets, and registries | `Pumpkin-MC/Extractor` (Fabric mod) |
| **2. Update Datapacks** | Ingest new data packs, tags, recipes, and Bedrock mappings | `assets/datapacks/<ver>`, `assets/bedrock` |
| **3. Version Declarations** | Register protocol version and ViaVersion/ViaBackwards remap nodes | `pumpkin-util`, `tools/pumpkin-codegen` |
| **4. Code Generation** | Regenerate zero-cost Rust data tables and registries | `pumpkin-codegen` -> `pumpkin-data` |
| **5. Compiler Fixes** | Update packet layouts, codecs, and data components | `pumpkin-protocol`, `pumpkin-inventory` |
| **6. Gameplay Logic** | Implement new block behaviors, item mechanics, and mob AI | `crates/pumpkin/src/block`, `item`, `entity` |
| **7. Multi-Version QA** | Validate backward compatibility, test suites, and client joins | `cargo test`, `pumpkin-gametest` |
---
## Phase 1: Port the Extractor Mod First (`Pumpkin-MC/Extractor`)
The [Extractor](https://github.com/Pumpkin-MC/Extractor) is a Kotlin-based Fabric mod that boots an actual Minecraft client or server instance to introspect live game registries and extract data into the exact JSON formats Pumpkin expects.
### 1. Clone or Update the Extractor Repository
```bash
git clone https://github.com/Pumpkin-MC/Extractor
cd Extractor
```
### 2. Update `gradle.properties`
Bump the dependency versions to match the target Minecraft version, Yarn mappings, and Fabric ecosystem:
```properties
minecraft_version=26.2
yarn_mappings=26.2+build.1:v2
loader_version=0.16.10
fabric_version=0.115.0+26.2
```
### 3. Resolve Extractor Compilation Errors
Minecraft and Fabric internal APIs often change between releases. Check and fix any broken extractors in `src/main/kotlin/de/snowii/extractor/extractors/`:
- **`Blocks.kt`**: Extracts block states, hardness, resistance, luminance, and collision box offsets.
- **`Items.kt`**: Extracts item IDs, max stack sizes, and default components.
- **`Entities.kt`**: Extracts entity IDs, dimensions (width, height), and eye heights.
- **`Packets.kt`**: Extracts packet IDs for handshake, status, login, configuration, and play states.
- **`SyncedRegistries.kt`**: Extracts dynamic registries synchronized to clients.
- **`TrackedData.kt`**: Extracts entity tracked data indices and serializers.
- **`MultiNoise.kt` & `Biome.kt`**: Extracts world generation biome trees and noise parameters.
### 4. Run the Extractor
Execute the server runner (or client runner for translation/screen dumps):
```bash
./gradlew runServer
```
Once the extraction finishes, all dumped JSON files will be located in `run/pumpkin_extractor_output/`.
### 5. Replace the Old Asset Files in Pumpkin
Copy the newly generated JSON files from `run/pumpkin_extractor_output/` and use them to **replace the old asset files** in Pumpkin:
- Replace the core game assets in `Pumpkin/assets/` (`blocks.json`, `items.json`, `entities.json`, `packets.json`, `properties.json`, `synced_registries.json`, `tracked_data.json`, `en_us.json`, etc.).
- Replace the world generation test files in `Pumpkin/crates/pumpkin-world/assets/`.
---
## Phase 2: Update Assets & Datapacks
Once the raw extractor assets are in place, update the versioned datapacks and supplemental files in Pumpkin:
### 1. Add the Versioned Datapack
Extract the internal vanilla data pack from the new Minecraft server JAR and place it under `assets/datapacks/<version>/`:
```
assets/datapacks/<version>/
└── data/
├── minecraft/
│ ├── advancement/
│ ├── chat_type/
│ ├── damage_type/
│ ├── dimension_type/
│ ├── enchantment/
│ ├── item_modifier/
│ ├── loot_table/
│ ├── recipe/
│ ├── tags/
│ └── worldgen/
└── c/
└── tags/ (Conventional / Common Tags)
```
### 2. Update Versioned Assets
Update or generate the corresponding versioned metadata files:
- `assets/registry/<version>_synced_registries.json`: Dynamic registries streamed to the client during the `Configuration` network state.
- `assets/tags/<version>_tags.json`: Tag collections.
- `assets/tracked_data/<version>_tracked_data.json`: Entity metadata indices.
### 3. Update Bedrock Mappings
If porting Bedrock Edition support simultaneously, update the files in `assets/bedrock/` using the latest mappings from [GeyserMC](https://github.com/GeyserMC/Geyser) and Bedrock Dedicated Server (BDS).
### 4. Decompile Sources for Reverse Engineering (Optional but Recommended)
For complex changes—such as worldgen noise router formulas and custom block collision shapes—decompile the matching vanilla JAR into `minecraft-sources-<version>/` (using Vineflower or Fabric Loom with official Mojang mappings) for reference.
---
## Phase 3: Register Version Constants & ViaVersion Mappings
Pumpkin supports multi-version clients through automated protocol remapping powered by **ViaBackwards** / **ViaRewind** mapping tables.
### 1. Declare Version in `pumpkin-util`
Open `crates/pumpkin-util/src/version.rs` and add the new version to [`JavaMinecraftVersion`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-util/src/version.rs):
```rust
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum JavaMinecraftVersion {
// ... existing versions ...
V_1_21_4,
V_1_21_11,
V_26_2, // New target version
}
impl JavaMinecraftVersion {
pub const fn protocol_version(&self) -> i32 {
match self {
// ...
Self::V_26_2 => 770, // Protocol version number
}
}
pub const fn version_name(&self) -> &'static str {
match self {
// ...
Self::V_26_2 => "26.2",
}
}
}
```
### 2. Declare Version in `pumpkin-codegen`
Open `tools/pumpkin-codegen/src/version.rs` and add the identical enum variant to the codegen AST.
### 3. Add ViaVersion / ViaBackwards Mappings
To enable clients on older versions to connect to the updated server (e.g., a `1.21.4` client connecting to a `26.2` server):
1. Obtain the NBT mapping file from the [ViaBackwards repository](https://github.com/ViaVersion/ViaBackwards):
`mappings-<new_version>to<previous_version>.nbt`
2. Save it to:
`assets/viabackwards/data/mappings-<new_version>to<previous_version>.nbt`
3. In `tools/pumpkin-codegen/src/remap/mod.rs`, link the new node into the `remap_nodes!` macro:
```rust
let node_26_2 = $crate::remap::MappingNode {
version: $crate::version::JavaMinecraftVersion::V_26_2,
value: "../../assets/viabackwards/data/mappings-26.2to26.1.nbt",
child: Some(&node_26_1),
};
$remapper.process(&node_26_2)
```
4. Check `tools/pumpkin-codegen/src/remap/` to ensure specific remap builders (`block_state.rs`, `item_id.rs`, `entity_id.rs`, `sound_id.rs`, `argument_type.rs`) correctly process any new remapping structures introduced by ViaVersion.
---
## Phase 4: Run Code Generation (`pumpkin-codegen`)
With all extractor assets, datapacks, and mapping nodes in place, execute the codegen tool from the workspace root:
```bash
cargo run -p pumpkin-codegen
```
### What Gets Regenerated?
`pumpkin-codegen` generates zero-cost Rust data tables into `crates/pumpkin-data/src/generated/`:
- **`block.rs`**: All block IDs, properties, state masks, and collision shapes.
- **`item.rs`**: Items, default components, and tool tiers.
- **`entity_type.rs` & `tracked_data.rs`**: Entity type IDs, default bounding boxes, and metadata serializers.
- **`packet.rs`**: Serverbound and clientbound packet ID constants across protocol states.
- **`recipes.rs`**: All crafting, cooking, and stonecutting recipes parsed from the new datapack.
- **`tag.rs`**: Tag lookups (`#minecraft:mineable/axe`, `#c:iron_ingots`).
- **`remap/*.rs`**: State remap lookup tables (`block_state_remap.rs`, `item_id_remap.rs`, `entity_id_remap.rs`, `sound_id_remap.rs`).
---
## Phase 5: Resolve Workspace Compilation Errors
After regenerating `pumpkin-data`, the Rust compiler will flag breaking changes across the workspace. Run:
```bash
cargo check --workspace
```
### Common Compiler Breakages & Fixes:
#### 1. Packet ID & Layout Changes (`pumpkin-protocol`)
Mojang frequently adds, moves, or alters packet IDs and payloads:
- Update `pumpkin-protocol/src/java/client/` and `pumpkin-protocol/src/java/server/`.
- Inspect packets like `LoginSuccess`, `PlayLogin`, `Respawn`, and `PlayerSpawnData` for newly added fields (e.g., new game mode flags, dimension attributes, or teleportation IDs).
- For Bedrock Edition, check `StartGame`, `NetworkItem`, and container transaction packets in `pumpkin-protocol/src/bedrock/`.
#### 2. Data Component Changes
If items switched from older NBT structures to new Data Components (or if components were renamed/restructured):
- Update `crates/pumpkin-data/src/data_component.rs`.
- Update serialization and deserialization in `pumpkin-inventory`.
#### 3. Registry Synchronization
During the `Configuration` phase, servers send dynamic registry contents to Java clients. If new registries were added to vanilla Minecraft (e.g., trim materials, banner patterns, instrument sounds):
- Verify `crates/pumpkin-data/src/generated/registry.rs`.
- Ensure `pumpkin/src/net/java/config.rs` streams all required registry codecs to the client.
---
## Phase 6: Implement Logic for New Blocks, Items & Entities
Once the server compiles, any newly introduced gameplay content must be implemented.
### 1. New Blocks
1. Locate new block identifiers in `pumpkin-data::Block`.
2. Create a behavior module under `crates/pumpkin/src/block/blocks/<block_name>.rs` implementing [`BlockBehaviour`](/developer/blocks/adding-blocks):
```rust
pub struct NewBlockBehaviour;
impl BlockBehaviour for NewBlockBehaviour {
fn on_use(&self, block: &Block, player: &Arc<Player>, location: BlockPos, world: &Arc<World>) {
// Interaction logic
}
}
```
3. Register the behavior in the block registry in `crates/pumpkin/src/block/mod.rs`.
### 2. New Items
1. Locate new item identifiers in `pumpkin-data::Item`.
2. If the item has unique right-click or use behavior (e.g., weapons, projectiles, instruments), create an item behavior in `crates/pumpkin/src/item/items/<item_name>.rs` implementing [`ItemBehaviour`](/developer/items/adding-items).
3. If the item places entities (e.g., spawn eggs, boats, minecarts), configure entity spawning logic in `pumpkin/src/item/items/spawn_egg.rs`.
4. Register the behavior in `crates/pumpkin/src/item/mod.rs`.
### 3. New Entities
1. Check `pumpkin-data::entity_type::EntityType` for new entity IDs.
2. Create an entity struct in `crates/pumpkin/src/entity/mob/` or `living/` extending [`LivingEntity`](/developer/entities/).
3. Implement `TrackedData` fields to match vanilla client expectations (e.g., poses, animations, glowing states).
4. Assign AI goals and navigation tasks using the [Mob AI & Goals system](/developer/entities/ai-and-mobs).
5. Add spawn packet construction in `crates/pumpkin/src/entity/spawning.rs`.
---
## Phase 7: Multi-Version & ViaVersion Verification
Ensure that older clients can still connect seamlessly:
1. **Verify Generated Remap Tables**:
Check `crates/pumpkin-data/src/generated/block_state_remap.rs` and `item_id_remap.rs`. Ensure that novel block states fall back gracefully to compatible equivalents on older client versions (e.g., new wood variants mapping to oak or spruce).
2. **Packet Translation**:
Verify that packet writers in `pumpkin-protocol` apply `remap` functions when serializing data for a connection whose negotiated `protocol_version` is older than the server's native version.
---
## Phase 8: Testing & Verification Checklist
Before opening a Pull Request for a version port, complete the following QA checklist:
- [ ] **Automated Tests**:
```bash
cargo test --workspace
```
- [ ] **Game Test Suite**:
```bash
cargo test -p pumpkin-gametest
```
- [ ] **Strict Linter Rules**:
```bash
cargo clippy --workspace --all-targets -- -D warnings
```
- [ ] **Spellcheck**:
```bash
typos
```
- [ ] **In-Game Java Client Test**:
- Connect with the native new Minecraft client version.
- Test login, world loading, chunk generation, and player movement.
- Place and break new blocks; verify collision boxes and redstone reactivity.
- Use and equip new items; test attack speed, durability, and animations.
- Spawn and fight new entities; test animations, hurt sounds, and drops.
- [ ] **In-Game Older Version Client Test**:
- Connect with an older supported client version (e.g., 1.21.x).
- Verify that blocks, items, and entities translate without causing client crashes or desyncs.
- [ ] **In-Game Bedrock Client Test**:
- Verify that Bedrock clients can authenticate, join, load world chunks, and view custom items.

View File

@ -0,0 +1,90 @@
# Creating Your First Command
Writing commands in C for Pumpkin is low-overhead, fast, and uses C WIT bindings.
---
## 1. Quick Example
Here is a complete C plugin file (`main.c`) that registers a `/hello` command with permission checks and sends a response back to the player.
```c [main.c]
#include <stdio.h>
#include "pumpkin.h"
void plugin_on_load(pumpkin_context_t ctx) {
// 1. Register permission node
pumpkin_permission_t perm = {
.node = "my_c_plugin:hello",
.description = "Allows executing the /hello command",
.default_access = PERMISSION_DEFAULT_ALLOW
};
pumpkin_register_permission(ctx, &perm);
// 2. Build and register command tree
const char* names[] = {"hello", "hi"};
pumpkin_command_t cmd = pumpkin_command_new(names, 2, "Greets the player");
pumpkin_register_command(ctx, cmd, "my_c_plugin:hello");
}
int32_t plugin_handle_command(uint32_t command_id, pumpkin_sender_t sender, pumpkin_server_t server) {
pumpkin_sender_send_message(sender, "Hello from C Plugin!");
return 1;
}
pumpkin_metadata_t plugin_get_metadata() {
pumpkin_metadata_t meta = {
.name = "my_c_plugin",
.version = "0.1.0",
.description = "My first Pumpkin C plugin"
};
return meta;
}
```
---
## 2. In-Game Preview
Once registered, your command automatically gains client-side autocompletion, syntax validation, and color highlighting in Minecraft:
<img src="/assets/first_command_preview.png" alt="In-Game Command Autocompletion Preview" width="500"/>
---
## 3. How It Works
::: details Step-by-Step Breakdown
### Step 1: Define the Permission Struct
Populate a `pumpkin_permission_t` struct and call `pumpkin_register_permission`:
```c
pumpkin_permission_t perm = {
.node = "my_c_plugin:hello",
.description = "Allows executing the /hello command",
.default_access = PERMISSION_DEFAULT_ALLOW
};
pumpkin_register_permission(ctx, &perm);
```
### Step 2: Build the Command Tree
Create the command tree by passing name array and description:
```c
const char* names[] = {"hello", "hi"};
pumpkin_command_t cmd = pumpkin_command_new(names, 2, "Greets the player");
```
### Step 3: Register Command & Handle Execution
Pass the command handle to `pumpkin_register_command` and handle responses inside `plugin_handle_command`:
```c
pumpkin_register_command(ctx, cmd, "my_c_plugin:hello");
```
:::
---
## Next Steps
- Check out the [C Quick Start Guide](./quick-start) to set up your compiler toolchain.

View File

@ -0,0 +1,110 @@
# Creating Your First Command
Registering custom commands in Pumpkin using C# provides a strongly-typed, clean structure.
---
## 1. Quick Example
Here is a complete C# plugin file (`MyPlugin.cs`) that registers a `/hello` command with permission checks and sends a response back to the player.
```csharp [MyPlugin.cs]
using PluginWorld;
using PluginWorld.wit.Exports.pumpkin.plugin.v0_1_0;
using PluginWorld.wit.Imports.pumpkin.plugin.v0_1_0;
namespace MyPumpkinPlugin;
public class MyPlugin : IPluginWorldExports, IMetadataExports
{
public static void InitPlugin() { }
public static void OnLoad(IContextImports.Context context)
{
// 1. Register permission node
var perm = new IPermissionImports.Permission(
"my_csharp_plugin:hello",
"Allows executing the /hello command",
IPermissionImports.PermissionDefault.Allow,
[]
);
IContextImports.RegisterPermission(context, perm);
// 2. Build and register command tree
var command = ICommandImports.Command.New(["hello", "hi"], "Greets the player");
IContextImports.RegisterCommand(context, command, "my_csharp_plugin:hello");
}
public static void OnUnload(IContextImports.Context context) { }
public static IEventImports.Event HandleEvent(uint eventId, IServerImports.Server server, IEventImports.Event @event)
{
return @event;
}
public static int HandleCommand(uint commandId, ICommandImports.CommandSender sender, IServerImports.Server server, ICommandImports.ConsumedArgs args)
{
ICommandImports.SendMessage(sender, "Hello from C# Plugin!");
return 1;
}
public static void HandleTask(uint handlerId, IServerImports.Server server) { }
public static IMetadataExports.PluginMetadata Metadata()
{
return new IMetadataExports.PluginMetadata(
"my_csharp_plugin",
"0.1.0",
"My first Pumpkin C# plugin",
["Developer"],
[]
);
}
}
```
---
## 2. In-Game Preview
Once registered, your command automatically gains client-side autocompletion, syntax validation, and color highlighting in Minecraft:
<img src="/assets/first_command_preview.png" alt="In-Game Command Autocompletion Preview" width="500"/>
---
## 3. How It Works
::: details Step-by-Step Breakdown
### Step 1: Define the Permission Node
Construct an `IPermissionImports.Permission` record and register it via `IContextImports.RegisterPermission`:
```csharp
var perm = new IPermissionImports.Permission(
"my_csharp_plugin:hello",
"Allows executing the /hello command",
IPermissionImports.PermissionDefault.Allow,
[]
);
IContextImports.RegisterPermission(context, perm);
```
### Step 2: Build the Command Tree
Instantiate your command with primary names and description:
```csharp
var command = ICommandImports.Command.New(["hello", "hi"], "Greets the player");
```
### Step 3: Register and Handle
Register the command with `IContextImports.RegisterCommand` and process incoming executions inside `HandleCommand`:
```csharp
IContextImports.RegisterCommand(context, command, "my_csharp_plugin:hello");
```
:::
---
## Next Steps
- Follow the [C# Quick Start Guide](./quick-start) to configure `.csproj` and build WebAssembly outputs.

View File

@ -0,0 +1,130 @@
# Schnellstart
Dieser Leitfaden hilft dir beim Einstieg in die Entwicklung von Pumpkin-Server-Plugins mit der Programmiersprache [D](https://dlang.org/).
D-Plugins für Pumpkin werden mithilfe der offiziellen Bindings [`pumpkin-api-d`](https://github.com/Pumpkin-MC/pumpkin-api-d) als WebAssembly-Komponenten (Wasm) kompiliert.
---
## Voraussetzungen
Bevor du D-Plugins für Pumpkin erstellst, stelle sicher, dass folgende Software installiert ist:
- **[LDC](https://github.com/ldc-developers/ldc)**: Version 1.43 oder neuer (LLVM-basierter D-Compiler).
- **`addon-wasi`**: Das WASI-Zielpaket für LDC.
- **[DUB](https://dub.pm/)**: Der D-Paket- und Build-Manager (in der Regel in LDC enthalten).
---
## 1. Projekt einrichten
Erstelle ein neues Verzeichnis für dein Plugin-Projekt und lege eine `dub.json`-Konfigurationsdatei an:
```bash
mkdir my-d-plugin
cd my-d-plugin
```
Erstelle die `dub.json` im Projektstammverzeichnis:
```json [dub.json]
{
"name": "my-d-plugin",
"description": "Ein minimales Pumpkin-Plugin in D.",
"license": "proprietary",
"authors": ["DeinName"],
"copyright": "Copyright © 2026, DeinName",
"dependencies": {
"pumpkin-api-d": "~>0.1.0"
},
"targetType": "executable",
"dflags": ["-Xcc=-mexec-model=reactor"],
"buildTypes": {
"debug": {
"buildOptions": ["debugMode", "debugInfo"]
},
"release": {
"buildOptions": ["optimize", "inline"],
"dflags": ["-L-S"]
}
}
}
```
> [!NOTE]
> Das Flag `-Xcc=-mexec-model=reactor` wird vom WebAssembly-Linker benötigt, damit das Plugin als Reaktor (eine Komponente mit exportierten Einstiegspunkten) anstelle eines eigenständigen CLI-Programms mit Beendigungspunkt behandelt wird.
---
## 2. Das Plugin schreiben
Erstelle ein `source`-Verzeichnis und lege deinen Code in `source/app.d` ab:
```d [source/app.d]
module plugin;
import wit.pumpkin.plugin.plugin;
import wit.common;
import pumpkin.register;
struct MyPlugin {
@GetMetadata PluginMetadata getMetadata()
{
immutable(WitString)[$] authors = [
"DeinName".witList
];
return (immutable PluginMetadata(
name: "my-d-plugin".witList,
version_: "0.1.0".witList,
authors: authors.witList,
description: "Ein Beispiel-Plugin in D.".witList,
dependencies: WitList!WitString(),
permissions: WitList!WitString()
)).witClone;
}
@OnLoad
Result!(void, WitString) onLoad(Context ctx)
{
scope (exit)
ctx.witDrop; // Eingehende Ressourcen müssen nach der Nutzung freigegeben werden
log(Level.info, "Hallo vom D-Plugin!".witList);
return ok!WitString;
}
}
mixin RegisterPlugin!MyPlugin;
```
---
## 3. Plugin kompilieren
Kompiliere dein Plugin zu einer WebAssembly-Komponente mit dem Ziel `wasm32-wasip2`:
```bash
dub build -b release -a wasm32-wasip2
```
Dadurch wird `my-d-plugin.wasm` im Projektstammverzeichnis erzeugt.
---
## 4. Plugin ausführen
1. Kopiere die kompilierte `.wasm`-Datei in das `plugins/`-Verzeichnis deines Pumpkin-Servers:
```bash
cp my-d-plugin.wasm /pfad/zu/pumpkin/plugins/
```
2. Starte oder starte den Pumpkin-Server neu:
```bash
./pumpkin
```
3. Prüfe die Server-Logs auf die Erfolgsmeldung:
```text
[INFO] Hallo vom D-Plugin!
```

View File

@ -0,0 +1,60 @@
# Writing the basic logic
## Plugin Entry Point
In Go, your plugin must implement the `api.Plugin` interface and register itself in the `init()` function. You also need to import `wit_exports` for WebAssembly compatibility.
:::code-group
```go [main.go]
package main
import (
"github.com/Pumpkin-MC/pumpkin-api-go/api"
"github.com/Pumpkin-MC/pumpkin-api-go/pkg/pumpkin_plugin_context"
"github.com/Pumpkin-MC/pumpkin-api-go/pkg/pumpkin_plugin_logging"
_ "github.com/Pumpkin-MC/pumpkin-api-go/pkg/wit_exports" // Required for WASM exports
)
type MyPlugin struct {
api.DefaultPlugin
}
func (p *MyPlugin) Metadata() api.Metadata {
return api.Metadata{
Name: "my-go-plugin",
Version: "0.1.0",
Authors: []string{"you"},
}
}
func (p *MyPlugin) OnLoad(ctx *pumpkin_plugin_context.Context) {
pumpkin_plugin_logging.Log(pumpkin_plugin_logging.LevelInfo(), "Go plugin loaded!")
}
func init() {
api.RegisterPlugin(&MyPlugin{})
}
func main() {}
```
:::
## Compiling the plugin
To compile your plugin to WebAssembly, you must use **TinyGo**. The standard Go compiler does not yet support the specific WASI targets required by Pumpkin in the same way.
Run the following command in your project folder:
```bash
tinygo build -o my_plugin.wasm -target=wasi main.go
```
This will generate a `my_plugin.wasm` file that can be loaded by Pumpkin.
## Testing the plugin
Installing a plugin is as simple as putting the plugin binary (`.wasm`) into the `plugins/` folder of your Pumpkin server!
When you start up the server and run the `/plugins` command, you should see your plugin listed.

View File

@ -0,0 +1,103 @@
# Creating Your First Command
Registering commands in Go with Pumpkin is built on standard Go idiom using TinyGo WASM compilation.
---
## 1. Quick Example
Here is a complete Go plugin file (`main.go`) that registers a `/hello` command with permission checks and sends a response back to the player.
```go [main.go]
package main
import (
"github.com/Pumpkin-MC/pumpkin-api-go/api"
"github.com/Pumpkin-MC/pumpkin-api-go/pkg/pumpkin_plugin_command"
"github.com/Pumpkin-MC/pumpkin-api-go/pkg/pumpkin_plugin_context"
"github.com/Pumpkin-MC/pumpkin-api-go/pkg/pumpkin_plugin_permission"
_ "github.com/Pumpkin-MC/pumpkin-api-go/pkg/wit_exports"
)
type MyPlugin struct {
api.DefaultPlugin
}
func (p *MyPlugin) Metadata() api.Metadata {
return api.Metadata{
Name: "my_go_plugin",
Version: "0.1.0",
Authors: []string{"Developer"},
Description: "My first Pumpkin Go plugin",
}
}
func (p *MyPlugin) OnLoad(ctx *pumpkin_plugin_context.Context) {
// 1. Register permission node
ctx.RegisterPermission(pumpkin_plugin_permission.Permission{
Node: "my_go_plugin:hello",
Description: "Allows executing the /hello command",
Default: pumpkin_plugin_permission.PermissionDefaultAllow(),
})
// 2. Build and register command tree
cmd := pumpkin_plugin_command.New([]string{"hello", "hi"}, "Greets the player")
ctx.RegisterCommand(cmd, "my_go_plugin:hello")
}
func (p *MyPlugin) HandleCommand(cmdID uint32, sender pumpkin_plugin_command.CommandSender) int32 {
sender.SendMessage("Hello from Go Plugin!")
return 1
}
func init() {
api.RegisterPlugin(&MyPlugin{})
}
func main() {}
```
---
## 2. In-Game Preview
Once registered, your command automatically gains client-side autocompletion, syntax validation, and color highlighting in Minecraft:
<img src="/assets/first_command_preview.png" alt="In-Game Command Autocompletion Preview" width="500"/>
---
## 3. How It Works
::: details Step-by-Step Breakdown
### Step 1: Register Permission
Call `ctx.RegisterPermission` inside `OnLoad`:
```go
ctx.RegisterPermission(pumpkin_plugin_permission.Permission{
Node: "my_go_plugin:hello",
Description: "Allows executing the /hello command",
Default: pumpkin_plugin_permission.PermissionDefaultAllow(),
})
```
### Step 2: Build the Command Tree
Instantiate the command tree with `pumpkin_plugin_command.New`:
```go
cmd := pumpkin_plugin_command.New([]string{"hello", "hi"}, "Greets the player")
```
### Step 3: Register & Execute
Register the command with `ctx.RegisterCommand` and handle execution in `HandleCommand`:
```go
ctx.RegisterCommand(cmd, "my_go_plugin:hello")
```
:::
---
## Next Steps
- Follow the [Go Quick Start Guide](./quick-start) to set up TinyGo compilation.
- Learn more about [Basic Logic](./basic-logic).

View File

@ -0,0 +1,35 @@
# Creating a new project
Pumpkin plugins use the [Go](https://go.dev/) programming language and are compiled to WebAssembly.
## Prerequisites
Before we can start, make sure you have the following installed:
- [Go](https://go.dev/doc/install) (latest version recommended)
- [TinyGo](https://tinygo.org/getting-started/install/) (required for WASM compilation)
## Initializing a new module
First, create a new directory for your project and initialize a Go module:
```bash
mkdir hello-pumpkin
cd hello-pumpkin
go mod init github.com/yourname/hello-pumpkin
```
Next, add the Pumpkin Go API as a dependency:
```bash
go get github.com/Pumpkin-MC/pumpkin-api-go
```
## Project Structure
Your project should have at least a `main.go` file. The structure should look like this:
```text
├── go.mod
├── go.sum
└── main.go
```

View File

@ -15,3 +15,5 @@ Die Pumpkin Plugin API orientiert sich in vielen Bereichen an der Spigot/Bukkit
* [C# API](https://github.com/Pumpkin-MC/pumpkin-api-cs) * [C# API](https://github.com/Pumpkin-MC/pumpkin-api-cs)
* [Go API](https://github.com/Pumpkin-MC/pumpkin-api-go) * [Go API](https://github.com/Pumpkin-MC/pumpkin-api-go)
* [C API](https://github.com/Pumpkin-MC/pumpkin-api-c) * [C API](https://github.com/Pumpkin-MC/pumpkin-api-c)
* [Kotlin API](https://github.com/Pumpkin-MC/pumpkin-api-kt)
* [D API](https://github.com/Pumpkin-MC/pumpkin-api-d)

View File

@ -0,0 +1,94 @@
# Creating Your First Command
Registering custom commands in Pumpkin using Kotlin is concise, idiomatic, and strongly typed.
---
## 1. Quick Example
Here is a complete Kotlin plugin (`Plugin.kt`) that registers a `/hello` command with permission checks and sends a response back to the player.
```kotlin [src/wasmWasiMain/kotlin/plugin/Plugin.kt]
package plugin
import pumpkin.plugin.context.Context
import pumpkin.plugin.command.Command
import pumpkin.plugin.permission.Permission
import pumpkin.plugin.permission.PermissionDefault
class MyPlugin {
fun onLoad(ctx: Context) {
// 1. Register permission node
ctx.registerPermission(
Permission(
node = "my_kotlin_plugin:hello",
description = "Allows executing the /hello command",
default = PermissionDefault.ALLOW,
children = emptyList()
)
)
// 2. Build and register command tree
val cmd = Command(
names = listOf("hello", "hi"),
description = "Greets the player"
)
ctx.registerCommand(cmd, "my_kotlin_plugin:hello")
}
fun handleCommand(sender: pumpkin.plugin.command.CommandSender): Int {
sender.sendMessage("Hello from Kotlin Plugin!")
return 1
}
}
```
---
## 2. In-Game Preview
Once registered, your command automatically gains client-side autocompletion, syntax validation, and color highlighting in Minecraft:
<img src="/assets/first_command_preview.png" alt="In-Game Command Autocompletion Preview" width="500"/>
---
## 3. How It Works
::: details Step-by-Step Breakdown
### Step 1: Define the Permission Node
Construct a `Permission` object and pass it to `ctx.registerPermission`:
```kotlin
ctx.registerPermission(
Permission(
node = "my_kotlin_plugin:hello",
description = "Allows executing the /hello command",
default = PermissionDefault.ALLOW,
children = emptyList()
)
)
```
### Step 2: Build the Command Tree
Instantiate `Command` with primary names and aliases:
```kotlin
val cmd = Command(
names = listOf("hello", "hi"),
description = "Greets the player"
)
```
### Step 3: Register with Context
Register the command with `ctx.registerCommand` and handle calls inside `handleCommand`:
```kotlin
ctx.registerCommand(cmd, "my_kotlin_plugin:hello")
```
:::
---
## Next Steps
- Follow the [Kotlin Quick Start Guide](./quick-start) to configure your `Makefile` and Kotlin/Wasm build tools.

View File

@ -0,0 +1,81 @@
# Quick Start
This guide will help you get started with writing Pumpkin server plugins using Kotlin.
:::warning
Until the Kotlin + Wasm component toolchain matures more, there will be some oddity and inconvenience.
Bugs are also expected.
:::
## Prerequisites
Before you start, ensure you have the following installed:
- JDK 17 or later
- To run Gradle 9.4
- [Rust](https://rust-lang.org/)
- This is required as a key component (wit-bindgen) is written and Rust must be built from a particular Kotlin-enabled fork.
- You only need a default Rust install for your host platform. NOT for any WebAssembly targets
- [wasm-tools](https://github.com/bytecodealliance/wasm-tools)
- To bundle the Wasm Kotlin produces into a component
- Make (e.g. [GNU Make](https://www.gnu.org/software/make/))
- To run the convenience `Makefile`. You may opt to do without and perform the contained steps manually.
## Setting up the project
Unlike most of the other APIs packages available, [pumpkin-api-kt](https://github.com/Pumpkin-MC/pumpkin-api-kt) is a TEMPLATE, not e.g. a Maven package.
To start off, clone the template (and rename it as you please):
```sh
git clone --recurse-submodules https://github.com/Pumpkin-MC/pumpkin-api-kt
mv pumpkin-api-kt my_kotlin_plugin
cd my_kotlin_plugin
```
Next, we'll want to update the `wit` submodule so we are using the latest version of the Pumpkin plugin API.
```sh
cd wit
git pull origin master
cd ..
```
Finally, rename the Gradle project. Change the `rootProject.name` in `settings.gradle.kts`, AND the `PROJECT_NAME` in `Makefile`. They must both match. Whatever you name the project, is going to be the filename of the Wasm produced.
## Creating your first plugin
As part of the template, a basic plugin is implemented in `src/wasmWasiMain/kotlin/plugin/Plugin.kt`.
Feel free to modify the metadata at the bottom. However, before changing anything else, it's recommended that you build the plugin (see next section) first so that the bindings are generated and IDE completion works for `pumpkin`.
## Building the plugin
To build your plugin into a WebAssembly component:
```sh
make
```
The compiled `.wasm` file will be located in `build`. You can place this file in the `plugins` folder of your Pumpkin server.
Note that doing this the first time might take awhile, while it builds `wit-bindgen` from Rust source.
Running `make` will check for `wit-bindgen` updates each time. You may want to run instead `make componentify` after the initial setup to avoid this.
## Troubleshooting
### Linker errors
If you start getting errors like
```
main ThreadId(01) pumpkin::plugin: Failed to load plugin from
"./plugins/my_plugin.wasm": Wasm plugin initialization error: plugin failed
to load with error: component imports instance 'pumpkin:plugin/gui@0.1.0', but
a matching implementation was not found in the linker
```
or other "linker" errors when loading your plugin into Pumpkin, update the `wit` submodule.
```sh
cd wit
git pull origin master
cd ..
```

View File

@ -0,0 +1,171 @@
# Befehle von Bukkit migrieren
In Bukkit werden Befehle in der `plugin.yml` definiert und über `CommandExecutor`-Klassen oder die Brigadier-Bibliothek verarbeitet.
In Pumpkin werden Befehle mithilfe eines **von Brigadier inspirierten Befehlsbaums** erstellt und programmatisch über `context.register_command` registriert. Es werden keine YAML-Konfigurationsdateien verwendet.
---
## Wesentliche Unterschiede
| Merkmal | Bukkit / Spigot | Pumpkin |
| :--- | :--- | :--- |
| **Deklaration** | In der `plugin.yml` unter `commands:` deklariert | Im Code über `Command::new(...)` erstellt |
| **Berechtigungen** | In `plugin.yml` verknüpft oder via `player.hasPermission()` geprüft | Expliziter Berechtigungsknoten bei `register_command()` gebunden |
| **Tab-Vervollständigung** | Manuelles String-Matching in `TabCompleter` | Automatische baumbasierte clientseitige Tab-Vervollständigung |
| **Unterbefehle (Subcommands)** | Manuelles `if (args[0].equalsIgnoreCase("..."))` | Verschachtelte `Command`-Baumknoten |
---
## Code-Vergleich: Einfacher Befehl
Vergleich der Registrierung eines `/feed`-Befehls in Bukkit vs. Pumpkin:
### 1. Bukkit-Implementierung (Java)
```java [FeedCommand.java]
// 1. Registered in plugin.yml:
// commands:
// feed:
// description: Feeds the player
// permission: myplugin.feed
public class FeedCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage("Only players can execute this command!");
return true;
}
Player player = (Player) sender;
if (!player.hasPermission("myplugin.feed")) {
player.sendMessage("No permission!");
return true;
}
player.setFoodLevel(20);
player.sendMessage("Your hunger has been satisfied!");
return true;
}
}
```
### 2. Pumpkin-Implementierungen
::: code-group
```rust [Rust]
use pumpkin_plugin_api::{
command::{CommandHandler, CommandSender, ConsumedArgs, CommandError, Command},
permission::{Permission, PermissionDefault},
Context, Plugin, PluginMetadata, Server,
};
struct FeedExecutor;
impl CommandHandler for FeedExecutor {
fn handle(&self, sender: CommandSender, _server: Server, _args: ConsumedArgs) -> Result<i32, CommandError> {
sender.send_message("Your hunger has been satisfied!");
Ok(1)
}
}
pub struct MyPlugin;
impl Plugin for MyPlugin {
fn new() -> Self { MyPlugin }
fn metadata(&self) -> PluginMetadata {
PluginMetadata {
name: "feed_plugin".into(),
version: "1.0.0".into(),
authors: vec!["Developer".into()],
description: "Feed command plugin".into(),
}
}
fn on_load(&mut self, context: Context) -> pumpkin_plugin_api::Result<()> {
// 1. Register permission node (Replaces plugin.yml permission)
context.register_permission(&Permission {
node: "feed_plugin:feed".to_string(),
description: "Allows executing /feed".to_string(),
default: PermissionDefault::Allow,
children: Vec::new(),
})?;
// 2. Build command tree
let command = Command::new(&["feed".to_string(), "eat".to_string()], "Feeds the player")
.execute(FeedExecutor);
// 3. Register with context
context.register_command(command, "feed_plugin:feed")?;
Ok(())
}
}
```
```python [Python]
from pumpkin_api import (
Plugin, PluginMetadata, register_plugin,
permission, command, context, server
)
class FeedExecutor:
def handle(self, sender: command.CommandSender, srv: server.Server, args: command.ConsumedArgs) -> int:
sender.send_message("Your hunger has been satisfied!")
return 1
class FeedPlugin(Plugin):
def metadata(self) -> PluginMetadata:
return PluginMetadata(name="feed_plugin", version="1.0.0", authors=["Dev"], description="Feed command")
def on_load(self, ctx: context.Context) -> None:
ctx.register_permission(permission.Permission(
node="feed_plugin:feed",
description="Allows executing /feed",
default=permission.PermissionDefault.ALLOW,
children=[]
))
cmd = command.Command(["feed", "eat"], "Feeds the player")
cmd.execute(FeedExecutor())
ctx.register_command(cmd, "feed_plugin:feed")
register_plugin(FeedPlugin)
```
```kotlin [Kotlin]
package plugin
import pumpkin.plugin.context.Context
import pumpkin.plugin.command.Command
import pumpkin.plugin.command.CommandSender
import pumpkin.plugin.permission.Permission
import pumpkin.plugin.permission.PermissionDefault
class FeedPlugin {
fun onLoad(ctx: Context) {
ctx.registerPermission(
Permission(
node = "feed_plugin:feed",
description = "Allows executing /feed",
default = PermissionDefault.ALLOW,
children = emptyList()
)
)
val cmd = Command(
names = listOf("feed", "eat"),
description = "Feeds the player"
)
ctx.registerCommand(cmd, "feed_plugin:feed")
}
fun handleCommand(sender: CommandSender): Int {
sender.sendMessage("Your hunger has been satisfied!")
return 1
}
}
```
:::

View File

@ -0,0 +1,69 @@
# Konfiguration & Datenspeicherung von Bukkit migrieren
Bukkit-Plugins stützen sich stark auf `config.yml`, `YamlConfiguration` und das Serialisierungssystem von Bukkit.
In Pumpkin laufen WebAssembly-Plugins in einer sicheren Sandbox-Umgebung, in der Konfigurationsdateien nativ über Standardformate wie **TOML**, **JSON** oder **YAML** verarbeitet werden können.
---
## Wesentliche Unterschiede
| Merkmal | Bukkit / Spigot | Pumpkin |
| :--- | :--- | :--- |
| **Konfigurationsdateiformat** | `config.yml` (YAML-Format) | Flexibel: TOML, JSON oder eigene Dateien |
| **Generierung von Standard-Konfigurationen** | `saveDefaultConfig()` | Lesen der Konfiguration aus dem Plugin-Verzeichnis oder eingebetteten WASM-Assets |
| **Daten-Parsing** | `getConfig().getString(...)` | Native Deserialisierung über Serde / JSON / TOML |
| **Dateisystem-Sandboxing** | Beliebiger direkter Dateisystemzugriff | Dem WASM-Plugin zugewiesener, isolierter Verzeichniszugriff |
---
## Code-Vergleich: Laden der Konfiguration
### 1. Bukkit-Implementierung (Java)
```java [ConfigExample.java]
public class ConfigExample extends JavaPlugin {
@Override
public void onEnable() {
saveDefaultConfig(); // Saves config.yml from jar resources
FileConfiguration config = getConfig();
String welcomeMsg = config.getString("welcome-message", "Default welcome!");
int maxItems = config.getInt("max-items", 10);
getLogger().info("Loaded message: " + welcomeMsg);
}
}
```
### 2. Pumpkin-Implementierung (Rust)
In Pumpkin kannst du `serde::Deserialize` ableiten, um saubere TOML-Konfigurationsdateien einzulesen:
```rust [config.rs]
use serde::Deserialize;
use std::fs;
#[derive(Deserialize, Debug)]
pub struct PluginConfig {
pub welcome_message: String,
pub max_items: i32,
}
impl Default for PluginConfig {
fn default() -> Self {
Self {
welcome_message: "Default welcome!".to_string(),
max_items: 10,
}
}
}
pub fn load_config() -> PluginConfig {
let config_path = "plugins/my_plugin/config.toml";
if let Ok(content) = fs::read_to_string(config_path) {
toml::from_str(&content).unwrap_or_default()
} else {
PluginConfig::default()
}
}
```

View File

@ -0,0 +1,117 @@
# Events von Bukkit migrieren
In Bukkit werden Events verarbeitet, indem Klassen erstellt werden, die `Listener` implementieren, und Methoden mit `@EventHandler` annotiert werden.
In Pumpkin sind Event-Handler Strukturen (Structs) oder Objekte, die explizit über `context.register_event_handler(...)` registriert werden. Zudem unterscheidet Pumpkin zwischen **blockierenden** und **nicht-blockierenden** Events, um die Nebenläufigkeit (Concurrency) des Servers zu maximieren.
---
## Wesentliche Unterschiede
| Merkmal | Bukkit / Spigot | Pumpkin |
| :--- | :--- | :--- |
| **Listener-Deklaration** | `@EventHandler`-Annotation an Methoden | Implementierung des Traits / Interface `EventHandler<E>` |
| **Registrierung** | `pm.registerEvents(listener, plugin)` | `context.register_event_handler(handler, priority, is_blocking)` |
| **Ausführungsmodell** | Ausführung auf dem Haupt-Thread (`EventPriority`) | Wahl zwischen **blockierend** (sequenziell/abbrechbar) und **nicht-blockierend** (nebenläufig) |
| **Abbrechen von Events** | `event.setCancelled(true)` | `event.cancel()` bei blockierenden Events |
---
## Blockierende vs. Nicht-blockierende Events in Pumpkin
Im Gegensatz zu Bukkit, wo alle Event-Handler sequenziell auf dem Haupt-Server-Thread laufen, kannst du in Pumpkin festlegen, ob ein Event-Handler **blockierend** ist:
```rust
// Registrierungssignatur in Rust:
context.register_event_handler(handler, priority, is_blocking)?;
```
- **Blockierend (`is_blocking = true`)**: Wird in sequenzieller Prioritätsreihenfolge ausgeführt. Kann Event-Daten ändern (z. B. die Beitrittsnachricht bearbeiten) oder das Event abbrechen.
- **Nicht-blockierend (`is_blocking = false`)**: Wird nebenläufig über Worker-Threads hinweg ausgeführt. Ideal für Logging, Metriken oder externe Benachrichtigungen, bei denen kein Abbruch des Events erforderlich ist.
---
## Code-Vergleich: Spieler-Beitritts-Event
### 1. Bukkit-Implementierung (Java)
```java [JoinListener.java]
public class JoinListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
event.setJoinMessage("Welcome " + player.getName() + " to the server!");
}
}
// In JavaPlugin:
// getServer().getPluginManager().registerEvents(new JoinListener(), this);
```
### 2. Pumpkin-Implementierungen
::: code-group
```rust [Rust]
use pumpkin_plugin_api::{
Context, Plugin, PluginMetadata, Server,
events::{EventData, EventHandler, EventPriority, PlayerJoinEvent},
text::TextComponent,
};
struct JoinHandler;
impl EventHandler<PlayerJoinEvent> for JoinHandler {
fn handle<'a>(
&'a self,
_server: Server,
mut event: EventData<PlayerJoinEvent>,
) -> EventData<PlayerJoinEvent> {
event.join_message = TextComponent::text("Welcome to the Pumpkin server!");
event
}
}
pub struct MyPlugin;
impl Plugin for MyPlugin {
fn new() -> Self { MyPlugin }
fn metadata(&self) -> PluginMetadata {
PluginMetadata {
name: "join_plugin".into(),
version: "1.0.0".into(),
authors: vec!["Developer".into()],
description: "Join event handler".into(),
}
}
fn on_load(&mut self, context: Context) -> pumpkin_plugin_api::Result<()> {
// Registriere blockierenden Event-Handler mit Normal-Priorität
context.register_event_handler(JoinHandler, EventPriority::Normal, true)?;
Ok(())
}
}
```
```python [Python]
from pumpkin_api import (
Plugin, PluginMetadata, register_plugin,
event, server, context
)
class MyPlugin(Plugin):
def metadata(self) -> PluginMetadata:
return PluginMetadata(name="join_plugin", version="1.0.0", authors=["Dev"], description="Join event")
def on_load(self, ctx: context.Context) -> None:
self.register_event(ctx, event.EventType.PLAYER_JOIN_EVENT, self.on_player_join)
def on_player_join(self, srv: server.Server, evt: event.PlayerJoinEventData) -> event.PlayerJoinEventData:
print(f"Player joined!")
return evt
register_plugin(MyPlugin)
```
:::

View File

@ -0,0 +1,27 @@
# Migrationsübersicht & Architektur
Der Wechsel von der Plugin-Entwicklung für **Bukkit / Spigot / Paper** zu Pumpkin erfordert den Übergang von einem Java-zentrierten, objektorientierten Modell hin zu einem kompilierten, mehrsprachigen **WebAssembly (WASM)**-Komponentenmodell.
---
Die folgende Tabelle stellt das bewährte Bukkit-/Paper-Paradigma Pumpkins moderner WebAssembly-Architektur gegenüber:
| Konzept | Bukkit / Spigot / Paper | Pumpkin |
| :--- | :--- | :--- |
| **Sprachunterstützung** | Java / Kotlin / Scala (JVM) | Rust, Python, Kotlin, C#, Go, C |
| **Binärausgabe** | `.jar` Java-Archiv | `.wasm` WebAssembly-Komponente |
| **Plugin-Deskriptor** | `plugin.yml`-Datei | Programmatische `PluginMetadata`-Struktur |
| **Lebenszyklus-Hooks** | `onEnable()` / `onDisable()` | `on_load(context)` / `on_unload(context)` |
| **Sicherheit & Isolation** | Uneingeschränkte JVM-Reflection | Isoliertes WASM-Fähigkeitenmodell (Capability Model) |
| **Nebenläufigkeit (Concurrency)** | Single-Thread-Tick-Loop (`BukkitScheduler`) | Multithreaded native Ausführung mit Async-Laufzeitumgebung |
---
## Detaillierte Migrationsthemen
Erkunde ausführliche Leitfäden zur Migration der einzelnen zentralen Plugin-Subsysteme:
- [Befehle migrieren](./commands) — Übergang von `getCommand().setExecutor()` und `plugin.yml` zu Brigadier-Befehlsbäumen.
- [Events migrieren](./events) — Ersetzen von `@EventHandler` und `Listener`-Schnittstellen durch Pumpkins blockierendes bzw. nicht-blockierendes Event-System.
- [Inventare & GUIs migrieren](./inventories) — Wechsel von `Bukkit.createInventory()` zu Pumpkins Container- und Fenster-Handlern.
- [Konfiguration & Daten migrieren](./configuration) — Ersetzt `getConfig()` / `config.yml` durch natives TOML, JSON oder benutzerdefinierte Speicherlösungen.

View File

@ -0,0 +1,72 @@
# Inventare & GUIs von Bukkit migrieren
Das Erstellen von Inventar-GUIs (wie Kisten-Menüs, Shop-Oberflächen oder benutzerdefinierten Spielerfenstern) ist eine alltägliche Aufgabe bei der Minecraft-Plugin-Entwicklung.
In Bukkit werden benutzerdefinierte GUIs über `Bukkit.createInventory()` erstellt und via `InventoryClickEvent` verarbeitet. In Pumpkin werden Inventarfenster über **Window-APIs** und Container-Klickpakete verwaltet.
---
## Wesentliche Unterschiede
| Merkmal | Bukkit / Spigot | Pumpkin |
| :--- | :--- | :--- |
| **Inventar-Erstellung** | `Bukkit.createInventory(owner, size, title)` | Fenster-Container-Definitionen (`WindowType`) |
| **Öffnen von Fenstern** | `player.openInventory(inv)` | `player.open_window(window)` |
| **Klicks abfangen** | Verarbeitung via `InventoryClickEvent` | Callback-Handler für Fensterklicks |
| **Item-Stacking** | `ItemStack` mit `ItemMeta` | `ItemStack` mit Komponenten / NBT |
---
## Code-Vergleich: Öffnen eines benutzerdefinierten GUI-Menüs
### 1. Bukkit-Implementierung (Java)
```java [MenuGUI.java]
public class MenuGUI implements Listener {
public void openMenu(Player player) {
Inventory inv = Bukkit.createInventory(null, 9, Component.text("Custom Menu"));
ItemStack item = new ItemStack(Material.DIAMOND);
ItemMeta meta = item.getItemMeta();
meta.displayName(Component.text("Click Me!"));
item.setItemMeta(meta);
inv.setItem(4, item);
player.openInventory(inv);
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (event.getView().getTitle().equals("Custom Menu")) {
event.setCancelled(true);
if (event.getSlot() == 4) {
event.getWhoClicked().sendMessage("Diamond clicked!");
}
}
}
}
```
### 2. Pumpkin-Implementierung (Rust)
```rust [gui.rs]
use pumpkin_plugin_api::{
player::Player,
item::ItemStack,
window::{Window, WindowType},
text::TextComponent,
};
pub fn open_custom_menu(player: &Player) {
// 1. Erstelle ein Truhenfenster mit 9 Slots
let mut window = Window::new(WindowType::Generic9x1, TextComponent::text("Custom Menu"));
// 2. Setze Gegenstand in Slot 4
let item = ItemStack::new("minecraft:diamond", 1);
window.set_item(4, Some(item));
// 3. Öffne Fenster für den Spieler
player.open_window(window);
}
```

View File

@ -0,0 +1,95 @@
# Creating Your First Command
Registering and handling custom commands in Pumpkin with Python is designed to be straightforward and expressive.
---
## 1. Quick Example
Here is a complete, minimal Python plugin (`main.py`) that registers a `/hello` command with permission checks and sends a response back to the player.
```python [main.py]
from pumpkin_api import (
Plugin, PluginMetadata, register_plugin,
permission, command, context, server
)
class HelloCommand:
def handle(self, sender: command.CommandSender, srv: server.Server, args: command.ConsumedArgs) -> int:
sender.send_message("Hello from Python Plugin!")
return 1
class MyPlugin(Plugin):
def metadata(self) -> PluginMetadata:
return PluginMetadata(
name="my_python_plugin",
version="0.1.0",
authors=["Developer"],
description="My first Pumpkin Python plugin"
)
def on_load(self, ctx: context.Context) -> None:
# 1. Register permission node
ctx.register_permission(permission.Permission(
node="my_python_plugin:hello",
description="Allows executing the /hello command",
default=permission.PermissionDefault.ALLOW,
children=[]
))
# 2. Build the command tree with aliases & executor
cmd = command.Command(["hello", "hi"], "Greets the player")
cmd.execute(HelloCommand())
# 3. Register the command
ctx.register_command(cmd, "my_python_plugin:hello")
register_plugin(MyPlugin)
```
---
## 2. In-Game Preview
Once registered, your command automatically gains client-side autocompletion, syntax validation, and color highlighting in Minecraft:
<img src="/assets/first_command_preview.png" alt="In-Game Command Autocompletion Preview" width="500"/>
---
## 3. How It Works
::: details Step-by-Step Breakdown
### Step 1: Define the Permission
Commands in Pumpkin require a permission node. Register it with `permission.PermissionDefault.ALLOW` to allow execution by default:
```python
ctx.register_permission(permission.Permission(
node="my_python_plugin:hello",
description="Allows executing the /hello command",
default=permission.PermissionDefault.ALLOW,
children=[]
))
```
### Step 2: Build the Command Tree
Create a `command.Command` instance with primary names and aliases, then attach your handler with `.execute(...)`:
```python
cmd = command.Command(["hello", "hi"], "Greets the player")
cmd.execute(HelloCommand())
```
### Step 3: Register with Context
Pass the command tree and permission node string to `ctx.register_command`:
```python
ctx.register_command(cmd, "my_python_plugin:hello")
```
:::
---
## Next Steps
- Check out [Events](./events) to handle player actions and server events in Python.
- Learn more about [Basic Logic](./basic-logic).

View File

@ -0,0 +1,115 @@
# Creating Your First Command
Registering and handling custom commands in Pumpkin is designed to be developer-friendly, fast, and structured like Mojang's Brigadier system.
---
## 1. Quick Example
Here is a complete, minimal Rust plugin that registers a `/hello` command with permission checks and sends a response back to the player.
```rust [src/lib.rs]
use pumpkin_plugin_api::{
command::{CommandHandler, CommandSender, ConsumedArgs, CommandError, Command},
permission::{Permission, PermissionDefault},
Context, Plugin, PluginMetadata, Server,
};
struct HelloExecutor;
impl CommandHandler for HelloExecutor {
fn handle(
&self,
sender: CommandSender,
_server: Server,
_args: ConsumedArgs,
) -> Result<i32, CommandError> {
sender.send_message("Hello from Pumpkin!");
Ok(1)
}
}
pub struct MyPlugin;
impl Plugin for MyPlugin {
fn new() -> Self {
MyPlugin
}
fn metadata(&self) -> PluginMetadata {
PluginMetadata {
name: "my_plugin".into(),
version: env!("CARGO_PKG_VERSION").into(),
authors: vec!["Developer".into()],
description: "My first Pumpkin plugin".into(),
}
}
fn on_load(&mut self, context: Context) -> pumpkin_plugin_api::Result<()> {
// 1. Register permission node
context.register_permission(&Permission {
node: "my_plugin:hello".to_string(),
description: "Allows executing the /hello command".to_string(),
default: PermissionDefault::Allow,
children: Vec::new(),
})?;
// 2. Build the command tree with aliases & executor
let names = ["hello".to_string(), "hi".to_string()];
let command = Command::new(&names, "Greets the player").execute(HelloExecutor);
// 3. Register the command
context.register_command(command, "my_plugin:hello")?;
Ok(())
}
}
```
---
## 2. In-Game Preview
Once registered, your command automatically gains client-side autocompletion, syntax validation, and color highlighting in Minecraft:
<img src="/assets/first_command_preview.png" alt="In-Game Command Autocompletion Preview" width="500"/>
---
## 3. How It Works
::: details Step-by-Step Breakdown
### Step 1: Define the Permission
Commands in Pumpkin require a permission node. Using `PermissionDefault::Allow` allows all players to execute it by default:
```rust
context.register_permission(&Permission {
node: "my_plugin:hello".to_string(),
description: "Allows executing the /hello command".to_string(),
default: PermissionDefault::Allow,
children: Vec::new(),
})?;
```
### Step 2: Build the Command Tree
Use `Command::new` to define primary names and aliases, then attach your `CommandHandler` struct with `.execute(...)`:
```rust
let names = ["hello".to_string(), "hi".to_string()];
let command = Command::new(&names, "Greets the player")
.execute(HelloExecutor);
```
### Step 3: Register with Context
Pass the command tree and the permission node string to `context.register_command`:
```rust
context.register_command(command, "my_plugin:hello")?;
```
:::
---
## Next Steps
- Explore complex subcommands and argument parsing in the [Rock-Paper-Scissors Tutorial](./rock-paper-scissors).
- Learn how to handle inventory and GUI interactions in plugin logic.

View File

@ -1,347 +0,0 @@
# Ein benutzerdefiniertes Inventar öffnen
## Überblick
Das Inventarsystem in Pumpkin bietet einen flexiblen Weg zur Verwaltung und Manipulation von Items. Dieses Dokument erklärt, wie du eigene Inventare erstellst und implementierst.
## Inhaltsverzeichnis
- [Ein benutzerdefiniertes Inventar öffnen](#ein-benutzerdefiniertes-inventar-öffnen)
- [Überblick](#überblick)
- [Inhaltsverzeichnis](#inhaltsverzeichnis)
- [Einfache Inventar-Implementierung](#einfache-inventar-implementierung)
- [Erforderliche Traits](#erforderliche-traits)
- [Inventory Trait](#inventory-trait)
- [Clearable Trait](#clearable-trait)
- [Screen Handler](#screen-handler)
- [Generische Screen Handler verwenden](#generische-screen-handler-verwenden)
- [Eigene Screen Handler erstellen](#eigene-screen-handler-erstellen)
- [Best Practices](#best-practices)
- [Beispiele](#beispiele)
- [Einfacher Inventar-Einsatz](#einfacher-inventar-einsatz)
## Einfache Inventar-Implementierung
Die Struktur `BasicInventory` bietet eine Standard‑Implementierung mit 27 Slots. So implementieren Sie Ihr eigenes Inventar:
```rust
use pumpkin_world::{
inventory::{
split_stack, {Clearable, Inventory},
},
item::ItemStack,
};
#[derive(Debug)]
pub struct BasicInventory {
pub items: [Arc<Mutex<ItemStack>>; 27],
}
```
## Erforderliche Traits
### Inventory Trait
Das Trait `Inventory` definiert Kernfunktionalitäten die alle Inventare implementieren müssen:
```rust
impl Inventory for BasicInventory {
// Get the total number of slots in the inventory
fn size(&self) -> usize {
self.items.len()
}
// Check if the inventory is completely empty
fn is_empty(&self) -> InventoryFuture<'_, bool> {
Box::pin(async move {
for slot in self.items.iter() {
if !slot.lock().await.is_empty() {
return false;
}
}
true
})
}
// Get a reference to an item stack in a specific slot
fn get_stack(&self, slot: usize) -> InventoryFuture<'_, Arc<Mutex<ItemStack>>> {
Box::pin(async move { self.items[slot].clone() })
}
// Remove and return the entire stack from a slot
fn remove_stack(&self, slot: usize) -> InventoryFuture<'_, ItemStack> {
Box::pin(async move {
let mut removed = ItemStack::EMPTY.clone();
let mut guard = self.items[slot].lock().await;
std::mem::swap(&mut removed, &mut *guard);
removed
})
}
// Remove a specific amount of items from a stack
fn remove_stack_specific(&self, slot: usize, amount: u8) -> InventoryFuture<'_, ItemStack> {
Box::pin(async move { split_stack(&self.items, slot, amount).await })
}
// Set the contents of a specific slot
fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> {
Box::pin(async move {
*self.items[slot].lock().await = stack;
})
}
}
```
### Clearable Trait
Das `Clearable`-Trait bietet die Möglichkeit, ein Inventar zu leeren. Dies muss für das `Inventory`-Trait implementiert werden:
```rust
impl Clearable for YourInventory {
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
Box::pin(async move {
for item in self.items.iter() {
*item.lock().await = ItemStack::EMPTY.clone();
}
})
}
}
```
## Screen Handler
Bildschirmhandler dienen der Erstellung und Verwaltung der Benutzeroberfläche für Inventare. Sie definieren, wie Gegenstände zwischen Slots verschoben werden können und wie das Inventar mit dem Inventar des Spielers interagiert.
### Generische Screen Handler verwenden
Pumpkin bietet einen generischen Bildschirmhandler für gängige Inventarlayouts. So verwenden Sie ihn:
```rust
use pumpkin_inventory::generic_container_screen_handler::create_generic_9x3;
use pumpkin_inventory::player::player_inventory::PlayerInventory;
use pumpkin_inventory::screen_handler::{InventoryPlayer, ScreenHandler, ScreenHandlerFactory};
struct MyScreenFactory {
inventory: Arc<dyn Inventory>,
}
impl ScreenHandlerFactory for MyScreenFactory {
fn create_screen_handler(
&self,
sync_id: u8,
player_inventory: &Arc<PlayerInventory>,
_player: &dyn InventoryPlayer,
) -> Option<Arc<Mutex<dyn ScreenHandler>>> {
Some(Arc::new(Mutex::new(create_generic_9x3(
sync_id,
player_inventory,
self.inventory.clone(),
))))
}
fn get_display_name(&self) -> TextComponent {
TextComponent::translate("container.barrel", vec![])
}
}
// Erstellen Sie eine Factory für den Bildschirm
let factory = MyScreenFactory {
inventory: inventory.clone(),
};
// Öffne das Inventar eines Spieler
player.open_handled_screen(factory).await;
// Der Bildschirm wird folgendes automatisch verarbeiten:
// - Item-Bewegungen zwischen Slots
// - Schnellbewegungsfunktion
// - Spieler Inventar Interaktion
// - Bildschirm schließen
```
### Eigene Screen Handler erstellen
Du kannst benutzerdefinierte Bildschirmhandler erstellen, indem du das `ScreenHandler`-Trait implementierst. Das bietet mehr Flexibilität und ermöglicht es, Bildschirme für andere Zwecke als nur die Inventarverwaltung zu erstellen.
Um einen benutzerdefinierten Bildschirmhandler zu erstellen, kannst du eine neue Struktur anlegen, die das `Slot`-Trait implementiert. `NormalSlot` ist ein Slot, der mit Pumpkin mitgeliefert wird und lediglich als Index für ein Inventar dient und keine Einschränkungen hat.
TODO: Beispiel für einen benutzerdefinierten Slot
Hier ist ein Beispiel für den Quellcode des generischen Bildschirmhandlers:
```rust
use std::{any::Any, sync::Arc};
use pumpkin_data::screen::WindowType;
use pumpkin_world::{inventory::Inventory, item::ItemStack};
use pumpkin_world::{
player::player_inventory::PlayerInventory,
screen_handler::{InventoryPlayer, ScreenHandler, ScreenHandlerBehaviour},
slot::NormalSlot,
};
pub fn create_generic_9x3(
sync_id: u8,
player_inventory: &Arc<PlayerInventory>,
inventory: Arc<dyn Inventory>,
) -> GenericContainerScreenHandler {
GenericContainerScreenHandler::new(
WindowType::Generic9x3,
sync_id,
player_inventory,
inventory,
3,
)
}
pub struct GenericContainerScreenHandler {
pub inventory: Arc<dyn Inventory>,
pub rows: u8,
behaviour: ScreenHandlerBehaviour,
}
impl GenericContainerScreenHandler {
fn new(
screen_type: WindowType,
sync_id: u8,
player_inventory: &Arc<PlayerInventory>,
inventory: Arc<dyn Inventory>,
rows: u8,
) -> Self {
let mut handler = Self {
inventory,
rows,
behaviour: ScreenHandlerBehaviour::new(sync_id, Some(screen_type)),
};
handler.add_inventory_slots();
let player_inventory: Arc<dyn Inventory> = player_inventory.clone();
handler.add_player_slots(&player_inventory);
handler
}
fn add_inventory_slots(&mut self) {
for i in 0..self.rows {
for j in 0..9 {
self.add_slot(Arc::new(NormalSlot::new(
self.inventory.clone(),
(j + i * 9) as usize,
)));
}
}
}
}
impl ScreenHandler for GenericContainerScreenHandler {
fn on_closed<'a>(&'a mut self, player: &'a dyn InventoryPlayer) -> ScreenHandlerFuture<'a, ()> {
Box::pin(async move {
self.default_on_closed(player).await;
self.inventory.on_close().await;
})
}
fn as_any(&self) -> &dyn Any {
self
}
fn get_behaviour(&self) -> &ScreenHandlerBehaviour {
&self.behaviour
}
fn get_behaviour_mut(&mut self) -> &mut ScreenHandlerBehaviour {
&mut self.behaviour
}
fn quick_move<'a>(
&'a mut self,
_player: &'a dyn InventoryPlayer,
slot_index: i32,
) -> ItemStackFuture<'a> {
Box::pin(async move {
let mut stack_left = ItemStack::EMPTY.clone();
// Assuming bounds check passed for slot_index by caller or within quick_move spec
let slot = self.get_behaviour().slots[slot_index as usize].clone();
if slot.has_stack().await {
let slot_stack_lock = slot.get_stack().await;
let slot_stack_guard = slot_stack_lock.lock().await;
stack_left = slot_stack_guard.clone();
// Release the guard before calling insert_item which needs its own lock
drop(slot_stack_guard);
// Re-acquire lock for insert_item (which expects &mut ItemStack)
let mut slot_stack_mut = slot_stack_lock.lock().await;
if slot_index < (self.rows * 9) as i32 {
// Move from inventory to player area (end)
if !self
.insert_item(
&mut slot_stack_mut,
(self.rows * 9).into(),
self.get_behaviour().slots.len() as i32,
true,
)
.await
{
return ItemStack::EMPTY.clone();
}
} else if !self
.insert_item(&mut slot_stack_mut, 0, (self.rows * 9).into(), false)
.await
{
// Move from player area to inventory (start)
return ItemStack::EMPTY.clone();
}
// Check the resulting state of the slot stack after insert_item
if slot_stack_mut.is_empty() {
drop(slot_stack_mut); // Release lock
slot.set_stack(ItemStack::EMPTY.clone()).await;
} else {
drop(slot_stack_mut); // Release lock
slot.mark_dirty().await;
}
}
stack_left
})
}
}
```
## Best Practices
1. **Thread-Sicherheit**
- Implementiere eine korrekte Fehlerbehandlung für die Slot-Grenzenprüfung.
- Denk daran, Stack-Sperren vor der Verwendung von `inventory.set_stack()` oder `slot.get_cloned_stack()` aufzuheben, um Deadlocks zu vermeiden.
2. **Inventarverwaltung**
- Verwende die Konstante `ItemStack::EMPTY` zum Leeren von Slots oder zum Initialisieren leerer Inventare.
3. **Implementierung der Bildschirmbehandlung**
- Behandel das Schließen des Inventars korrekt, um den Verlust von Gegenständen zu verhindern.
- Stelle sicher, dass die Anzahl der Slots der Anzahl der Slots im jeweiligen Fenstertyp entspricht.
## Beispiele
### Grundlegende Inventarnutzung
```rust
// Erstellt ein neues Inventar
let inventory = BasicInventory {
items: [(); 27].map(|_| Arc::new(Mutex::new(ItemStack::EMPTY))),
};
// Fügt ein Item dem Slot hinzu
inventory.set_stack(0, ItemStack::new(1, &Items::OAK_LOG)).await;
// Entfernt Items aus einem Slot
let removed = inventory.remove_stack(0).await;
// Prüft ob das Inventar leer ist
let is_empty = inventory.is_empty().await;
```

View File

@ -1,11 +0,0 @@
# Ein Beispiel‑Plugin schreiben
Dieses Tutorial führt dich durch das Erstellen eines neuen Plugins.
Du solltest etwas Erfahrung mit Rust und der Kommandozeile mitbringen.
Inhalte dieses Tutorials:
- Die Join‑Nachricht anpassen
- Einen Schere‑Stein‑Papier‑Befehl erstellen
- Plugin‑Daten im Plugin‑Ordner speichern (bald)

View File

@ -0,0 +1,348 @@
# Licensing & Updates (`pumpkin-plugin-utils`)
`pumpkin-plugin-utils` is an official utility crate for Pumpkin Rust plugins. It provides built-in tools for **licensing checks**, **cryptographic signature verification**, and **update checks** against the [Pumpkin Marketplace](https://market.pumpkinmc.org).
## Features
- **Offline Ed25519 Signature Verification**: Verifies plugin integrity and embedded marketplace metadata in `< 1ms` on startup without blocking the server.
- **Global Metadata Caching**: Call `init(&context)` once in your plugin's `on_load` lifecycle method to cache verified metadata globally.
- **Online License Verification**: Query the marketplace `/api/v1/rest/check-license` endpoint with automatic 7-day lease caching (`license_lease.json`).
- **Offline Grace Period**: Resilient offline lease evaluation ensures your plugin keeps working during marketplace maintenance or network outages.
- **Zero-Argument Update Checking**: Easily check if newer plugin releases are available on the marketplace.
- **Dynamic Public Key Resolution**: Resolves the marketplace public key dynamically via host WIT imports or HTTPS fallback without hardcoding keys.
---
## Adding the Dependency
Add `pumpkin-plugin-utils` alongside `pumpkin-plugin-api` in your plugin's `Cargo.toml`:
:::code-group
```toml [Cargo.toml]
[package]
name = "my-plugin"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib"]
[dependencies]
pumpkin-plugin-api = "0.1.0-dev+26.2-26.45"
pumpkin-plugin-utils = "0.1.0-dev+26.2-26.45"
tracing = "0.1"
```
:::
---
## Initialization
Before performing license or update checks, initialize the utility crate inside your plugin's `on_load` method using the plugin's `Context`:
```rust
use pumpkin_plugin_api::{Context, Plugin, PluginMetadata};
use tracing::{info, warn};
struct MyPlugin;
impl Plugin for MyPlugin {
fn new() -> Self {
Self
}
fn metadata(&self) -> PluginMetadata {
PluginMetadata {
name: "MyPlugin".into(),
version: env!("CARGO_PKG_VERSION").into(),
authors: vec!["Author".into()],
description: "Plugin with license and update checks".into(),
}
}
fn on_load(&mut self, context: Context) -> pumpkin_plugin_api::Result<()> {
// Initialize pumpkin-plugin-utils (verifies signature & caches metadata)
let metadata = pumpkin_plugin_utils::init(&context)
.map_err(|e| format!("Initialization failed: {e}"))?;
info!(
"Loaded plugin '{}' v{} (Dev: {})",
metadata.plugin_name, metadata.version, metadata.dev_name
);
Ok(())
}
}
```
::: info What happens during `init`?
1. Locates the plugin's `.wasm` binary in the server directory.
2. Extracts the `pumpkin.metadata` and `wasm_signature` custom sections.
3. Cryptographically verifies the Ed25519 signature over the WASM binary and metadata.
4. Caches the verified `PumpkinMetadata` globally for subsequent calls.
:::
---
## Checking for Updates
`pumpkin-plugin-utils` provides both zero-argument automatic checking and custom manual checking.
### 1. Automatic Update Check (Recommended)
Once initialized, call `pumpkin_plugin_utils::check_for_updates()` without arguments. It automatically uses the cached plugin name, current version, and marketplace endpoint:
```rust
use tracing::{info, warn};
fn check_updates() {
match pumpkin_plugin_utils::check_for_updates() {
Ok(update) => {
if update.update_available {
info!(
"A new update is available: {}!",
update.latest_version.as_deref().unwrap_or("unknown")
);
} else {
info!("Plugin is up to date.");
}
}
Err(err) => {
warn!("Failed to check for updates: {err}");
}
}
}
```
### 2. Manual Update Check (`UpdateChecker`)
If you want to manually specify the plugin name, version, or a custom marketplace URL, use `UpdateChecker`:
```rust
use pumpkin_plugin_utils::UpdateChecker;
let checker = UpdateChecker::new();
let response = checker.check_for_updates(
"my-plugin",
"1.0.0",
"https://market.pumpkinmc.org",
)?;
if response.update_available {
println!("Update found: {:?}", response.latest_version);
}
```
### Update Response Structure
The update check returns a `CheckUpdateResponse`:
```rust
pub struct CheckUpdateResponse {
/// Whether a newer stable release exists on the marketplace.
pub update_available: bool,
/// The latest stable version string, if available.
pub latest_version: Option<String>,
}
```
---
## Checking and Verifying Licenses
`pumpkin-plugin-utils` supports online verification against the marketplace API as well as offline lease management with configurable grace periods.
### 1. Online License Check
To verify a license against the marketplace (`GET /api/v1/rest/check-license`):
```rust
// Pass `None` to use the embedded license key from metadata
let response = pumpkin_plugin_utils::check_license_online(None)
.map_err(|e| format!("License verification failed: {e}"))?;
if response.valid {
info!("License is valid (status: {})", response.status);
} else {
warn!("License is invalid: {}", response.status);
return Err(format!("Invalid license status: {}", response.status).into());
}
```
#### Providing a Custom License Key Override
If your plugin allows server owners to configure a license key in a `config.toml` file, pass `Some(&key)`:
```rust
let config_key = "LIC-CUSTOM-KEY-12345";
let response = pumpkin_plugin_utils::check_license_online(Some(config_key))?;
```
::: tip 7-Day Lease Caching
Successful online checks automatically save a verified lease file (`license_lease.json`) into the plugin's data folder with a 7-day expiration.
:::
### 2. Evaluating License with Grace Period
To keep paid plugins functional when the server is offline or the marketplace is unreachable, use `evaluate_license`:
```rust
use pumpkin_plugin_utils::LicenseStatus;
use tracing::{info, warn};
// Specify grace period duration in days (e.g., 7 days)
let grace_period_days = 7;
match pumpkin_plugin_utils::evaluate_license(grace_period_days) {
LicenseStatus::Valid(meta) => {
info!("License valid for buyer (User ID: {})", meta.user_id);
}
LicenseStatus::GracePeriod { metadata, days_remaining, reason } => {
warn!(
"Running in offline grace period ({} days remaining). Reason: {}",
days_remaining, reason
);
}
LicenseStatus::Invalid(reason) => {
return Err(format!("Plugin license invalid or tampered: {reason}").into());
}
LicenseStatus::Unsigned => {
info!("Plugin is running in unsigned / development mode.");
}
}
```
### `LicenseStatus` Enum
| Variant | Description |
| :--- | :--- |
| `LicenseStatus::Valid(PumpkinMetadata)` | License is valid, verified, or the plugin is free / open-source. |
| `LicenseStatus::GracePeriod { metadata, days_remaining, reason }` | Operating offline with a previously validated lease that is within the allowable grace period. |
| `LicenseStatus::Invalid(String)` | Signature is invalid, expired, revoked, or metadata was tampered with. |
| `LicenseStatus::Unsigned` | Binary does not contain marketplace metadata/signature (useful during local development). |
---
## Accessing Plugin Metadata
You can access the verified plugin metadata anywhere in your codebase using `get_metadata` or `metadata()`:
```rust
if let Some(meta) = pumpkin_plugin_utils::get_metadata() {
println!("Plugin Name: {}", meta.plugin_name);
println!("Plugin Version: {}", meta.version);
println!("Is Paid: {}", meta.is_paid);
println!("License Key: {:?}", meta.license_key);
println!("Buyer User ID: {}", meta.user_id);
println!("Developer: {} (ID: {})", meta.dev_name, meta.dev_id);
println!("Marketplace URL: {}", meta.marketplace_url);
println!("Issued At: {}", meta.issued_at);
}
```
### `PumpkinMetadata` Fields
| Field | Type | Description |
| :--- | :--- | :--- |
| `plugin_name` | `String` | Canonical plugin name on the marketplace. |
| `version` | `String` | SemVer version string of the plugin binary. |
| `plugin_id` | `i64` | Unique plugin identifier on the marketplace. |
| `dev_id` | `i64` | Developer account ID. |
| `dev_name` | `String` | Developer display name. |
| `is_paid` | `bool` | `true` if this is a premium/commercial plugin. |
| `user_id` | `i64` | Buyer / licensee user ID (`0` for free plugins). |
| `license_key` | `Option<String>` | Unique license key issued to the licensee. |
| `marketplace_url` | `String` | Base marketplace URL (`https://market.pumpkinmc.org`). |
| `issued_at` | `String` | ISO-8601 timestamp when the binary/license was issued. |
---
## Complete Example
Here is a full plugin implementation combining initialization, online licensing checks, offline grace periods, and update checking:
:::code-group
```rust:line-numbers [src/lib.rs]
use pumpkin_plugin_api::{Context, Plugin, PluginMetadata};
use pumpkin_plugin_utils::LicenseStatus;
use tracing::{error, info, warn};
struct CommercialPlugin;
impl Plugin for CommercialPlugin {
fn new() -> Self {
Self
}
fn metadata(&self) -> PluginMetadata {
PluginMetadata {
name: "CommercialPlugin".into(),
version: env!("CARGO_PKG_VERSION").into(),
authors: vec!["Developer".into()],
description: "A commercial Pumpkin plugin".into(),
}
}
fn on_load(&mut self, context: Context) -> pumpkin_plugin_api::Result<()> {
// 1. Initialize plugin-utils (verifies Ed25519 signature & caches metadata)
let meta = pumpkin_plugin_utils::init(&context).map_err(|err| {
error!("Signature verification failed: {err}");
format!("Security verification error: {err}")
})?;
info!("Loaded {} v{}", meta.plugin_name, meta.version);
// 2. Validate license (offline evaluation + online check)
match pumpkin_plugin_utils::evaluate_license(7) {
LicenseStatus::Valid(_) => {
info!("Local license status: Valid");
}
LicenseStatus::GracePeriod { days_remaining, .. } => {
warn!("Local license in grace period: {days_remaining} days remaining");
}
LicenseStatus::Unsigned => {
info!("Running in development mode (unsigned binary)");
}
LicenseStatus::Invalid(reason) => {
error!("Invalid license: {reason}");
return Err(format!("License verification failed: {reason}").into());
}
}
// 3. Online license check if paid
if meta.is_paid {
if let Ok(check) = pumpkin_plugin_utils::check_license_online(None) {
if !check.valid {
return Err(format!("Online license rejected: {}", check.status).into());
}
info!("Online license check confirmed: {}", check.status);
} else {
warn!("Online license verification unreachable, falling back to local lease");
}
}
// 4. Check for updates
if let Ok(update) = pumpkin_plugin_utils::check_for_updates() {
if update.update_available {
info!(
"A new version is available on the marketplace: {}",
update.latest_version.as_deref().unwrap_or("unknown")
);
}
}
Ok(())
}
fn on_unload(&mut self, _context: Context) -> pumpkin_plugin_api::Result<()> {
info!("CommercialPlugin unloaded.");
Ok(())
}
}
pumpkin_plugin_api::register_plugin!(CommercialPlugin);
```
:::

View File

@ -7,3 +7,14 @@
**Ursache:** Das hängt mit der Authentifizierung zusammen, häufig mit der Einstellung `prevent_proxy_connections`. **Ursache:** Das hängt mit der Authentifizierung zusammen, häufig mit der Einstellung `prevent_proxy_connections`.
**Lösung:** Deaktiviere `prevent_proxy_connections` in `pumpkin.toml`. **Lösung:** Deaktiviere `prevent_proxy_connections` in `pumpkin.toml`.
2. ## Verbindung über 0.0.0.0 schlägt fehl
**Problem:** Spieler, die dem Server auf demselben PC beitreten möchten, können keine Verbindung herstellen (z. B. Fehler „Connection refused“), wenn sie `0.0.0.0` oder `0.0.0.0:25565` eingeben.
**Ursache:** In `pumpkin.toml` weist `0.0.0.0` den Server an, auf allen lokalen Netzwerkschnittstellen zu lauschen. Es ist eine Bind-Adresse für den Server, aber keine gültige Zieladresse für den Minecraft-Client.
**Lösung:**
- Wenn du vom **selben PC** aus beitrittst, verwende `localhost` oder `127.0.0.1`.
- Wenn du von einem **anderen Gerät im selben lokalen Netzwerk (LAN)** aus beitrittst, verwende die lokale IP-Adresse des Host-PCs (z. B. `192.168.x.x`).
- Wenn Spieler über das **Internet** beitreten sollen, müssen sie deine öffentliche IP-Adresse oder Domain verwenden (mit entsprechender Portweiterleitung im Router).

View File

@ -1,35 +1,45 @@
# Migrating a Server from Bukkit / Spigot / Paper to Pumpkin # Migrating from Bukkit / Spigot / Paper to Pumpkin
Switching your server environment from Paper/Spigot to Pumpkin brings massive performance gains, multithreaded tick execution, and reduced RAM usage. However, because Pumpkin is built in Rust rather than running on the Java Virtual Machine, there are fundamental architectural differences that server administrators need to know. This guide covers architectural and configuration differences when transitioning a server from Bukkit, Spigot, or Paper to Pumpkin.
--- ---
## 1. Major Server Differences At-a-Glance ## 1. Architectural Differences
| Feature / Aspect | Bukkit / Spigot / Paper | Pumpkin | | Aspect | Bukkit / Spigot / Paper | Pumpkin |
| :--- | :--- | :--- | | :--- | :--- | :--- |
| **Runtime Environment** | Java Virtual Machine (JVM) | Native Binary (Rust) | | **Runtime Environment** | Java Virtual Machine (requires Java 17/21+) | Native executable (compiled Rust, no Java required) |
| **Main Thread Architecture** | Single-threaded tick loop with asynchronous offloading | Multithreaded tick execution across CPU cores | | **Startup Command** | `java [flags] -jar server.jar` | `./pumpkin` |
| **Plugin Engine** | `.jar` files compiled for Java / Bukkit API | `.wasm` WebAssembly components running in sandboxed WASM runtime | | **Tick Loop** | Single-threaded tick loop with async worker offloading | Multithreaded tick execution across CPU cores |
| **Plugin Languages** | Java / Kotlin / Scala | Rust, Python, Kotlin, C#, Go, C | | **Plugin Format** | Java bytecode (`.jar`) targeting Bukkit API | WebAssembly (`.wasm`), or `.jar` via PatchBukkit |
| **Configuration Format** | `server.properties` & `paper.yml` / `spigot.yml` | `pumpkin.toml` & structured TOML configuration files | | **Plugin Languages** | Java, Kotlin, Scala | Rust, Python, Kotlin, C#, Go, C |
| **Memory Footprint** | High baseline (JVM garbage collection overhead) | Micro baseline (Native memory management) | | **Configuration** | `server.properties`, `paper.yml`, `spigot.yml` | `pumpkin.toml` (TOML format) |
| **Memory Management** | JVM Garbage Collection | Native OS memory allocation |
--- ---
## 2. Plugins & Extensions ## 2. Plugins & Extensions
- **Java `.jar` Plugins Cannot Run Directly**: Standard Bukkit/Spigot `.jar` plugins are bytecode compiled for the Java JVM and Bukkit API. They cannot be dropped into Pumpkin's `plugins/` directory. ### WebAssembly Plugins
- **WebAssembly Plugins**: Pumpkin uses WebAssembly (`.wasm`) for plugins. This sandboxes plugins for memory safety and security while allowing developers to write plugins in virtually any language. Pumpkin's primary plugin format is WebAssembly (`.wasm`):
- **Porting Plugins**: If you maintain custom internal plugins, consult our [Developer Migration Guide](../plugin-dev/migrating-from-bukkit/index) to convert Java logic to Pumpkin plugin bindings. - **Isolation**: Plugins run in a sandboxed WebAssembly runtime.
- **Language Support**: Plugins can be compiled to WASM from Rust, Python, Go, C#, C, or Kotlin.
- **Custom Plugins**: For porting custom Bukkit plugins to Pumpkin, see the [Developer Migration Guide](../plugin-dev/migrating-from-bukkit/index).
### Bukkit Plugin Compatibility: PatchBukkit
For servers relying on existing Bukkit/Spigot `.jar` plugins, the **PatchBukkit** project provides a compatibility layer:
- **Architecture**: PatchBukkit embeds a JVM within Pumpkin and reimplements parts of the Bukkit API, bridging calls to Pumpkin via JNI and FFI.
- **Plugin Location**: Compatible `.jar` plugins are placed in `patchbukkit/patchbukkit-plugins/`.
- **Status & Limitations**: PatchBukkit is in active development. While standard Bukkit API calls are supported, plugins that depend on internal NMS (`net.minecraft.server`) classes, CraftBukkit internals, or bytecode manipulation may not function properly.
- **Java Requirement**: Running PatchBukkit requires a Java runtime (JRE/JDK) installed on the host system to run the embedded JVM.
--- ---
## 3. Configuration & Properties ## 3. Configuration & Properties
Instead of `server.properties` and YAML files, Pumpkin consolidates server configuration into clean TOML files: Pumpkin uses TOML configuration files instead of `server.properties` and YAML:
| Paper / Spigot Setting | Pumpkin `pumpkin.toml` Equivalent | | Paper / Spigot (`server.properties`) | Pumpkin (`pumpkin.toml`) |
| :--- | :--- | | :--- | :--- |
| `server-port=25565` | `server_address = "0.0.0.0:25565"` | | `server-port=25565` | `server_address = "0.0.0.0:25565"` |
| `motd=...` | `motd = "A Pumpkin Server"` | | `motd=...` | `motd = "A Pumpkin Server"` |
@ -42,31 +52,75 @@ Instead of `server.properties` and YAML files, Pumpkin consolidates server confi
## 4. World & Data Storage ## 4. World & Data Storage
- **Anvil Format Compatibility**: Pumpkin reads standard Minecraft chunk data format. - **Format Compatibility**: Pumpkin reads standard Anvil chunk format (`.mca` files).
- **Dimension Directories**: Make sure `world`, `world_nether`, and `world_the_end` directory structures are mapped appropriately when copying existing worlds from Paper/Spigot server installations. - **Directory Layout**: Ensure dimension directories (`world`, `world_nether`, `world_the_end`) match Pumpkin's expected layout when copying world folders from existing Paper/Spigot installations.
- **Latest World & Data Pack Format Required**: At least for now, Pumpkin only supports the latest world format and latest data pack format for its target Minecraft release. Older world formats or legacy data pack versions are not automatically converted at runtime.
- **Upgrading Worlds in the Client**: If migrating an older world, upgrade it first before loading it in Pumpkin. You can update a world directly in the official Minecraft client: open the client on the matching latest version, navigate to **Singleplayer**, select the world, click **Edit**, and choose **Optimize World**. Alternatively, you can run the world once on a vanilla server matching the latest version.
- **Data Packs**: Ensure all data packs located in `world/datapacks` are updated to the pack format expected by the target release.
--- ---
## 5. Performance Tuning & Startup ## 5. Startup & JVM Flags
Unlike Paper servers which require complex JVM flags (`-XX:+UseG1GC`, `-Xms`, `-Xmx`), Pumpkin runs as a direct native binary: ### No Java Installation Needed
Pure Pumpkin is a self-contained native executable. You do not need a Java runtime (JRE/JDK) installed on your system or inside your container to run the server.
```bash ### Startup Commands
# Starting Pumpkin Server on Linux/macOS Paper and Spigot servers often use JVM startup scripts with heap allocation and garbage collection flags (such as Aikar's Flags):
:::code-group
```bash [Paper (JVM)]
# Common Paper startup command with Aikar's Flags:
java -Xms10G -Xmx10G \
-XX:+UseG1GC \
-XX:+ParallelRefProcEnabled \
-XX:MaxGCPauseMillis=200 \
-XX:+UnlockExperimentalVMOptions \
-XX:+DisableExplicitGC \
-XX:+AlwaysPreTouch \
-XX:G1NewSizePercent=30 \
-XX:G1MaxNewSizePercent=40 \
-XX:G1HeapRegionSize=8M \
-XX:G1ReservePercent=20 \
-XX:G1HeapWastePercent=5 \
-XX:G1MixedGCCountTarget=4 \
-XX:InitiatingHeapOccupancyPercent=15 \
-XX:G1MixedGCLiveThresholdPercent=90 \
-XX:G1RSetUpdatingPauseTimePercent=5 \
-XX:SurvivorRatio=32 \
-XX:+PerfDisableSharedMem \
-XX:MaxTenuringThreshold=1 \
-Dusing.aikars.flags=https://mcflags.emc.gs \
-Daikars.new.flags=true \
-jar paper.jar --nogui
```
```bash [Pumpkin (Native)]
# Linux / macOS:
./pumpkin ./pumpkin
# Or running via Docker # Windows:
./pumpkin.exe
# Docker:
docker run -p 25565:25565 -v ./data:/data pumpkinmc/pumpkin:latest docker run -p 25565:25565 -v ./data:/data pumpkinmc/pumpkin:latest
``` ```
No garbage collection tuning or JVM heap allocation tuning is needed. :::
### Memory Differences
- **No Garbage Collector**: Pumpkin is written in Rust and uses deterministic compile-time memory management (RAII). There is no runtime garbage collector or GC pause tuning.
- **No Fixed Heap Allocation**: Flags like `-Xms` and `-Xmx` do not exist in native binaries. Memory is allocated from the OS dynamically as chunks and entities load, and returned when they unload.
- **JVM Flags Do Not Apply**: Flags tuning garbage collection strategies, generational sizing, or JVM internals are not needed and cannot be passed to the binary.
--- ---
## Admin Checklist for Migration ## Admin Checklist
1. [ ] Back up your existing Paper/Spigot server data and world files. 1. [ ] Back up existing server data and world files, and ensure the world and data packs are updated to the latest format (e.g., via the client's "Optimize World").
2. [ ] Map `server.properties` values into Pumpkin's `pumpkin.toml`. 2. [ ] Map `server.properties` settings to `pumpkin.toml`.
3. [ ] Check if replacement WebAssembly plugins (`.wasm`) are available for your essential server utilities. 3. [ ] Identify required plugins and check for WebAssembly (`.wasm`) equivalents or test with [PatchBukkit](#bukkit-plugin-compatibility-patchbukkit).
4. [ ] Configure Proxy support (`Velocity` / `BungeeCord`) if running behind a server network. 4. [ ] Configure proxy settings (`Velocity` / `BungeeCord`) in `pumpkin.toml` if using a proxy network.
5. [ ] Launch `./pumpkin` and verify player connectivity and performance logs. 5. [ ] Update startup scripts to launch `./pumpkin` directly without JVM arguments.
6. [ ] Start the server and check connectivity and logs.

View File

@ -2,7 +2,7 @@
This guide explains how to implement and register a new command in the Pumpkin server codebase. This guide explains how to implement and register a new command in the Pumpkin server codebase.
Commands in Pumpkin are implemented in the `crates/pumpkin/src/command/commands/` directory and registered into the central [`CommandDispatcher`](file:///home/alex/Documents/Development/Rust/Pumpkin/crates/pumpkin-command/src/node/dispatcher.rs) during server initialization. Commands in Pumpkin are implemented in the `crates/pumpkin/src/command/commands/` directory and registered into the central [`CommandDispatcher`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/node/dispatcher.rs) during server initialization.
--- ---
@ -10,8 +10,8 @@ Commands in Pumpkin are implemented in the `crates/pumpkin/src/command/commands/
A typical command file contains: A typical command file contains:
1. **Metadata Constants**: Command description, permission node identifier, and argument names. 1. **Metadata Constants**: Command description, permission node identifier, and argument names.
2. **Permission Registration**: Declaring default OP requirements in the server's [`PermissionRegistry`](file:///home/alex/Documents/Development/Rust/Pumpkin/crates/pumpkin-util/src/permission.rs). 2. **Permission Registration**: Declaring default OP requirements in the server's [`PermissionRegistry`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-util/src/permission.rs).
3. **Command Executors**: Structs implementing the [`CommandExecutor`](file:///home/alex/Documents/Development/Rust/Pumpkin/crates/pumpkin-command/src/node/mod.rs) trait for each terminal node or subcommand. 3. **Command Executors**: Structs implementing the [`CommandExecutor`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/node/mod.rs) trait for each terminal node or subcommand.
4. **Registration Function**: Constructing the argument tree using fluent builders (`command`, `literal`, `argument`). 4. **Registration Function**: Constructing the argument tree using fluent builders (`command`, `literal`, `argument`).
--- ---
@ -60,7 +60,7 @@ const ERROR_NOT_PLAYER: CommandErrorType<0> = CommandErrorType::new(
### 2. Implement the Executors ### 2. Implement the Executors
Command execution logic is encapsulated in structs implementing [`CommandExecutor`](file:///home/alex/Documents/Development/Rust/Pumpkin/crates/pumpkin-command/src/node/mod.rs): Command execution logic is encapsulated in structs implementing [`CommandExecutor`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/node/mod.rs):
```rust ```rust
/// Heals the executing player to full health. /// Heals the executing player to full health.

View File

@ -6,7 +6,7 @@ Pumpkin provides a comprehensive suite of type-safe command arguments through `p
## Standard Argument Types ## Standard Argument Types
Argument parsers implement the [`ArgumentType<S>`](file:///home/alex/Documents/Development/Rust/Pumpkin/crates/pumpkin-command/src/argument_types/argument_type.rs) trait. The following built-in types are available for command builders: Argument parsers implement the [`ArgumentType<S>`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/argument_types/argument_type.rs) trait. The following built-in types are available for command builders:
### 1. Primitive & Scalar Types ### 1. Primitive & Scalar Types
@ -43,7 +43,7 @@ argument("location", Vec3ArgumentType)
``` ```
### Retrieving Parsed Coordinates ### Retrieving Parsed Coordinates
Inside an executor, coordinate arguments resolve relative offsets against the sender's current position and orientation in the [`CommandSource`](file:///home/alex/Documents/Development/Rust/Pumpkin/crates/pumpkin/src/command/context/command_source.rs): Inside an executor, coordinate arguments resolve relative offsets against the sender's current position and orientation in the [`CommandSource`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/command/context/command_source.rs):
```rust ```rust
// Extracts centered f64 coordinates (handling ~ and ^ relative to sender) // Extracts centered f64 coordinates (handling ~ and ^ relative to sender)
@ -59,7 +59,7 @@ let block_pos: BlockPos = BlockPosArgumentType::get_block_pos(context, "pos")?;
Entity selectors allow players and command blocks to target entities using player names, UUIDs, or vanilla target selectors (`@p`, `@r`, `@a`, `@e`, `@s`). Entity selectors allow players and command blocks to target entities using player names, UUIDs, or vanilla target selectors (`@p`, `@r`, `@a`, `@e`, `@s`).
In Pumpkin, entity selectors are accessed via [`EntityArgumentType`](file:///home/alex/Documents/Development/Rust/Pumpkin/crates/pumpkin/src/command/argument_types/entity.rs): In Pumpkin, entity selectors are accessed via [`EntityArgumentType`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin/src/command/argument_types/entity.rs):
```rust ```rust
pub enum EntityArgumentType { pub enum EntityArgumentType {
@ -115,7 +115,7 @@ Pumpkin provides specialized argument parsers for Minecraft data types:
## Suggestion Providers & Tab Completion ## Suggestion Providers & Tab Completion
Arguments can supply dynamic tab-completion candidates to connected players using the [`SuggestionProvider`](file:///home/alex/Documents/Development/Rust/Pumpkin/crates/pumpkin-command/src/suggestion/mod.rs) trait: Arguments can supply dynamic tab-completion candidates to connected players using the [`SuggestionProvider`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-command/src/suggestion/mod.rs) trait:
```rust ```rust
use crate::command::context::command_context::CommandContext; use crate::command::context::command_context::CommandContext;

View File

@ -110,7 +110,7 @@ For complex changes—such as worldgen noise router formulas and custom block co
Pumpkin supports multi-version clients through automated protocol remapping powered by **ViaBackwards** / **ViaRewind** mapping tables. Pumpkin supports multi-version clients through automated protocol remapping powered by **ViaBackwards** / **ViaRewind** mapping tables.
### 1. Declare Version in `pumpkin-util` ### 1. Declare Version in `pumpkin-util`
Open `crates/pumpkin-util/src/version.rs` and add the new version to [`JavaMinecraftVersion`](file:///home/alex/Documents/Development/Rust/Pumpkin/crates/pumpkin-util/src/version.rs): Open `crates/pumpkin-util/src/version.rs` and add the new version to [`JavaMinecraftVersion`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/crates/pumpkin-util/src/version.rs):
```rust ```rust
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]

View File

@ -0,0 +1,135 @@
# Quick Start
This guide will help you get started with writing Pumpkin server plugins using the [D programming language](https://dlang.org/).
D plugins for Pumpkin compile to WebAssembly (Wasm) components using the official [`pumpkin-api-d`](https://github.com/Pumpkin-MC/pumpkin-api-d) bindings.
---
## Prerequisites
Before building D plugins for Pumpkin, ensure you have the following installed:
- **[LDC](https://github.com/ldc-developers/ldc)**: Version 1.43 or later (LLVM-based D compiler).
- **`addon-wasi`**: The WASI target package for LDC.
- **[DUB](https://dub.pm/)**: The D package and build tool (usually included with LDC).
---
## 1. Setting Up the Project
Create a new directory for your plugin project and add a `dub.json` configuration file:
```bash
mkdir my-d-plugin
cd my-d-plugin
```
Create `dub.json` in the project root:
```json [dub.json]
{
"name": "my-d-plugin",
"description": "A minimal Pumpkin plugin built with D.",
"license": "proprietary",
"authors": ["You"],
"copyright": "Copyright © 2026, You",
"dependencies": {
"pumpkin-api-d": "~>0.1.0"
},
"targetType": "executable",
"dflags": ["-Xcc=-mexec-model=reactor"],
"buildTypes": {
"debug": {
"buildOptions": ["debugMode", "debugInfo"]
},
"release": {
"buildOptions": ["optimize", "inline"],
"dflags": ["-L-S"]
}
}
}
```
> [!NOTE]
> The flag `-Xcc=-mexec-model=reactor` is required by the WebAssembly linker so that the plugin is treated as a reactor (a component exposing entry points) rather than a command-line program with an exit point.
---
## 2. Writing the Plugin
Create a `source` directory and place your code in `source/app.d`:
```d [source/app.d]
module plugin;
import wit.pumpkin.plugin.plugin;
import wit.common;
import pumpkin.register;
struct MyPlugin {
@GetMetadata PluginMetadata getMetadata()
{
immutable(WitString)[$] authors = [
"You".witList
];
return (immutable PluginMetadata(
name: "my-d-plugin".witList,
version_: "0.1.0".witList,
authors: authors.witList,
description: "An example plugin in D.".witList,
dependencies: WitList!WitString(),
permissions: WitList!WitString()
)).witClone;
}
@OnLoad
Result!(void, WitString) onLoad(Context ctx)
{
scope (exit)
ctx.witDrop; // Incoming resources must be cleaned up after use
log(Level.info, "Hello from D plugin!".witList);
return ok!WitString;
}
}
mixin RegisterPlugin!MyPlugin;
```
### Key Elements:
- **`@GetMetadata`**: Defines plugin information (name, version, authors, description, permissions) requested by Pumpkin when loading the component.
- **`@OnLoad`**: Entry point invoked when Pumpkin initializes the plugin. Ensure incoming context resources (`ctx`) are freed with `ctx.witDrop`.
- **`mixin RegisterPlugin!MyPlugin;`**: Generates the necessary WebAssembly component exports and boilerplate required by Pumpkin's WASM loader.
---
## 3. Building the Plugin
Compile your plugin into a WebAssembly component targeting `wasm32-wasip2`:
```bash
dub build -b release -a wasm32-wasip2
```
This generates `my-d-plugin.wasm` in your project root.
---
## 4. Running Your Plugin
1. Copy the compiled `.wasm` file to your server's `plugins/` directory:
```bash
cp my-d-plugin.wasm /path/to/pumpkin/plugins/
```
2. Start or restart Pumpkin:
```bash
./pumpkin
```
3. Check the server logs to verify your plugin loaded:
```text
[INFO] Hello from D plugin!
```

View File

@ -6,7 +6,7 @@ If you run into any issues please reach out on [our Discord server](https://disc
::: :::
The Pumpkin Plugin API takes inspiration from the Spigot/Bukkit plugin API in many places, The Pumpkin Plugin API takes inspiration from the Spigot/Bukkit plugin API in many places,
so if you have previous experience with these and have experience with Rust, Python, C#, Go, C, or Kotlin development, so if you have previous experience with these and have experience with Rust, Python, C#, Go, C, Kotlin, or D development,
you should have a pretty easy time writing plugins for Pumpkin. :smile: you should have a pretty easy time writing plugins for Pumpkin. :smile:
* [Rust API](https://github.com/Pumpkin-MC/Pumpkin) * [Rust API](https://github.com/Pumpkin-MC/Pumpkin)
@ -15,3 +15,4 @@ you should have a pretty easy time writing plugins for Pumpkin. :smile:
* [Go API](https://github.com/Pumpkin-MC/pumpkin-api-go) * [Go API](https://github.com/Pumpkin-MC/pumpkin-api-go)
* [C API](https://github.com/Pumpkin-MC/pumpkin-api-c) * [C API](https://github.com/Pumpkin-MC/pumpkin-api-c)
* [Kotlin API](https://github.com/Pumpkin-MC/pumpkin-api-kt) * [Kotlin API](https://github.com/Pumpkin-MC/pumpkin-api-kt)
* [D API](https://github.com/Pumpkin-MC/pumpkin-api-d)

View File

@ -7,3 +7,14 @@
**Cause:** This has to do with authentication, and usually with the `prevent_proxy_connections` setting. **Cause:** This has to do with authentication, and usually with the `prevent_proxy_connections` setting.
**Fix:** Disable `prevent_proxy_connections` under `[networking.java.authentication]` in `pumpkin.toml` **Fix:** Disable `prevent_proxy_connections` under `[networking.java.authentication]` in `pumpkin.toml`
2. ## Cannot connect using 0.0.0.0
**Issue:** Players attempting to join a server running on their own machine cannot connect (e.g., encountering a "Connection refused" error) when entering `0.0.0.0` or `0.0.0.0:25565`.
**Cause:** In `pumpkin.toml`, `0.0.0.0` is a wildcard listener address that tells Pumpkin to bind and listen on all local network interfaces. It is not a valid destination address for Minecraft clients to connect to.
**Fix:**
- When connecting from the **same machine**, enter `localhost` or `127.0.0.1` in the Minecraft client.
- When connecting from **another device on the same local network (LAN)**, use the server host's local IP address (e.g., `192.168.x.x`).
- When connecting over the **internet**, other players must connect using your public IP address or domain name (with port `25565` forwarded on your router).

View File

@ -0,0 +1,25 @@
# サーバー管理の概要
Pumpkin サーバー管理者のための**管理者セクション**へようこそ。Pumpkin は Rust で書かれた高性能マルチスレッド Minecraft サーバーであり、最小限のリソース消費で膨大なプレイヤー数をサポートできるように設計されています。
---
## サーバー管理者向けの主な機能
- **高度なマルチスレッド化**: 最新のマルチコアプロセッサ向けにゼロから設計されています。
- **WASM プラグインアーキテクチャ**: JVM のオーバーヘッドなしで、Rust、Python、Kotlin、C#、Go、C による安全でサンドボックス化されたプラグイン実行が可能です。
- **ネイティブなクロスプロキシサポート**: Velocity、BungeeCord、最新のプロキシ転送を標準でサポートしています。
- **TOML ベースの設定**: `pumpkin.toml` および機能ごとの TOML 設定ファイルによる、クリーンで人間が読みやすい設定です。
---
## 管理ガイドとトピック
以下の管理ガイドをご覧ください:
- [Bukkit / Paper / Spigot サーバーからの移行](./migrating-from-bukkit) — サーバー管理、プラグイン、ワールド保存、パフォーマンスに関する主な相違点。
- [サーバー設定](../config/introduction) — `pumpkin.toml` 設定の詳細な解説。
- [プロキシの設定](../config/proxy) — BungeeCord および Velocity プレイヤー転送の設定。
- [コマンドと権限](../config/commands) — ゲーム内のオペレーターコマンドと権限の管理。
- [認証](../config/authentication) — オンラインモードとオフラインモード、Yggdrasil の設定。
- [トラブルシューティングと一般的な問題](../troubleshooting/common_issues) — ポートバインド、メモリ、プラグイン読み込み問題の解決。

View File

@ -0,0 +1,126 @@
# Bukkit / Spigot / Paper から Pumpkin への移行
このガイドでは、サーバーを Bukkit、Spigot、または Paper から Pumpkin に移行する際のアーキテクチャおよび設定の違いについて説明します。
---
## 1. アーキテクチャの違い
| 項目 | Bukkit / Spigot / Paper | Pumpkin |
| :--- | :--- | :--- |
| **実行環境** | Java 仮想マシン (Java 17/21+ が必要) | ネイティブ実行ファイル (Rust コンパイル済み、Java 不要) |
| **起動コマンド** | `java [flags] -jar server.jar` | `./pumpkin` |
| **ティックループ** | 非同期タスクオフロードを伴うシングルスレッド | CPU コア全体にわたるマルチスレッド実行 |
| **プラグイン形式** | Bukkit API 向け Java バイトコード (`.jar`) | WebAssembly (`.wasm`)、または PatchBukkit 経由の `.jar` |
| **プラグイン言語** | Java, Kotlin, Scala | Rust, Python, Kotlin, C#, Go, C |
| **設定ファイル** | `server.properties`, `paper.yml`, `spigot.yml` | `pumpkin.toml` (TOML 形式) |
| **メモリ管理** | JVM ガベージコレクション (GC) | OS ネイティブメモリ割り当て |
---
## 2. プラグインと拡張機能
### WebAssembly プラグイン
Pumpkin の主要なプラグイン形式は WebAssembly (`.wasm`) です:
- **分離性**: プラグインはサンドボックス化された WebAssembly ランタイム内で実行されます。
- **言語サポート**: Rust、Python、Go、C#、C、または Kotlin から WASM へコンパイルできます。
- **カスタムプラグイン**: 独自の Bukkit プラグインを移植する場合は、[開発者向け移行ガイド](../plugin-dev/migrating-from-bukkit/index)を参照してください。
### Bukkit プラグインの互換性: PatchBukkit
既存の Bukkit/Spigot `.jar` プラグインを必要とするサーバー向けに、**PatchBukkit** プロジェクトが互換レイヤーを提供しています:
- **アーキテクチャ**: PatchBukkit は Pumpkin 内に JVM を組み込み、Bukkit API の一部を再実装して、JNI および FFI 経由で Pumpkin に仲介します。
- **プラグインの配置**: 互換性のある `.jar` プラグインは `patchbukkit/patchbukkit-plugins/` に配置します。
- **状況と制限**: PatchBukkit は開発中です。標準的な Bukkit API 呼び出しはサポートされていますが、内部の NMS (`net.minecraft.server`) クラス、CraftBukkit リフレクション、またはバイトコード操作に依存するプラグインは正常に動作しない場合があります。
- **Java の必要性**: PatchBukkit を実行するには、組み込み JVM を実行するためにホスト環境に Java ランタイム (JRE/JDK) が必要です。
---
## 3. 設定とプロパティ
Pumpkin では `server.properties` や YAML の代わりに TOML 設定ファイルを使用します:
| Paper / Spigot (`server.properties`) | Pumpkin (`pumpkin.toml`) |
| :--- | :--- |
| `server-port=25565` | `server_address = "0.0.0.0:25565"` |
| `motd=...` | `motd = "A Pumpkin Server"` |
| `max-players=20` | `max_players = 20` |
| `online-mode=true` | `online_mode = true` |
| `view-distance=10` | `view_distance = 10` |
| `simulation-distance=8` | `simulation_distance = 8` |
---
## 4. ワールドとデータストレージ
- **形式の互換性**: Pumpkin は標準的な Anvil チャンク形式 (`.mca` ファイル) を読み込みます。
- **ディレクトリ配置**: 既存の Paper/Spigot からワールドをコピーする際は、ディメンションディレクトリ (`world`, `world_nether`, `world_the_end`) が Pumpkin の想定する配置と一致していることを確認してください。
- **最新のワールドおよびデータパック形式が必要**: 少なくとも現時点では、Pumpkin は対象の Minecraft バージョンに対応する最新のワールド形式およびデータパック形式のみをサポートしています。古いワールド形式や以前のデータパックバージョンを起動時に自動変換する機能はありません。
- **クライアントでのワールド更新**: 古いバージョンで生成されたワールドを移行する場合は、Pumpkin に読み込む前に更新してください。公式の Minecraft クライアントで直接ワールドをアップグレードできます。対応する最新バージョンのクライアントを起動し、**シングルプレイ**から対象ワールドを選択して**編集** -> **ワールドを最適化**を実行します。または、最新バージョンのバニラサーバーで一度ワールドを起動して保存することでも更新可能です。
- **データパック**: `world/datapacks` 内のすべてのデータパックが、対象バージョンで要求されるパック形式に更新されていることを確認してください。
---
## 5. 起動と JVM フラグ
### Java のインストールは不要
純粋な Pumpkin は単体の自己完結型ネイティブ実行ファイルです。サーバーを実行するために OS やコンテナ内に Java ランタイム (JRE/JDK) をインストールする必要はありません。
### 起動コマンドの比較
Paper や Spigot サーバーでは通常、ヒープ割り当てやガベージコレクション設定を含む JVM 起動スクリプト (Aikar's Flags など) を使用します:
:::code-group
```bash [Paper (JVM)]
# Aikar's Flags を用いた典型的な Paper 起動コマンド:
java -Xms10G -Xmx10G \
-XX:+UseG1GC \
-XX:+ParallelRefProcEnabled \
-XX:MaxGCPauseMillis=200 \
-XX:+UnlockExperimentalVMOptions \
-XX:+DisableExplicitGC \
-XX:+AlwaysPreTouch \
-XX:G1NewSizePercent=30 \
-XX:G1MaxNewSizePercent=40 \
-XX:G1HeapRegionSize=8M \
-XX:G1ReservePercent=20 \
-XX:G1HeapWastePercent=5 \
-XX:G1MixedGCCountTarget=4 \
-XX:InitiatingHeapOccupancyPercent=15 \
-XX:G1MixedGCLiveThresholdPercent=90 \
-XX:G1RSetUpdatingPauseTimePercent=5 \
-XX:SurvivorRatio=32 \
-XX:+PerfDisableSharedMem \
-XX:MaxTenuringThreshold=1 \
-Dusing.aikars.flags=https://mcflags.emc.gs \
-Daikars.new.flags=true \
-jar paper.jar --nogui
```
```bash [Pumpkin (ネイティブ)]
# Linux / macOS:
./pumpkin
# Windows:
./pumpkin.exe
# Docker:
docker run -p 25565:25565 -v ./data:/data pumpkinmc/pumpkin:latest
```
:::
### メモリモデルの違い
- **ガベージコレクターなし**: Pumpkin は Rust で記述されており、コンパイル時の決定論的なメモリ管理 (RAII) を使用します。ランタイムガベージコレクターはなく、GC 一時停止の調整もありません。
- **固定ヒープ割り当てなし**: ネイティブバイナリには `-Xms` や `-Xmx` などのフラグは存在しません。メモリはチャンクやエンティティのロードに応じて動的に確保され、アンロード時に解放されます。
- **JVM フラグは適用不可**: ガベージコレクション戦略、世代サイズ、または JVM 内部パラメータを調整するフラグは不要であり、バイナリに渡すことはできません。
---
## 管理者チェックリスト
1. [ ] 既存のサーバーデータとワールドファイルのバックアップを作成し、ワールドとデータパックが最新形式に更新されていることを確認する (クライアントの「ワールドを最適化」など)。
2. [ ] `server.properties` の設定を `pumpkin.toml` に反映する。
3. [ ] 必要なプラグインを確認し、WebAssembly (`.wasm`) の代替を探すか、[PatchBukkit](#bukkit-プラグインの互換性patchbukkit) でテストする。
4. [ ] プロキシネットワークを使用する場合は、`pumpkin.toml` でプロキシ設定 (`Velocity` / `BungeeCord`) を行う。
5. [ ] 起動スクリプトを更新し、JVM 引数なしで `./pumpkin` を直接実行するように変更する。
6. [ ] サーバーを起動し、接続性とログを確認する。

View File

@ -0,0 +1,83 @@
# Authentication
Pumpkin verifies accounts with Mojang's session servers to ensure players use legitimate accounts. Authentication settings are configured under `[networking.java.authentication]` and `[networking.bedrock.authentication]` in `pumpkin.toml`.
## Java Edition Authentication
:::code-group
```toml [pumpkin.toml]
[networking.java.authentication]
enabled = true
fallbacks = []
profile_by_name_fallbacks = []
profile_by_uuid_fallbacks = []
connect_timeout = 5000
read_timeout = 5000
prevent_proxy_connections = false
[networking.java.authentication.player_profile]
allow_banned_players = false
allowed_actions = ["FORCED_NAME_CHANGE", "USING_BANNED_SKIN"]
[networking.java.authentication.textures]
enabled = true
allowed_url_schemes = ["http", "https"]
allowed_url_domains = [".minecraft.net", ".mojang.com"]
[networking.java.authentication.textures.types]
skin = true
cape = true
elytra = true
```
:::
### Configuration Options
- **`enabled`**: Enables online authentication for Java clients (default: `true`).
- **`url`**: (Optional) Custom authentication URL to verify join requests (e.g., custom auth servers like Drasl). Supports `{username}` and `{server_hash}` parameters.
- **`fallbacks`**: List of fallback authentication URLs contacted if the primary/official session server is unreachable.
- **`profile_by_name_url`**: (Optional) Custom URL template to fetch player profiles by username (`{username}`).
- **`profile_by_name_fallbacks`**: Fallback URLs for looking up player profiles by username.
- **`profile_by_uuid_url`**: (Optional) Custom URL template to fetch player profiles by UUID (`{uuid}`).
- **`profile_by_uuid_fallbacks`**: Fallback URLs for looking up player profiles by UUID.
- **`connect_timeout`**: Connection timeout in milliseconds when contacting authentication servers (default: `5000`).
- **`read_timeout`**: Read timeout in milliseconds when contacting authentication servers (default: `5000`).
- **`prevent_proxy_connections`**: Whether to block connections coming from proxies or VPNs during Mojang authentication (default: `false`).
- **`prevent_proxy_connection_auth_url`**: (Optional) Custom authentication endpoint used specifically when proxy prevention is enabled.
- **`services_url`**: (Optional) Public Minecraft services URL (used for player certificates and keys).
### Player Profile Settings
- **`allow_banned_players`**: Whether to allow players flagged or banned by Mojang to connect (default: `false`).
- **`allowed_actions`**: Profile actions permitted when flagged players connect (e.g. `["FORCED_NAME_CHANGE", "USING_BANNED_SKIN"]`).
### Textures Settings
- **`enabled`**: Enables fetching and validating player skins, capes, and elytra textures (default: `true`).
- **`allowed_url_schemes`**: URL schemes permitted for texture downloads (default: `["http", "https"]`).
- **`allowed_url_domains`**: Domains permitted for texture downloads (default: `[".minecraft.net", ".mojang.com"]`).
- **`types.skin`**: Enable custom player skins (default: `true`).
- **`types.cape`**: Enable player capes (default: `true`).
- **`types.elytra`**: Enable player elytra textures (default: `true`).
## Bedrock Edition Authentication
:::code-group
```toml [pumpkin.toml]
[networking.bedrock.authentication]
enabled = true
connect_timeout = 5000
read_timeout = 5000
```
:::
### Configuration Options
- **`enabled`**: Whether Xbox Live authentication is required for Bedrock clients (default: `true`).
- **`url`**: (Optional) Custom authentication or discovery endpoint URL.
- **`connect_timeout`**: Connection timeout in milliseconds (default: `5000`).
- **`read_timeout`**: Read timeout in milliseconds (default: `5000`).

253
docs/ja_jp/config/basic.md Normal file
View File

@ -0,0 +1,253 @@
# 基本設定
Pumpkin は単一の `pumpkin.toml` ファイルを使用してサーバーのすべての側面を設定します。以下は、利用可能なすべてのセクションとデフォルト値を含む設定ファイルの完全な構造です。
## 完全なデフォルトの `pumpkin.toml`
```toml
seed = "1790155153199293024"
default_difficulty = "Normal"
op_permission_level = 4
allow_nether = true
allow_end = true
hardcore = false
tps = 20.0
default_gamemode = "Survival"
force_gamemode = false
scrub_ips = true
use_favicon = true
default_level_name = "world"
allow_chat_reports = false
white_list = false
enforce_whitelist = false
[logging]
enabled = true
level = "info"
threads = false
thread_ids = false
target = false
color = true
timestamp = true
timestamp_format = "[hour]:[minute]:[second]"
file = "latest.log"
[resource_pack.java]
enabled = false
url = ""
sha1 = ""
prompt_message = ""
force = false
[resource_pack.bedrock]
enabled = false
force = false
packs = []
[world]
lighting = "default"
autosave_ticks = 6000
[world.chunk]
type = "anvil"
write_in_place = false
[world.chunk.compression]
algorithm = "LZ4"
level = 6
[networking.query]
enabled = false
address = "0.0.0.0:25565"
[networking.rcon]
enabled = false
address = "0.0.0.0:25575"
password = ""
max_connections = 10
[networking.rcon.logging]
logged_successfully = true
wrong_password = true
commands = true
quit = true
[networking.proxy]
enabled = false
[networking.proxy.velocity]
enabled = false
secret = ""
[networking.proxy.bungeecord]
enabled = false
secret = ""
[networking.lan_broadcast]
enabled = false
[networking.java]
enabled = true
address = "0.0.0.0:25565"
encryption = true
online_mode = true
max_players = 1000
view_distance = 16
simulation_distance = 10
keep_alive_time = 15
motd = "A blazingly fast Pumpkin server!"
[networking.java.compression]
enabled = true
threshold = 256
level = 4
[networking.java.authentication]
enabled = true
fallbacks = []
profile_by_name_fallbacks = []
profile_by_uuid_fallbacks = []
connect_timeout = 5000
read_timeout = 5000
prevent_proxy_connections = false
[networking.java.authentication.player_profile]
allow_banned_players = false
allowed_actions = ["FORCED_NAME_CHANGE", "USING_BANNED_SKIN"]
[networking.java.authentication.textures]
enabled = true
allowed_url_schemes = ["http", "https"]
allowed_url_domains = [".minecraft.net", ".mojang.com"]
[networking.java.authentication.textures.types]
skin = true
cape = true
elytra = true
[networking.java.packet_limiter]
enabled = true
max_packet_rate = 500.0
burst_capacity = 500.0
kick_message = "Kicked for spamming packets"
[networking.bedrock]
enabled = true
online_mode = true
max_players = 1000
view_distance = 16
simulation_distance = 10
motd = "A blazingly fast Pumpkin server!"
username_prefix = ""
replace_username_spaces = true
chunk_caching = true
[networking.bedrock.compression]
enabled = true
threshold = 256
level = 4
[networking.bedrock.authentication]
enabled = true
connect_timeout = 5000
read_timeout = 5000
[networking.bedrock.nethernet]
enabled = true
address = "0.0.0.0:19132"
identity_key = "nethernet-key.der"
stun_servers = []
[networking.bedrock.packet_limiter]
enabled = true
max_packet_rate = 500.0
burst_capacity = 500.0
kick_message = "Kicked for spamming packets"
[commands]
use_console = true
use_tty = true
log_console = true
broadcast_console_to_ops = true
default_op_level = 0
[commands.overrides]
[chat]
format = "<{DISPLAYNAME}> {MESSAGE}"
[chat.anti_spam]
enabled = true
spam_threshold = 200
message_cost = 20
decay_per_tick = 1
ops_bypass = true
[pvp]
enabled = true
hurt_animation = true
protect_creative = true
knockback = true
swing = true
[server_links]
enabled = true
bug_report = "https://github.com/Pumpkin-MC/Pumpkin/issues"
support = ""
status = ""
feedback = ""
community = ""
website = ""
forums = ""
news = ""
announcements = ""
[server_links.custom]
[player_data]
save_player_data = true
save_player_cron_interval = 300
[fun]
april_fools = true
[recipe]
send_recipes = true
[plugins]
enabled = true
hot_reload = false
ask_permission_confirmation = true
allow_unsigned = true
allowed_permissions = []
blocked_permissions = []
inherit_env = false
loopback_only = false
verify_signatures = true
[plugins.overrides]
[advancement]
save_advancements = true
```
## 設定項目の詳細
### トップレベル設定
- **`seed`**: ワールド生成用のシード値文字列。
- **`default_difficulty`**: デフォルトの難易度 (`"Peaceful"`, `"Easy"`, `"Normal"`, `"Hard"`)。
- **`op_permission_level`**: オペレーターに割り当てられるデフォルトの権限レベル (1〜4)。
- **`allow_nether`**: ネザーディメンションを有効にするかどうか。
- **`allow_end`**: ジ・エンドディメンションを有効にするかどうか。
- **`hardcore`**: ハードコアモードを有効化 (サバイバルでリスポーン不可)。
- **`tps`**: 目標 TPS (ticks per second、デフォルト: `20.0`)。
- **`default_gamemode`**: デフォルトのゲームモード (`"Survival"`, `"Creative"`, `"Adventure"`, `"Spectator"`)。
- **`force_gamemode`**: 参加時にプレイヤーへデフォルトのゲームモードを強制するかどうか。
- **`scrub_ips`**: ログ内のプレイヤー IP アドレスを匿名化するかどうか。
- **`use_favicon`**: サーバーアイコン (`icon.png`) を有効にするかどうか。
- **`favicon_path`**: カスタムサーバーファビコンアイコンへの任意のファイルパス。
- **`default_level_name`**: メインワールドディレクトリの名前 (デフォルト: `"world"`)。
- **`allow_chat_reports`**: 署名付きチャット通報を許可するかどうか。
- **`white_list`**: サーバーホワイトリストを有効にするかどうか。
- **`enforce_whitelist`**: ホワイトリストが有効化された際に、ホワイトリストに登録されていないプレイヤーをキックするかどうか。

View File

@ -0,0 +1,50 @@
# Bedrock と NetherNet
Pumpkin は、NetherNet WebRTC/ICE トランスポートやユーザー名のカスタマイズを含め、Minecraft 統合版 (Bedrock Edition) クライアントをネイティブでサポートしています。
## 設定
:::code-group
```toml [pumpkin.toml]
[networking.bedrock]
enabled = true
online_mode = true
max_players = 1000
view_distance = 16
simulation_distance = 10
motd = "A blazingly fast Pumpkin server!"
username_prefix = ""
replace_username_spaces = true
chunk_caching = true
[networking.bedrock.nethernet]
enabled = true
address = "0.0.0.0:19132"
identity_key = "nethernet-key.der"
stun_servers = []
```
:::
### Bedrock オプション
- **`enabled`**: 統合版 (Bedrock Edition) クライアントからの接続を受け入れるかどうか (デフォルト: `true`)。
- **`online_mode`**: Bedrock プレイヤーに対して Xbox Live 認証を強制するかどうか (デフォルト: `true`)。
- **`max_players`**: 同時接続可能な Bedrock プレイヤーの最大数 (`0` で無制限、デフォルト: `1000`)。
- **`view_distance`**: Bedrock クライアントに送信される最大チャンク描画距離 (デフォルト: `16`)。
- **`simulation_distance`**: Bedrock プレイヤーの最大シミュレーション距離 (デフォルト: `10`)。
- **`motd`**: Bedrock サーバーリストに表示される MOTD (Message of the Day)。
- **`username_prefix`**: Bedrock プレイヤーのゲーマータグの先頭に付加する任意のプレフィックス (例: `"."` または `"*"` など)。クロスプレイサーバーでの Java 版アカウントとの名前衝突を防止します (デフォルト: `""`)。
- **`replace_username_spaces`**: Bedrock ゲーマータグ内のスペースをアンダースコア `_` に自動置換するかどうか。Minecraft のスラッシュコマンドでプレイヤー名を指定できるようにします (デフォルト: `true`)。
- **`chunk_caching`**: ネットワーク帯域を節約するために、クライアント側のチャンク blob キャッシュを有効にするかどうか (デフォルト: `true`)。
### NetherNet トランスポート設定
NetherNet は、Minecraft Bedrock の最新の WebRTC/ICE ネットワーキングトランスポートです:
- **`enabled`**: クライアントが NetherNet を使用して接続できるかどうか (デフォルト: `true`)。
- **`address`**: TCP シグナリングおよび UDP ICE 多重化用のネットワークソケットアドレス (デフォルト: `"0.0.0.0:19132"`)。
- **`external_ip`**: サーバーが NAT 配下でホストされている場合に通知する任意のパブリック IP アドレス。
- **`identity_key`**: クライアントの TOFU (Trust On First Use) のために再起動間でも保持される PKCS#8 P-384 秘密 ID キーファイルへのパス (デフォルト: `"nethernet-key.der"`)。
- **`stun_servers`**: ICE NAT トラバーサル用の STUN サーバー URL の任意のリスト。

39
docs/ja_jp/config/chat.md Normal file
View File

@ -0,0 +1,39 @@
# チャットとスパム対策
Pumpkin では、`pumpkin.toml` 内の `[chat]` セクションで、ゲーム内チャットのフォーマットのカスタマイズや組み込みのスパム対策機能を提供しています。
## 設定
:::code-group
```toml [pumpkin.toml]
[chat]
format = "<{DISPLAYNAME}> {MESSAGE}"
[chat.anti_spam]
enabled = true
spam_threshold = 200
message_cost = 20
decay_per_tick = 1
ops_bypass = true
```
:::
### チャット設定
- **`format`**: チャットメッセージのフォーマット文字列 (デフォルト: `"<{DISPLAYNAME}> {MESSAGE}"`)。
- `{DISPLAYNAME}`: プレイヤーの表示名。
- `{MESSAGE}`: チャットメッセージの本文。
> [!NOTE]
> 安全なチャット通報機能 (`allow_chat_reports = true`) が有効になっている場合、カスタムチャットフォーマットは適用されません。
### スパム対策 (Anti-Spam)
Pumpkin はリーキーバケット (leaky-bucket) 方式のスパムカウンターを実装しており、スパム行為を行うプレイヤーや bot の大量接続からサーバーを保護します:
- **`enabled`**: スパム対策を有効にするかどうか (デフォルト: `true`)。
- **`spam_threshold`**: プレイヤーがキックされるスパムカウンターのしきい値 (単位: ティック、デフォルト: `200` ティック)。
- **`message_cost`**: チャットメッセージまたはコマンドが送信されるたびにプレイヤーのスパムカウンターに追加される量 (デフォルト: `20` ティック)。
- **`decay_per_tick`**: サーバーの 1 ティックごとにプレイヤーのスパムカウンターから減少する量 (デフォルト: `1` ティック)。
- **`ops_bypass`**: サーバーオペレーターがスパムチェックをバイパスできるかどうか (デフォルト: `true`)。

View File

@ -0,0 +1,48 @@
# コマンド
Pumpkin は Minecraft コマンドをサポートしており、`pumpkin.toml` 内でコンソール、TTY、権限の挙動を設定できます。
## 設定
:::code-group
```toml [pumpkin.toml]
[commands]
use_console = true
use_tty = true
log_console = true
broadcast_console_to_ops = true
default_op_level = 0
# 任意のコマンドごとのオーバーライド
[commands.overrides.gamemode]
permission_level = 4
[commands.overrides.tp]
enabled = false
```
:::
### 設定オプション
- **`use_console`**: コンソールからのコマンド入力を受け付けるかどうか。
- **`use_tty`**: 対話型コンソール入力のために TTY サポート (rustyline) を有効にするかどうか。
- **`log_console`**: プレイヤーが実行したコマンドをコンソールに記録するかどうか。
- **`broadcast_console_to_ops`**: コンソールおよび RCON のコマンド出力をオンラインのオペレーターにブロードキャストするかどうか (バニラの `broadcast-console-to-ops` と同等)。
- **`default_op_level`**: 非オペレーターに割り当てられる OP 権限レベル (0〜4、デフォルト: `0`)。
## コマンドオーバーライド
`[commands.overrides.<command>]` を使用して、個々のコマンドの権限をカスタマイズしたり、完全に無効化したりできます。キーには先頭のスラッシュを除いたコマンド名を指定します (例: `gamemode`, `tp`)。
### オーバーライドオプション
- **`enabled`**: コマンドが有効かどうか (デフォルト: `true`)。`false` に設定すると、コマンドは完全に非表示になります。実行できず、`/help` にも表示されず、タブ補完にも現れません。実行を試みたプレイヤーには不明なコマンドのメッセージが表示されます。
- **`permission_level`**: コマンドの実行に必要な最小権限レベル:
- `0`: 誰でも使用可能。
- `2`: 通常のオペレーター (一般的なチートコマンド、例: `/gamemode`)。
- `3`: 管理者 (モデレーションコマンド、例: `/kick`, `/ban`)。
- `4`: サーバーオーナー (サーバー全体の管理、例: `/stop`, `/op`)。
コマンドのデフォルトの権限レベルを維持する場合は、`permission_level` を省略してください。

View File

@ -0,0 +1,54 @@
# Compression
Packet compression reduces bandwidth usage for both Java and Bedrock clients. In `pumpkin.toml`, compression is configured independently for Java and Bedrock networking, as well as world chunk compression.
## Network Compression
### Java Edition
:::code-group
```toml [pumpkin.toml]
[networking.java.compression]
enabled = true
threshold = 256
level = 4
```
:::
### Bedrock Edition
:::code-group
```toml [pumpkin.toml]
[networking.bedrock.compression]
enabled = true
threshold = 256
level = 4
```
:::
### Configuration Options
- **`enabled`**: Enables network packet compression.
- **`threshold`**: Minimum packet payload size (in bytes) required before triggering compression.
- **`level`**: Compression level (0 to 9, where higher values trade CPU time for smaller packet sizes).
## World Chunk Compression
Chunk compression settings control how stored world chunk data is compressed on disk.
:::code-group
```toml [pumpkin.toml]
[world.chunk.compression]
algorithm = "LZ4"
level = 6
```
:::
- **`algorithm`**: Compression algorithm used for chunk data. Supported options are `"LZ4"`, `"ZLib"`, `"GZip"`, and `"Custom"` (default: `"LZ4"`).
- **`level`**: Compression level for chunk data (default: `6`).

View File

@ -0,0 +1,24 @@
### 設定
Pumpkin は強力な設定システムを備えており、外部プラグインに依存することなくサーバーの動作の様々な側面をカスタマイズできます。これにより、サーバー運用の柔軟性と制御性が高まります。
### 設定ファイル
Pumpkin の設定は単一の `pumpkin.toml` ファイルに保存されます。
- `pumpkin.toml`: すべてのサーバー設定、機能、ネットワーキング、動作を一箇所で制御します。
Pumpkin を起動する前に `pumpkin.toml` を作成することも、初回起動後に編集することもできます。
### サーバーバージョン
Pumpkin は最新の Minecraft バージョンをサポートすることを目指しています。他のバージョン向けに Pumpkin サーバーをホストしたい場合は、[ViaProxy](https://github.com/ViaVersion/ViaProxy) というプロジェクトがあります。
- プロキシ接続を許可するように設定してください。
- Pumpkin と ViaProxy には直接の関係はありません。彼らのコードに関する issue を Pumpkin に送信しないでください。さらに、これはサードパーティ製のプロキシであり、Pumpkin はその動作や結果について一切の責任を負いません。
#### 主な特徴
- 広範なカスタマイズ: サーバー設定、プレイヤーの挙動、ワールド生成などを設定可能。
- パフォーマンスの最適化: 設定の調整によるサーバーパフォーマンスの最適化。
- プラグイン不要のカスタマイズ: 追加のプラグインを必要とせず、望み通りの変更を実現。

View File

@ -0,0 +1,22 @@
# LAN Broadcast
Pumpkin can broadcast server announcements on the local network so LAN clients can easily discover and join the server.
## Configuration
:::code-group
```toml [pumpkin.toml]
[networking.lan_broadcast]
enabled = false
# motd = "My Custom LAN Server"
# port = 25565
```
:::
### Configuration Options
- **`enabled`**: Enables or disables broadcasting server presence on the local network (default: `false`).
- **`motd`**: (Optional) Custom one-line Message of the Day shown in LAN client discovery. If omitted, defaults to the server's Java MOTD with newlines removed.
- **`port`**: (Optional) Port advertised in the LAN broadcast. Useful for port forwarding or predictable ports in containerized environments like Docker.

View File

@ -0,0 +1,34 @@
# Logging
Pumpkin provides customizable logging options in `pumpkin.toml`.
## Configuration
:::code-group
```toml [pumpkin.toml]
[logging]
enabled = true
level = "info"
threads = false
thread_ids = false
target = false
color = true
timestamp = true
timestamp_format = "[hour]:[minute]:[second]"
file = "latest.log"
```
:::
### Configuration Options
- **`enabled`**: Master switch to enable or disable server logging (default: `true`).
- **`level`**: Minimum log level for console and file output. Available levels are `"trace"`, `"debug"`, `"info"`, `"warn"`, `"error"`, and `"off"` (default: `"info"`). Can also be overridden with the `RUST_LOG` environment variable.
- **`threads`**: Whether to include thread names in log messages (default: `false`).
- **`thread_ids`**: Whether to include numeric thread IDs in log messages (default: `false`).
- **`target`**: Whether to include module and component targets in log entries (default: `false`).
- **`color`**: Whether to enable ANSI colored log output in the console (default: `true`).
- **`timestamp`**: Whether to include timestamps in log entries (default: `true`).
- **`timestamp_format`**: Timestamp format string using `time` format description syntax (default: `"[hour]:[minute]:[second]"`).
- **`file`**: File path to write log output to (default: `"latest.log"`).

View File

@ -0,0 +1,30 @@
# パケットリミッター
Pumpkin には、パケットフラッド攻撃、スパム攻撃、クライアント側の悪用 (エクスプロイト) からサーバーを保護するための組み込みパケットレートリミッターが搭載されています。パケットレート制限は、Java Edition クライアントと Bedrock Edition クライアントで個別に設定できます。
## 設定
:::code-group
```toml [pumpkin.toml]
[networking.java.packet_limiter]
enabled = true
max_packet_rate = 500.0
burst_capacity = 500.0
kick_message = "Kicked for spamming packets"
[networking.bedrock.packet_limiter]
enabled = true
max_packet_rate = 500.0
burst_capacity = 500.0
kick_message = "Kicked for spamming packets"
```
:::
### 設定オプション
- **`enabled`**: このクライアントエディションでパケットレートリミッターを有効にするかどうか (デフォルト: `true`)。
- **`max_packet_rate`**: クライアント接続ごとに 1 秒あたりに許可される受信パケットの最大数 (デフォルト: `500.0`)。リミッターモジュール自体を無効化せずにレート制限のみを無効にするには、`<= 0.0` に設定します。
- **`burst_capacity`**: クライアントパケットの一時的なスパイクを許容するトークンバケットのバースト許容量 (デフォルト: `500.0`)。
- **`kick_message`**: パケット制限を超過した際にプレイヤーに表示される切断メッセージ (デフォルト: `"Kicked for spamming packets"`)。

View File

@ -0,0 +1,41 @@
# プレイヤーデータとゲームプレイ
永続的なプレイヤーデータの保存、進捗 (Advancements)、レシピの同期、および季節ごとの楽しい機能に関する設定は、`pumpkin.toml` で設定します。
## 設定
:::code-group
```toml [pumpkin.toml]
[player_data]
save_player_data = true
save_player_cron_interval = 300
[advancement]
save_advancements = true
[recipe]
send_recipes = true
[fun]
april_fools = true
```
:::
### プレイヤーデータ
- **`save_player_data`**: 永続的なプレイヤーデータ (インベントリ、位置、体力など) をディスクに保存するかどうか (デフォルト: `true`)。
- **`save_player_cron_interval`**: オンラインプレイヤーデータの自動定期保存を行う間隔 (秒単位、デフォルト: `300` 秒 / 5 分)。
### 進捗 (Advancements)
- **`save_advancements`**: プレイヤーの進捗状況を追跡し、ディスクに保存するかどうか (デフォルト: `true`)。
### レシピ
- **`send_recipes`**: クラフトや精錬のレシピを接続中のクライアントと同期し、クライアント側のレシピ本を有効にするかどうか (デフォルト: `true`)。
### お楽しみ機能
- **`april_fools`**: エイプリルフールのイースターエッグや季節限定の楽しい機能を有効にするかどうか (デフォルト: `true`)。

View File

@ -0,0 +1,59 @@
# プラグイン
Pumpkin は、ケーパビリティベースのセキュリティを備えた WebAssembly (WASM) プラグインランタイムを提供します。プラグインの挙動、署名検証、権限は `pumpkin.toml` 内の `[plugins]` で設定します。
## 設定
:::code-group
```toml [pumpkin.toml]
[plugins]
enabled = true
hot_reload = false
ask_permission_confirmation = true
allow_unsigned = true
allowed_permissions = []
blocked_permissions = []
inherit_env = false
loopback_only = false
verify_signatures = true
# 任意のプラグインごとのオーバーライド
[plugins.overrides.my_plugin]
enabled = true
allow_unsigned = true
max_memory_mb = 128
allowed_permissions = ["fs:read:data"]
blocked_permissions = ["network:outbound"]
loopback_only = true
[plugins.overrides.my_plugin.environment]
API_KEY = "example_secret"
```
:::
### グローバルプラグイン設定
- **`enabled`**: プラグインランタイムを有効または無効にするマスタースイッチ (デフォルト: `true`)。
- **`hot_reload`**: `plugins/` ディレクトリを監視し、実行時に変更されたプラグインを自動的に再読み込みするかどうか (デフォルト: `false`)。
- **`ask_permission_confirmation`**: プラグインが未承認のケーパビリティ/権限を要求した際に、サーバーコンソールで確認を求めるかどうか (デフォルト: `true`)。
- **`allow_unsigned`**: 署名されていない WASM プラグインの読み込みを許可するかどうか (デフォルト: `true`)。
- **`allowed_permissions`**: すべてのプラグインに対してグローバルに事前承認され、対話型コンソールプロンプトをバイパスする権限のリスト (デフォルト: `[]`)。
- **`blocked_permissions`**: すべてのプラグインに対してグローバルに拒否される権限のリスト (デフォルト: `[]`)。
- **`inherit_env`**: ホストの環境変数をデフォルトでプラグインの WASI サンドボックスに継承するかどうか (デフォルト: `false`)。
- **`loopback_only`**: プラグインからのアウトバウンドネットワーク接続を `127.0.0.1` / localhost のみに制限するかどうか (デフォルト: `false`)。
- **`max_memory_mb`**: (任意) プラグインインスタンスごとのグローバル最大メモリ制限 (MB 単位)。
- **`verify_signatures`**: 読み込み前に Pumpkin が WASM プラグインの暗号署名を検証するかどうか (デフォルト: `true`)。
### プラグインごとのオーバーライド
`[plugins.overrides.<plugin_name>]` を使用して、特定のプラグインの権限や環境変数を細かく調整できます:
- **`enabled`**: この特定のプラグインを有効または無効にする (デフォルト: `true`)。
- **`allow_unsigned`**: この特定のプラグインが署名なしで実行できるかどうかをオーバーライド (`true`/`false`)。
- **`max_memory_mb`**: このプラグイン専用に割り当てられる最大メモリ制限 (MB 単位)。
- **`allowed_permissions`**: このプラグインに対して事前承認された権限。
- **`blocked_permissions`**: このプラグインに対して明示的にブロックされた権限。
- **`loopback_only`**: このプラグインのループバックネットワーク制限をオーバーライド。
- **`environment`**: プラグインの WASI 環境に直接渡されるカスタム環境変数のテーブル。

View File

@ -0,0 +1,30 @@
# プロキシ
Pumpkin はネットワークサーバー構成向けのプロキシプロトコルをサポートしています。Velocity および BungeeCord のサポートは、`pumpkin.toml` 内の `[networking.proxy]` で設定します。
## 設定
:::code-group
```toml [pumpkin.toml]
[networking.proxy]
enabled = false
[networking.proxy.velocity]
enabled = false
secret = ""
[networking.proxy.bungeecord]
enabled = false
secret = ""
```
:::
### 設定オプション
- **`[networking.proxy].enabled`**: プロキシサポートを有効にするマスタースイッチ。
- **`[networking.proxy.velocity].enabled`**: Velocity の modern 転送プロトコルを有効化。
- **`[networking.proxy.velocity].secret`**: Velocity プロキシ設定と一致する転送シークレット。
- **`[networking.proxy.bungeecord].enabled`**: BungeeCord のプレイヤー情報転送プロトコルを有効化。
- **`[networking.proxy.bungeecord].secret`**: BungeeGuard (`bungeeguard-token`) を介して BungeeCord プロキシからの接続を認証するための任意の共有シークレット。設定すると、受信接続はこのトークンを提供する必要があり、プレイヤーがプロキシをバイパスして直接接続するのを防ぎます。

26
docs/ja_jp/config/pvp.md Normal file
View File

@ -0,0 +1,26 @@
# PVP
PVP (プレイヤー対プレイヤーの戦闘) の挙動と戦闘メカニクスは、`pumpkin.toml` 内の `[pvp]` で設定します。
## 設定
:::code-group
```toml [pumpkin.toml]
[pvp]
enabled = true
hurt_animation = true
protect_creative = true
knockback = true
swing = true
```
:::
### 設定オプション
- **`enabled`**: プレイヤー同士の戦闘 (PVP) を有効化。
- **`hurt_animation`**: 攻撃を受けた際の被ダメージアニメーションを表示。
- **`protect_creative`**: クリエイティブモードのプレイヤーが PVP ダメージを受けるのを防止。
- **`knockback`**: ダメージを受けた際のノックバック効果を有効化。
- **`swing`**: 攻撃時の腕を振るアニメーションを有効化。

View File

@ -0,0 +1,20 @@
# Query
The Query protocol allows external applications (such as server lists or monitoring systems) to request status details from Pumpkin.
## Configuration
:::code-group
```toml [pumpkin.toml]
[networking.query]
enabled = false
address = "0.0.0.0:25565"
```
:::
### Configuration Options
- **`enabled`**: Enables or disables the GS4 Query listener (default: `false`).
- **`address`**: Network address and port to bind the Query listener to (default: `"0.0.0.0:25565"`).

37
docs/ja_jp/config/rcon.md Normal file
View File

@ -0,0 +1,37 @@
# RCON
RCON を使用すると、ネットワーク接続を介して Pumpkin サーバーをリモート管理できます。`pumpkin.toml` では、設定は `[networking.rcon]` の下に配置されます。
## 設定
:::code-group
```toml [pumpkin.toml]
[networking.rcon]
enabled = false
address = "0.0.0.0:25575"
password = ""
max_connections = 10
[networking.rcon.logging]
logged_successfully = true
wrong_password = true
commands = true
quit = true
```
:::
### RCON 設定
- **`enabled`**: RCON サービスを有効にするマスタースイッチ。
- **`address`**: RCON サーバーをバインドする IP アドレスとポート。
- **`password`**: RCON クライアントの認証に必要なパスワード。
- **`max_connections`**: 許可される RCON クライアントの最大同時接続数。
### RCON ログ設定
- **`logged_successfully`**: クライアントの認証成功イベントをログに記録するかどうか。
- **`wrong_password`**: 認証失敗 (パスワード間違い) の試行をログに記録するかどうか。
- **`commands`**: RCON 経由で実行されたコマンドをログに記録するかどうか。
- **`quit`**: クライアントの切断イベントをログに記録するかどうか。

View File

@ -0,0 +1,62 @@
# Resource Pack
Pumpkin supports serving resource packs to Java and Bedrock clients. Resource pack options are configured under `[resource_pack.java]` and `[resource_pack.bedrock]` in `pumpkin.toml`.
## Java Resource Pack
:::code-group
```toml [pumpkin.toml]
[resource_pack.java]
enabled = false
url = ""
sha1 = ""
prompt_message = ""
force = false
```
:::
### Options
- **`enabled`**: Enable serving resource pack to Java clients.
- **`url`**: Direct download URL for the Java resource pack zip.
- **`sha1`**: SHA-1 checksum of the resource pack zip file.
- **`prompt_message`**: Message shown to players when prompted to download.
- **`force`**: Disconnect players who decline the resource pack download.
## Bedrock Resource Pack
:::code-group
```toml [pumpkin.toml]
[resource_pack.bedrock]
enabled = false
force = false
packs = [
# { uuid = "00000000-0000-0000-0000-000000000000", version = "1.0.0", size = 1048576, download_url = "https://example.com/pack.mcpack" }
]
```
:::
### Options
- **`enabled`**: Enable resource packs for Bedrock clients.
- **`force`**: Force Bedrock clients to download required packs before joining.
- **`packs`**: Array of Bedrock resource pack definitions.
### Bedrock Pack Fields
Each pack in the `packs` array accepts the following properties:
- **`uuid`**: (Required) Unique identifier (UUID) for the Bedrock pack matching its `manifest.json`.
- **`version`**: (Required) Version string of the pack (e.g. `"1.0.0"`).
- **`size`**: (Required) File size of the pack archive in bytes.
- **`download_url`**: (Required) Direct download URL for the `.mcpack` or archive file.
- **`content_key`**: (Optional) Decryption key for encrypted marketplace/custom packs.
- **`sub_pack_name`**: (Optional) Sub-pack name within the pack to activate.
- **`content_id`**: (Optional) Content identifier string.
- **`has_scripts`**: (Optional) Whether the pack contains client scripts (`true`/`false`, default: `false`).
- **`addon_pack`**: (Optional) Whether the pack is marked as an addon pack (default: `false`).
- **`rtx_enabled`**: (Optional) Whether ray tracing / RTX features are enabled for the pack (default: `false`).

View File

@ -0,0 +1,50 @@
# サーバーリンク (Server Links)
Minecraft クライアント (1.21 以降) では、ポーズメニューやゲームメニュー内にクリック可能なサーバーリンクを表示できます。標準リンクおよびカスタムサーバーリンクは、`pumpkin.toml` 内の `[server_links]` で設定します。
## 設定
:::code-group
```toml [pumpkin.toml]
[server_links]
enabled = true
bug_report = "https://github.com/Pumpkin-MC/Pumpkin/issues"
support = ""
status = ""
feedback = ""
community = ""
website = ""
forums = ""
news = ""
announcements = ""
[server_links.custom]
# "Store" = "https://store.example.com"
# "Discord" = "https://discord.gg/example"
```
:::
### 設定オプション
- **`enabled`**: 接続中のクライアントへのサーバーリンクの配信を有効にするマスタースイッチ (デフォルト: `true`)。
- **`bug_report`**: サーバーまたはプロジェクトのバグトラッカーへのリンク (デフォルト: `"https://github.com/Pumpkin-MC/Pumpkin/issues"`)。
- **`support`**: テクニカルサポートまたはヘルプデスクへのリンク。
- **`status`**: サーバーの稼働状況 / ステータスページへのリンク。
- **`feedback`**: プレイヤーのフィードバックまたは提案ページへのリンク。
- **`community`**: コミュニティフォーラムまたはグループへのリンク。
- **`website`**: 公式ウェブサイトへのリンク。
- **`forums`**: ディスカッションフォーラムへのリンク。
- **`news`**: サーバーブログまたはニュースページへのリンク。
- **`announcements`**: お知らせページへのリンク。
### カスタムリンク
`[server_links.custom]` の下に、クライアントメニューに表示する任意のキーと値のリンクを定義できます:
```toml
[server_links.custom]
"Store" = "https://store.example.com"
"Discord" = "https://discord.gg/example"
```

View File

@ -0,0 +1,41 @@
# ワールド
Pumpkin では、`pumpkin.toml` 内の `[world]` セクションで、ワールドのストレージ形式、自動保存の間隔、ライティングモードを細かく調整できます。
## 設定
:::code-group
```toml [pumpkin.toml]
[world]
lighting = "default"
autosave_ticks = 6000
[world.chunk]
type = "anvil"
write_in_place = false
[world.chunk.compression]
algorithm = "LZ4"
level = 6
```
:::
### ワールド設定
- **`lighting`**: ライティングエンジンの光伝搬計算モード。
- `"default"`: 標準のバニラ Minecraft の光伝搬。
- `"full"`: 影がなく、すべての場所が最大の空の明るさになります。
- `"dark"`: すべての場所が完全に真っ暗になります (光レベル 0)。
- **`autosave_ticks`**: ワールドが自動保存されるサーバーティックの間隔 (デフォルト: `6000`、20 TPS で 5 分に相当)。`0` に設定するとワールドの自動保存が無効になります。
### チャンクストレージ設定
- **`type`**: 使用するチャンクストレージ形式:
- `"anvil"`: 標準の Minecraft Anvil リージョンファイル形式 (`.mca`)。
- `"linear"`: ディスク使用量を抑えるために高速圧縮を使用する Linear リージョンストレージ形式。
- `"pump"`: Pumpkin ネイティブの最適化されたワールド形式。
- **`write_in_place`**: 空きチャンクを再割り当てするのではなく、既存のリージョンファイル内の元の位置にチャンクを上書きするかどうか (デフォルト: `false`)。
- **`compression.algorithm`**: チャンクデータに使用される圧縮アルゴリズム (`"LZ4"`, `"ZLib"`, `"GZip"`, `"Custom"`)。
- **`compression.level`**: チャンクストレージの圧縮レベル (デフォルト: `6`)。

View File

@ -0,0 +1,139 @@
# Pumpkin Architecture & Crates
Pumpkin is organized as a modular Cargo workspace composed of specialized crates. Each crate has distinct responsibilities, strictly defined boundaries, and minimal cross-dependencies.
This architecture enables high parallel compilation speeds, isolated testing, zero-cost data sharing, and clean separation between network protocols, game logic, and world management.
---
## Workspace Crate Overview
### Workspace Architecture at a Glance
| Layer | Crates | Responsibilities |
| :--- | :--- | :--- |
| **Core Runtime** | `pumpkin` | Game loop, world ticking, player sessions, entity management, and event loops |
| **Networking & Protocols** | `pumpkin-protocol`, `pumpkin-auth`, `pumpkin-nbt` | Java/Bedrock packet serialization, Yggdrasil & Xbox Live authentication, SNBT |
| **World & Gameplay** | `pumpkin-world`, `pumpkin-inventory`, `pumpkin-command` | Region I/O (Anvil/Linear), terrain generation, block ticking, containers, Brigadier tree |
| **Extensibility** | `pumpkin-plugin-runtime`, `pumpkin-host-bindings`, `pumpkin-plugin-api`, `pumpkin-plugin-wit` | WebAssembly plugin execution via Wasmtime, WIT host APIs, native and WASM loaders |
| **Foundations** | `pumpkin-data`, `pumpkin-config`, `pumpkin-util` | Code-generated registries, typed configuration files, mathematical vectors, permissions |
---
## Detailed Crate Breakdown
### 1. `pumpkin` (Core Server)
- **Path**: `crates/pumpkin`
- **Purpose**: The main server binary and centralized orchestration engine.
- **Responsibilities**:
- Initializes configuration, logging (`tracing`), and telemetry.
- Spawns Tokio network listeners for Minecraft: Java Edition, Bedrock Edition, RCON, Query, and LAN broadcast.
- Manages the server tick loop (`Server::tick`), coordinating world updates, player actions, entity movements, and chunk broadcasting.
- Dispatches incoming client packets through `crates/pumpkin/src/net/java/` and `net/bedrock/`.
- Integrates the plugin manager, firing event handlers before and after packet processing.
### 2. `pumpkin-protocol` (Network Protocol)
- **Path**: `crates/pumpkin-protocol`
- **Purpose**: High-speed network wire format serialization and deserialization for Minecraft Java and Bedrock editions.
- **Responsibilities**:
- Implements the `ClientPacket` (serialization) and `ServerPacket` (deserialization) traits.
- Handles protocol primitives: `VarInt`, `VarLong`, UUIDs, NBT compounds, and string codecs.
- Implements packets across all states: `Handshake`, `Status`, `Login`, `Config`, and `Play`.
- Provides packet compression (ZLib/Fast compression) and packet encryption (AES-128/CFB8).
- Encapsulates RCON and GameSpy4 Query protocols.
### 3. `pumpkin-world` (World & Chunks)
- **Path**: `crates/pumpkin-world`
- **Purpose**: World loading, saving, terrain generation, and chunk management.
- **Responsibilities**:
- Supports multiple chunk storage formats:
- **Vanilla Anvil (`.mca`)**: Reading and writing standard region files.
- **Linear (`.linear`)**: High-efficiency zstd-compressed region format saving 50–95% disk space.
- **Slime (`.slime`)**: Single-file world format.
- **Pump**: Native Pumpkin chunk storage format.
- Implements world generation pipelines: Perlin noise heightmaps, 3D noise routers, biome climate parameters, placed features, carvers, and superflat terrain.
- Manages block lighting and sky lighting propagation.
- Coordinates chunk loading, unloading, and streaming via cylindrical chunk iterators.
### 4. `pumpkin-data` (Minecraft Datasets & Registries)
- **Path**: `crates/pumpkin-data`
- **Purpose**: Compile-time static registries and data tables generated directly from vanilla Minecraft assets and reports.
- **Responsibilities**:
- Contains complete ID mappings, properties, and definitions for blocks, items, biomes, entities, sounds, particles, enchantments, and recipes.
- Packet ID lookups across multiple Minecraft protocol versions.
- Zero-cost lookup tables generated by `tools/pumpkin-codegen`.
### 5. `pumpkin-config` (Configuration Management)
- **Path**: `crates/pumpkin-config`
- **Purpose**: TOML configuration parsing, serialization, and validation.
- **Responsibilities**:
- Loads and writes `pumpkin.toml`.
- Configures server ports, compression thresholds, proxy modes, resource packs, logging levels, world settings, and Bedrock integration.
- Provides safe defaults and schema validations.
### 6. `pumpkin-inventory` (Inventory & Containers)
- **Path**: `crates/pumpkin-inventory`
- **Purpose**: Server-side container window handlers and inventory mechanics.
- **Responsibilities**:
- Manages player inventory, chest containers, crafting tables, furnaces, and villager trading screens.
- Validates client slot clicks, drag operations, item stacking, and item splitting.
- Coordinates window packet synchronization to ensure client inventory fidelity.
### 7. `pumpkin-command` (Command Dispatcher)
- **Path**: `crates/pumpkin-command`
- **Purpose**: Brigadier-inspired hierarchical command tree dispatcher and parser.
- **Responsibilities**:
- Constructs modular command trees with typed arguments (`Integer`, `Float`, `Entity`, `BlockPos`, etc.).
- Executes permission-checked commands.
- Provides real-time autocompletion suggestions sent to connected clients.
### 8. `pumpkin-auth` (Authentication & Session Verification)
- **Path**: `crates/pumpkin-auth`
- **Purpose**: Cryptographic authentication and player identity verification.
- **Responsibilities**:
- Validates client sessions with Mojang's Yggdrasil authentication servers.
- Handles RSA keypair generation and shared secret exchange during the Login state.
- Supports offline-mode UUID generation and custom authentication endpoints.
- Implements proxy forwarding protocols: [BungeeCord](https://github.com/SpigotMC/BungeeCord), [BungeeGuard](https://github.com/lucko/BungeeGuard), and [Velocity](https://github.com/PaperMC/Velocity) modern forwarding with HMAC-SHA256 signatures.
### 9. `pumpkin-nbt` (Named Binary Tag Codec)
- **Path**: `crates/pumpkin-nbt`
- **Purpose**: High-throughput binary NBT parser and serializer.
- **Responsibilities**:
- Parses and encodes all standard NBT tag types (`Byte`, `Short`, `Int`, `Long`, `Float`, `Double`, `ByteArray`, `String`, `List`, `Compound`, `IntArray`, `LongArray`).
- Supports compression layers: Gzip, Zlib, and uncompressed Network NBT.
### 10. `pumpkin-plugin-*` (Extensibility Infrastructure)
- **Paths**:
- `crates/pumpkin-plugin-api`: The Rust developer SDK for compiling native plugins.
- `crates/pumpkin-plugin-runtime`: Wasmtime-powered WebAssembly execution host.
- `crates/pumpkin-plugin-wit`: WebAssembly Interface Type (WIT) specifications.
- `crates/pumpkin-host-bindings`: Auto-generated host bindings connecting Wasmtime and the server core.
- **Purpose**: Enables safe, polyglot plugin execution (Rust, Python, C#, C, Go, Kotlin) with sandboxed memory and near-native performance.
### 11. `pumpkin-util` & `pumpkin-macros` (Foundations)
- **Paths**: `crates/pumpkin-util`, `crates/pumpkin-macros`, `crates/pumpkin-api-macros`
- **Purpose**: Foundational types, shared algorithms, and procedural macros.
- **Responsibilities**:
- Mathematical utilities: `Vector2`, `Vector3`, `BoundingBox`, and angle conversions.
- Text and chat formatting: `TextComponent` and JSON component serialization.
- Procedural macros such as `#[java_packet(...)]` that bind packet structs to protocol IDs and packet traits.
### 12. `tools/` (Developer Tooling)
- **`tools/pumpkin-codegen`**: Automated code generator that parses Minecraft version jars, data reports, and asset archives to emit Rust source files into `pumpkin-data`.
- **`tools/pumpkin-fuzzer`**: Fuzz testing suites for network packet parsers, NBT readers, and region file decoders to identify potential crash vectors or memory anomalies.
---
## Concurrency & Threading Model
| Component | Runtime / Pool | Primary Workload | Communication Mechanism |
| :--- | :--- | :--- | :--- |
| **Network & Socket I/O** | Tokio Async Runtime | TCP packet reads, Bedrock UDP packets, framing, session handshakes | Async tasks (`tokio::spawn`), non-blocking reactors |
| **Heavy Compute** | Rayon Thread Pool | Terrain generation, noise routers, light propagation, chunk compression | Worker threads via crossbeam / Rayon iterators |
| **Inter-Thread Bridge** | Tokio Channels | Dispatching completed chunks and encoded packets back to network tasks | Non-blocking `tokio::sync::mpsc` channels |
Pumpkin strictly adheres to this separation of concerns:
- **I/O Bound**: Managed on Tokio asynchronous tasks.
- **CPU Bound**: Managed on Rayon thread pools.
- **Communication**: Coordinated via cross-thread channels (`tokio::sync::mpsc`) without ever blocking the Tokio reactor loop.

View File

@ -0,0 +1,182 @@
# Adding a Block Behavior
This guide walks through implementing interactive behavior for a block in Pumpkin.
---
## When Is a Behavior Needed?
- **Non-Interactive Blocks** (e.g., stone, dirt, terracotta): Do **not** require any custom Rust code. Their breaking speeds, hardness, and placement properties are automatically derived from `pumpkin-data`.
- **Interactive or Functional Blocks** (e.g., doors, chests, levers, crops, campfires, TNT): Require an implementation of the `BlockBehaviour` trait to respond to player clicks, redstone signals, physics steps, or timer ticks.
---
## Step 1: Create the Behavior Struct
Create a new file under `crates/pumpkin/src/block/blocks/<category>/<block_name>.rs` (or directly in `crates/pumpkin/src/block/blocks/`).
Use the `#[pumpkin_block(...)]` macro to associate your behavior struct with one or more vanilla block identifiers:
```rust
use std::sync::Arc;
use pumpkin_data::Block;
use pumpkin_data::block_properties::{DoorLikeProperties, Facing};
use pumpkin_macros::pumpkin_block;
use pumpkin_util::math::position::BlockPos;
use crate::block::registry::BlockActionResult;
use crate::block::{
BlockBehaviour, NormalUseArgs, OnNeighborUpdateArgs, PlacedArgs, UseWithItemArgs,
};
use crate::world::World;
/// Associates this behavior struct with one or multiple block IDs.
#[pumpkin_block([
"minecraft:oak_door",
"minecraft:iron_door",
"minecraft:spruce_door",
"minecraft:birch_door"
])]
pub struct DoorBlock;
impl BlockBehaviour for DoorBlock {
fn normal_use(&self, args: NormalUseArgs<'_>) -> BlockActionResult {
let state_id = args.world.get_block_state(args.location).await;
// Iron doors require redstone power and cannot be opened manually by hand
if args.block.id == pumpkin_data::Block::IRON_DOOR.id {
return BlockActionResult::Pass;
}
// Toggle open state
let is_open = DoorLikeProperties::open(state_id);
let new_state = DoorLikeProperties::with_open(state_id, !is_open);
args.world.set_block_state(args.location, new_state).await;
BlockActionResult::Consume
}
fn on_neighbor_update(&self, args: OnNeighborUpdateArgs<'_>) {
// Handle neighbor redstone signals or support block destruction
}
}
```
---
## Step 2: `BlockBehaviour` Hook Reference
The `BlockBehaviour` trait exposes lifecycle hooks modeled on vanilla mechanics:
### Player & Item Interaction Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `normal_use` | `(&self, args: NormalUseArgs<'_>) -> BlockActionResult` | Triggered when right-clicking the block with an empty hand. |
| `use_with_item` | `(&self, args: UseWithItemArgs<'_>) -> BlockActionResult` | Triggered when right-clicking the block while holding an item. |
| `get_screen_handler_factory` | `(&self, args: GetScreenHandlerFactoryArgs<'_>) -> Option<Box<dyn ScreenHandlerFactory>>` | Returns an inventory container factory to open a UI screen (e.g., Chests, Crafting Tables). |
### World Lifecycle & Physics Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `placed` | `(&self, args: PlacedArgs<'_>)` | Triggered immediately after the block is placed in the world. |
| `broken` | `(&self, args: BrokenArgs<'_>)` | Triggered when broken by a player or game mechanics. |
| `on_entity_collision` | `(&self, args: OnEntityCollisionArgs<'_>)` | Triggered when an entity walks inside, steps on, or falls into the block. |
| `on_neighbor_update` | `(&self, args: OnNeighborUpdateArgs<'_>)` | Triggered when an adjacent block state updates or is destroyed. |
| `on_projectile_hit` | `(&self, args: OnProjectileHitArgs<'_>)` | Triggered when an arrow, snowball, or projectile strikes the block. |
### Redstone & Power Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `emits_redstone_power` | `(&self, state_id: BlockStateId) -> bool` | Declares whether the block emits redstone power to neighbors. |
| `get_weak_redstone_power` | `(&self, ...) -> u8` | Returns emitted weak power level (0–15). |
| `get_strong_redstone_power` | `(&self, ...) -> u8` | Returns emitted strong direct power level (0–15). |
### Foliage & Bonemeal Hooks
| Hook | Signature | Description |
| :--- | :--- | :--- |
| `is_valid_bonemeal_target` | `(&self, args: BonemealArgs<'_>) -> bool` | Checks if bone meal can be applied (e.g., crop not fully grown). |
| `is_bonemeal_success` | `(&self, args: BonemealArgs<'_>) -> bool` | Evaluates random chance roll for bone meal success. |
| `perform_bonemeal` | `(&self, args: BonemealArgs<'_>)` | Advances growth stages or spawns adjacent flora. |
---
## Step 3: Modifying Block States
All block properties are strongly typed in `pumpkin_data::block_properties`:
```rust
use pumpkin_data::block_properties::{BedLikeProperties, Part};
// 1. Read typed properties from the numeric BlockStateId
let part = BedLikeProperties::part(state_id); // Part::Head or Part::Foot
let is_occupied = BedLikeProperties::occupied(state_id);
// 2. Generate a new BlockStateId with updated properties
let updated_state = BedLikeProperties::with_occupied(state_id, true);
// 3. Commit the updated state to the world
world.set_block_state(pos, updated_state).await;
```
---
## Step 4: Adding a Block Entity (Tile Entity)
If your block needs to store persistent custom state (inventories, custom text, timers):
1. Create a block entity struct in `crates/pumpkin/src/block/entities/`:
```rust
use pumpkin_util::math::position::BlockPos;
use crate::block::entities::BlockEntity;
pub struct CustomBlockEntity {
pub pos: BlockPos,
pub custom_counter: u32,
}
impl BlockEntity for CustomBlockEntity {
fn to_nbt(&self) -> pumpkin_nbt::compound::NbtCompound {
let mut compound = pumpkin_nbt::compound::NbtCompound::new();
compound.put_int("Counter", self.custom_counter as i32);
compound
}
fn from_nbt(&mut self, tag: &pumpkin_nbt::compound::NbtCompound) {
if let Some(val) = tag.get_int("Counter") {
self.custom_counter = val as u32;
}
}
fn tick(&mut self, world: &std::sync::Arc<crate::world::World>, pos: &BlockPos) {
// Periodic logic per game tick
}
}
```
2. Link the block entity in your `BlockBehaviour`:
```rust
impl BlockBehaviour for CustomBlock {
fn create_block_entity(&self, pos: BlockPos) -> Option<Arc<Mutex<dyn BlockEntity>>> {
Some(Arc::new(Mutex::new(CustomBlockEntity::new(pos))))
}
}
```
---
## Step 5: Registering the Block
1. Export your module in `crates/pumpkin/src/block/blocks/mod.rs`:
```rust
pub mod doors;
```
2. Register the behavior struct in `crates/pumpkin/src/block/registry.rs`:
```rust
manager.register(DoorBlock);
```
At startup, `manager.register` automatically reads the block IDs declared in `#[pumpkin_block(...)]` and routes interactions to your implementation.

Some files were not shown because too many files have changed in this diff Show More