Better formatting

This commit is contained in:
Alexander Medvedev 2025-08-11 22:42:58 +02:00
parent 77e999bb8a
commit d219a313bc
51 changed files with 579 additions and 234 deletions

View File

@ -1,4 +1,5 @@
### Development # Development
1. Install [Bun](https://bun.sh) 1. Install [Bun](https://bun.sh)
2. Download dependencies by running `bun install` 2. Download dependencies by running `bun install`
3. Edit the documentation 3. Edit the documentation

View File

@ -164,7 +164,7 @@
"@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.1", "", {}, "sha512-fTIQwLF+Qhuws31iw7Ncl1R3HUDtGwIipiJ9iU+UsDUwMhegFcQKQHd51nZjb7CArq0MvON8rbgCGQYWHUKAdg=="], "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.1", "", {}, "sha512-fTIQwLF+Qhuws31iw7Ncl1R3HUDtGwIipiJ9iU+UsDUwMhegFcQKQHd51nZjb7CArq0MvON8rbgCGQYWHUKAdg=="],
"@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="], "@types/bun": ["@types/bun@1.2.20", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="],
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="], "@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
@ -212,7 +212,7 @@
"@vue/server-renderer": ["@vue/server-renderer@3.5.18", "", { "dependencies": { "@vue/compiler-ssr": "3.5.18", "@vue/shared": "3.5.18" }, "peerDependencies": { "vue": "3.5.18" } }, "sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA=="], "@vue/server-renderer": ["@vue/server-renderer@3.5.18", "", { "dependencies": { "@vue/compiler-ssr": "3.5.18", "@vue/shared": "3.5.18" }, "peerDependencies": { "vue": "3.5.18" } }, "sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA=="],
"@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], "@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vueuse/core": ["@vueuse/core@12.5.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.20", "@vueuse/metadata": "12.5.0", "@vueuse/shared": "12.5.0", "vue": "^3.5.13" } }, "sha512-GVyH1iYqNANwcahAx8JBm6awaNgvR/SwZ1fjr10b8l1HIgDp82ngNbfzJUgOgWEoxjL+URAggnlilAEXwCOZtg=="], "@vueuse/core": ["@vueuse/core@12.5.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.20", "@vueuse/metadata": "12.5.0", "@vueuse/shared": "12.5.0", "vue": "^3.5.13" } }, "sha512-GVyH1iYqNANwcahAx8JBm6awaNgvR/SwZ1fjr10b8l1HIgDp82ngNbfzJUgOgWEoxjL+URAggnlilAEXwCOZtg=="],
@ -226,7 +226,7 @@
"birpc": ["birpc@0.2.19", "", {}, "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ=="], "birpc": ["birpc@0.2.19", "", {}, "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ=="],
"bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="], "bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
@ -346,40 +346,20 @@
"vite": ["vite@5.4.14", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": "bin/vite.js" }, "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA=="], "vite": ["vite@5.4.14", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": "bin/vite.js" }, "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA=="],
"vitepress": ["vitepress@1.6.3", "", { "dependencies": { "@docsearch/css": "3.8.2", "@docsearch/js": "3.8.2", "@iconify-json/simple-icons": "^1.2.21", "@shikijs/core": "^2.1.0", "@shikijs/transformers": "^2.1.0", "@shikijs/types": "^2.1.0", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^5.2.1", "@vue/devtools-api": "^7.7.0", "@vue/shared": "^3.5.13", "@vueuse/core": "^12.4.0", "@vueuse/integrations": "^12.4.0", "focus-trap": "^7.6.4", "mark.js": "8.11.1", "minisearch": "^7.1.1", "shiki": "^2.1.0", "vite": "^5.4.14", "vue": "^3.5.13" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3"], "bin": "bin/vitepress.js" }, "sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw=="], "vitepress": ["vitepress@1.6.4", "", { "dependencies": { "@docsearch/css": "3.8.2", "@docsearch/js": "3.8.2", "@iconify-json/simple-icons": "^1.2.21", "@shikijs/core": "^2.1.0", "@shikijs/transformers": "^2.1.0", "@shikijs/types": "^2.1.0", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^5.2.1", "@vue/devtools-api": "^7.7.0", "@vue/shared": "^3.5.13", "@vueuse/core": "^12.4.0", "@vueuse/integrations": "^12.4.0", "focus-trap": "^7.6.4", "mark.js": "8.11.1", "minisearch": "^7.1.1", "shiki": "^2.1.0", "vite": "^5.4.14", "vue": "^3.5.13" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3", "postcss"], "bin": { "vitepress": "bin/vitepress.js" } }, "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg=="],
"vue": ["vue@3.5.18", "", { "dependencies": { "@vue/compiler-dom": "3.5.18", "@vue/compiler-sfc": "3.5.18", "@vue/runtime-dom": "3.5.18", "@vue/server-renderer": "3.5.18", "@vue/shared": "3.5.18" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA=="], "vue": ["vue@3.5.18", "", { "dependencies": { "@vue/compiler-dom": "3.5.18", "@vue/compiler-sfc": "3.5.18", "@vue/runtime-dom": "3.5.18", "@vue/server-renderer": "3.5.18", "@vue/shared": "3.5.18" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA=="],
"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.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vue/compiler-dom/@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vue/compiler-sfc/@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vue/compiler-sfc/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], "@vue/compiler-sfc/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"@vue/compiler-ssr/@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vue/reactivity/@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vue/runtime-core/@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vue/runtime-dom/@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vue/server-renderer/@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vueuse/core/vue": ["vue@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", "@vue/runtime-dom": "3.5.13", "@vue/server-renderer": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ=="], "@vueuse/core/vue": ["vue@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", "@vue/runtime-dom": "3.5.13", "@vue/server-renderer": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ=="],
"@vueuse/integrations/vue": ["vue@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", "@vue/runtime-dom": "3.5.13", "@vue/server-renderer": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ=="], "@vueuse/integrations/vue": ["vue@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", "@vue/runtime-dom": "3.5.13", "@vue/server-renderer": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ=="],
"@vueuse/shared/vue": ["vue@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", "@vue/runtime-dom": "3.5.13", "@vue/server-renderer": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ=="], "@vueuse/shared/vue": ["vue@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", "@vue/runtime-dom": "3.5.13", "@vue/server-renderer": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ=="],
"vitepress/vue": ["vue@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", "@vue/runtime-dom": "3.5.13", "@vue/server-renderer": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ=="],
"vue/@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vue/compiler-sfc/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], "@vue/compiler-sfc/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"@vueuse/core/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="], "@vueuse/core/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="],
@ -390,6 +370,8 @@
"@vueuse/core/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="], "@vueuse/core/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="],
"@vueuse/core/vue/@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="],
"@vueuse/integrations/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="], "@vueuse/integrations/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="],
"@vueuse/integrations/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ=="], "@vueuse/integrations/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ=="],
@ -398,6 +380,8 @@
"@vueuse/integrations/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="], "@vueuse/integrations/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="],
"@vueuse/integrations/vue/@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="],
"@vueuse/shared/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="], "@vueuse/shared/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="],
"@vueuse/shared/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ=="], "@vueuse/shared/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ=="],
@ -406,13 +390,7 @@
"@vueuse/shared/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="], "@vueuse/shared/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="],
"vitepress/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="], "@vueuse/shared/vue/@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="],
"vitepress/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ=="],
"vitepress/vue/@vue/runtime-dom": ["@vue/runtime-dom@3.5.13", "", { "dependencies": { "@vue/reactivity": "3.5.13", "@vue/runtime-core": "3.5.13", "@vue/shared": "3.5.13", "csstype": "^3.1.3" } }, "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog=="],
"vitepress/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="],
"@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="], "@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="],
@ -456,20 +434,6 @@
"@vueuse/shared/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA=="], "@vueuse/shared/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA=="],
"vitepress/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="],
"vitepress/vue/@vue/compiler-sfc/@babel/parser": ["@babel/parser@7.26.8", "", { "dependencies": { "@babel/types": "^7.26.8" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw=="],
"vitepress/vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="],
"vitepress/vue/@vue/compiler-sfc/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA=="],
"vitepress/vue/@vue/runtime-dom/@vue/reactivity": ["@vue/reactivity@3.5.13", "", { "dependencies": { "@vue/shared": "3.5.13" } }, "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg=="],
"vitepress/vue/@vue/runtime-dom/@vue/runtime-core": ["@vue/runtime-core@3.5.13", "", { "dependencies": { "@vue/reactivity": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw=="],
"vitepress/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA=="],
"@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser": ["@babel/parser@7.26.8", "", { "dependencies": { "@babel/types": "^7.26.8" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw=="], "@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser": ["@babel/parser@7.26.8", "", { "dependencies": { "@babel/types": "^7.26.8" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw=="],
"@vueuse/core/vue/@vue/compiler-sfc/@babel/parser/@babel/types": ["@babel/types@7.26.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA=="], "@vueuse/core/vue/@vue/compiler-sfc/@babel/parser/@babel/types": ["@babel/types@7.26.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA=="],
@ -482,10 +446,6 @@
"@vueuse/shared/vue/@vue/compiler-sfc/@babel/parser/@babel/types": ["@babel/types@7.26.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA=="], "@vueuse/shared/vue/@vue/compiler-sfc/@babel/parser/@babel/types": ["@babel/types@7.26.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA=="],
"vitepress/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser": ["@babel/parser@7.26.8", "", { "dependencies": { "@babel/types": "^7.26.8" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw=="],
"vitepress/vue/@vue/compiler-sfc/@babel/parser/@babel/types": ["@babel/types@7.26.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA=="],
"@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types": ["@babel/types@7.26.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA=="], "@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types": ["@babel/types@7.26.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA=="],
"@vueuse/core/vue/@vue/compiler-sfc/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], "@vueuse/core/vue/@vue/compiler-sfc/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="],
@ -504,12 +464,6 @@
"@vueuse/shared/vue/@vue/compiler-sfc/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], "@vueuse/shared/vue/@vue/compiler-sfc/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="],
"vitepress/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types": ["@babel/types@7.26.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA=="],
"vitepress/vue/@vue/compiler-sfc/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="],
"vitepress/vue/@vue/compiler-sfc/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="],
"@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], "@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="],
"@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], "@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="],
@ -521,9 +475,5 @@
"@vueuse/shared/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], "@vueuse/shared/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="],
"@vueuse/shared/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], "@vueuse/shared/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="],
"vitepress/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="],
"vitepress/vue/@vue/compiler-dom/@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="],
} }
} }

View File

@ -7,19 +7,19 @@ Here, common Minecraft server software is compared against Pumpkin.
> It's also important to consider that other servers have had years to optimize. > It's also important to consider that other servers have had years to optimize.
> Vanilla forks, which don’t need to rewrite the entire Vanilla logic, can focus exclusively on optimizations. > Vanilla forks, which don’t need to rewrite the entire Vanilla logic, can focus exclusively on optimizations.
![Screenshot From 2024-10-15 16-42-53](https://github.com/user-attachments/assets/e08fbb00-42fe-4479-a03b-11bb6886c91a) ![A screenshot showing 9 Minecraft game windows](https://github.com/user-attachments/assets/e08fbb00-42fe-4479-a03b-11bb6886c91a)
## Specifications ## Specifications
#### Technical ### Technical
**Software** #### Software
- Distribution: Manjaro Linux - Distribution: Manjaro Linux
- Architecture: x86_64 (64-bit) - Architecture: x86_64 (64-bit)
- Kernel Version: 6.11.3-arch1-1 - Kernel Version: 6.11.3-arch1-1
**Hardware** #### Hardware
- Motherboard: MAG B650 TOMAHAWK WIFI - Motherboard: MAG B650 TOMAHAWK WIFI
- CPU: AMD Ryzen 7600X 6-Core - CPU: AMD Ryzen 7600X 6-Core
@ -27,12 +27,12 @@ Here, common Minecraft server software is compared against Pumpkin.
- Storage: Samsung 990 PRO 1TB PCIe 4.0 M.2 SSD - Storage: Samsung 990 PRO 1TB PCIe 4.0 M.2 SSD
- Cooling: be quiet Dark Rock Elite - Cooling: be quiet Dark Rock Elite
**Rust** #### Rust
- Toolchain: stable-x86_64-unknown-linux-gnu (1.81.0) - Toolchain: stable-x86_64-unknown-linux-gnu (1.81.0)
- Rust Compiler: rustc 1.81.0 (eeb90cda1 2024-09-04) - Rust Compiler: rustc 1.81.0 (eeb90cda1 2024-09-04)
**Java** #### Java
- JDK Version: OpenJDK 23 64-Bit 2024-09-17 - JDK Version: OpenJDK 23 64-Bit 2024-09-17
- JRE Version: OpenJDK Runtime Environment (build 23+37) - JRE Version: OpenJDK Runtime Environment (build 23+37)
@ -44,7 +44,7 @@ Here, common Minecraft server software is compared against Pumpkin.
- View distance: 10 - View distance: 10
- Simulated distance: 10 - Simulated distance: 10
- Online mode: false - Online mode: false
- Rcon: false - RCON: false
<sub><sup>Online mode was disabled for easier testing with non-premium accounts.</sup></sub> <sub><sup>Online mode was disabled for easier testing with non-premium accounts.</sup></sub>
@ -80,7 +80,8 @@ Run args:
<sub><sup>Pumpkin does cache already loaded chunks, resulting in no extra RAM usage besides player data and minimal CPU usage.</sup></sub> <sub><sup>Pumpkin does cache already loaded chunks, resulting in no extra RAM usage besides player data and minimal CPU usage.</sup></sub>
#### Compile time ### Compile time
Compiling from nothing: Compiling from nothing:
**Debug:** <FmtNum :n=10.35 />sec **Debug:** <FmtNum :n=10.35 />sec
@ -135,7 +136,6 @@ Run args: `nogui`
| 5 | <FmtNum :n=1.9 />GB | <FmtNum :n=1.5 />% | <FmtNum :n=15 />% | | 5 | <FmtNum :n=1.9 />GB | <FmtNum :n=1.5 />% | <FmtNum :n=15 />% |
| 10 | <FmtNum :n=2 />GB | <FmtNum :n=3 />% | <FmtNum :n=20 />% | | 10 | <FmtNum :n=2 />GB | <FmtNum :n=3 />% | <FmtNum :n=20 />% |
## Purpur ## Purpur
Build: [2324](https://api.purpurmc.org/v2/purpur/1.21.1/2324/download) Build: [2324](https://api.purpurmc.org/v2/purpur/1.21.1/2324/download)
@ -184,5 +184,4 @@ Run args:
| 5 | <FmtNum :n=390 />MB | <FmtNum :n=1.0 />% | <FmtNum :n=6 />% | | 5 | <FmtNum :n=390 />MB | <FmtNum :n=1.0 />% | <FmtNum :n=6 />% |
| 10 | <FmtNum :n=421 />MB | <FmtNum :n=3 />% | <FmtNum :n=9 />% | | 10 | <FmtNum :n=421 />MB | <FmtNum :n=3 />% | <FmtNum :n=9 />% |
Benchmarked at <FmtDateTime :d="new Date('2024-10-15T16:34Z')" /> Benchmarked at <FmtDateTime :d="new Date('2024-10-15T16:34Z')" />

View File

@ -12,10 +12,12 @@ Servers authenthicate with Mojang's session servers in order to ensure the clien
Whether authenthication is enabled or not. Whether authenthication is enabled or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[authentication] [authentication]
enabled = false enabled = false
``` ```
::: :::
#### `prevent_proxy_connections`: Boolean #### `prevent_proxy_connections`: Boolean
@ -23,33 +25,41 @@ enabled = false
Whether to block proxy connections or not. Whether to block proxy connections or not.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[authentication] [authentication]
enabled = true enabled = true
prevent_proxy_connections = true prevent_proxy_connections = true
``` ```
::: :::
#### `auth_url`: String (optional) #### `auth_url`: String (optional)
The URL to authenthicate with. Uses Mojang's session servers to authenthicate if not specified. The URL to authenthicate with. Uses Mojang's session servers to authenthicate if not specified.
##### Placeholders ##### Placeholders
| Placeholder | Description | | Placeholder | Description |
| --------------- | ------------------ | | --------------- | ------------------ |
| `{username}` | Player username | | `{username}` | Player username |
| `{server_hash}` | Hash of the server | | `{server_hash}` | Hash of the server |
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[authentication] [authentication]
auth_url = "[custom auth server here]" auth_url = "[custom auth server here]"
``` ```
::: :::
#### `prevent_proxy_connection_auth_url`: String (optional) #### `prevent_proxy_connection_auth_url`: String (optional)
The URL to authenthicate with if `prevent_proxy_connections` is enabled. Uses Mojang's session servers to authenthicate if not specified. The URL to authenthicate with if `prevent_proxy_connections` is enabled. Uses Mojang's session servers to authenthicate if not specified.
##### Placeholders ##### Placeholders
| Placeholder | Description | | Placeholder | Description |
| --------------- | ------------------------ | | --------------- | ------------------------ |
| `{username}` | Player username | | `{username}` | Player username |
@ -57,104 +67,132 @@ The URL to authenthicate with if `prevent_proxy_connections` is enabled. Uses Mo
| `{ip}` | IP Address of the player | | `{ip}` | IP Address of the player |
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[authentication] [authentication]
prevent_proxy_connection_auth_url = "[custom auth server here]" prevent_proxy_connection_auth_url = "[custom auth server here]"
``` ```
::: :::
### Player Profile ### Player Profile
#### `allow_banned_players`: Boolean #### `allow_banned_players`: Boolean
Allow players flagged by Mojang. Allow players flagged by Mojang.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[authentication.player_profile] [authentication.player_profile]
allow_banned_players = true allow_banned_players = true
``` ```
::: :::
#### `allowed_actions`: String Array #### `allowed_actions`: String Array
What actions are allowed if `allow_banned_players` is enabled. What actions are allowed if `allow_banned_players` is enabled.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[authentication.player_profile] [authentication.player_profile]
allow_banned_players = true allow_banned_players = true
allowed_actions = ["FORCED_NAME_CHANGE", "USING_BANNED_SKIN"] allowed_actions = ["FORCED_NAME_CHANGE", "USING_BANNED_SKIN"]
``` ```
::: :::
### Textures ### Textures
#### `enabled`: Boolean #### `enabled`: Boolean
Whether to filter/validate player textures (e.g. skins/capes). Whether to filter/validate player textures (e.g. skins/capes).
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[authentication.textures] [authentication.textures]
enabled = true enabled = true
``` ```
::: :::
#### `allowed_url_schemes`: String Array #### `allowed_url_schemes`: String Array
Allowed URL schemes for textures. Allowed URL schemes for textures.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[authentication.textures] [authentication.textures]
enabled = true enabled = true
allowed_url_schemes = ["http", "https"] allowed_url_schemes = ["http", "https"]
``` ```
::: :::
#### `allowed_url_domains`: String Array #### `allowed_url_domains`: String Array
Allowed URL domains for textures. Allowed URL domains for textures.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[authentication.textures] [authentication.textures]
enabled = true enabled = true
allowed_url_domains = [".minecraft.net", ".mojang.com"] allowed_url_domains = [".minecraft.net", ".mojang.com"]
``` ```
::: :::
### Texture Types ### Texture Types
#### `skin`: Boolean #### `skin`: Boolean
Whether to use player skins or not. Whether to use player skins or not.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[authentication.textures.types] [authentication.textures.types]
skin = true skin = true
``` ```
::: :::
#### `cape`: Boolean #### `cape`: Boolean
Whether to use player capes or not. Whether to use player capes or not.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[authentication.textures.types] [authentication.textures.types]
cape = true cape = true
``` ```
::: :::
#### `elytra`: Boolean #### `elytra`: Boolean
Whether to use player elytras or not. Whether to use player elytras or not.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[authentication.textures.types] [authentication.textures.types]
elytra = true elytra = true
``` ```
::: :::
## Default Config ## Default Config
By default, authentication is enabled and uses Mojang's servers. Here is the default config: By default, authentication is enabled and uses Mojang's servers. Here is the default config:
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[authentication] [authentication]
enabled = true enabled = true
@ -174,4 +212,5 @@ skin = true
cape = true cape = true
elytra = true elytra = true
``` ```
::: :::

View File

@ -7,9 +7,11 @@ Representing `configuration.toml`
The address to bind the server to. The address to bind the server to.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
server_address = "0.0.0.0:25565" server_address = "0.0.0.0:25565"
``` ```
::: :::
## Seed ## Seed
@ -17,9 +19,11 @@ server_address = "0.0.0.0:25565"
The seed for world generation. The seed for world generation.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
seed = "" seed = ""
``` ```
::: :::
## Max players ## Max players
@ -27,9 +31,11 @@ seed = ""
The maximum number of players allowed on the server. The maximum number of players allowed on the server.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
max_players = 100000 max_players = 100000
``` ```
::: :::
## View distance ## View distance
@ -37,9 +43,11 @@ max_players = 100000
The maximum view distance for players. The maximum view distance for players.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
view_distance = 10 view_distance = 10
``` ```
::: :::
## Simulation distance ## Simulation distance
@ -47,9 +55,11 @@ view_distance = 10
The maximum simulation distance for players. The maximum simulation distance for players.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
simulation_distance = 10 simulation_distance = 10
``` ```
::: :::
## Default difficulty ## Default difficulty
@ -57,11 +67,12 @@ simulation_distance = 10
The default game difficulty. The default game difficulty.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
default_difficulty = "Normal" default_difficulty = "Normal"
``` ```
:::
:::
```toml ```toml
Peaceful Peaceful
@ -75,9 +86,11 @@ Hard
The permission level assigned by the `/op` command. The permission level assigned by the `/op` command.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
op_permission_level = 4 op_permission_level = 4
``` ```
::: :::
## Allow nether ## Allow nether
@ -85,9 +98,11 @@ op_permission_level = 4
Whether the Nether dimension is enabled. Whether the Nether dimension is enabled.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
allow_nether = true allow_nether = true
``` ```
::: :::
## Hardcore ## Hardcore
@ -95,9 +110,11 @@ allow_nether = true
Whether the server is in hardcore mode. Whether the server is in hardcore mode.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
hardcore = false hardcore = false
``` ```
::: :::
## Online Mode ## Online Mode
@ -105,9 +122,11 @@ hardcore = false
Whether online mode is enabled. Requires valid Minecraft accounts. Whether online mode is enabled. Requires valid Minecraft accounts.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
online_mode = true online_mode = true
``` ```
::: :::
## Encryption ## Encryption
@ -118,9 +137,11 @@ Whether packet encryption is enabled.
> Required when online mode is enabled. > Required when online mode is enabled.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
encryption = true encryption = true
``` ```
::: :::
## MOTD ## MOTD
@ -128,9 +149,11 @@ encryption = true
Message of the Day; the server's description displayed on the status screen. Message of the Day; the server's description displayed on the status screen.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
motd = "A Blazing fast Pumpkin Server!" motd = "A Blazing fast Pumpkin Server!"
``` ```
::: :::
## TPS ## TPS
@ -138,9 +161,11 @@ motd = "A Blazing fast Pumpkin Server!"
The server's target tick rate. The server's target tick rate.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
tps = 20.0 tps = 20.0
``` ```
::: :::
## Default gamemode ## Default gamemode
@ -148,9 +173,11 @@ tps = 20.0
The default game mode for players. The default game mode for players.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
default_gamemode = "Survival" default_gamemode = "Survival"
``` ```
::: :::
```toml ```toml
@ -166,9 +193,11 @@ Spectator
Whether to scrub players' IP addresses from logs. Whether to scrub players' IP addresses from logs.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
scrub_ips = true scrub_ips = true
``` ```
::: :::
## Use favicon ## Use favicon
@ -176,9 +205,11 @@ scrub_ips = true
Whether to use a server favicon or not. Whether to use a server favicon or not.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
use_favicon = true use_favicon = true
``` ```
::: :::
## Favicon path ## Favicon path
@ -186,7 +217,9 @@ use_favicon = true
The path to the server's favicon. The path to the server's favicon.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
favicon_path = "icon.png" favicon_path = "icon.png"
``` ```
::: :::

View File

@ -1,25 +1,33 @@
# Commands # Commands
Pumpkin supports Vanilla commands and allows you to configure where they can be ran from. Pumpkin supports Vanilla commands and allows you to configure where they can be ran from.
## Configuring Commands ## Configuring Commands
#### `use_console`: Boolean #### `use_console`: Boolean
Whether commands from the console are accepted or not. Whether commands from the console are accepted or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[commands] [commands]
use_console = false use_console = false
``` ```
::: :::
#### `log_console`: Boolean #### `log_console`: Boolean
Whether commands from players should be logged in the console or not. Whether commands from players should be logged in the console or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[commands] [commands]
log_console = false log_console = false
``` ```
::: :::
## Operation permission level ## Operation permission level
@ -27,20 +35,24 @@ log_console = false
The default permission level for all players. The default permission level for all players.
:::code-group :::code-group
```toml [configuration.toml] {2} ```toml [configuration.toml] {2}
default_op_level = 0 default_op_level = 0
``` ```
::: :::
## Default Config ## Default Config
By default, Pumpkin will allow commands from console and log all commands run by players. By default, Pumpkin will allow commands from console and log all commands run by players.
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[commands] [commands]
use_console = true use_console = true
log_console = true log_console = true
default_op_level = 0 default_op_level = 0
``` ```
::: :::

View File

@ -1,19 +1,23 @@
# Compression # Compression
Compression is used to reduce the size of packets. This is beneficial to reduce bandwidth server side and also to help players on slower internet connections. Compression is used to reduce the size of packets. This is beneficial to reduce bandwidth server side and also to help players on slower internet connections.
## Configuring compression ## Configuring compression
#### `enabled`: Boolean #### `enabled`: Boolean
Whether packet compression is enabled or not. Whether packet compression is enabled or not.
> [!TIP] > [!TIP]
> It might be beneficial to disable compression if the server is behind a proxy. > It might be beneficial to disable compression if the server is behind a proxy.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[packet_compression] [packet_compression]
enabled = true enabled = true
``` ```
::: :::
#### `threshold`: Integer (0-1024) #### `threshold`: Integer (0-1024)
@ -24,10 +28,12 @@ The minimum packet size before the server attempts to compress the packet.
> Increasing this value can hurt players on slower connections. > Increasing this value can hurt players on slower connections.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[packet_compression] [packet_compression]
threshold = 256 threshold = 256
``` ```
::: :::
#### `level`: Integer (0-9) #### `level`: Integer (0-9)
@ -35,10 +41,12 @@ threshold = 256
A value between 0 to 9: 0 to disable compression, 1 being the fastest compression (at the cost of size), and 9 being maximum compression (at the cost of speed). A value between 0 to 9: 0 to disable compression, 1 being the fastest compression (at the cost of size), and 9 being maximum compression (at the cost of speed).
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[packet_compression] [packet_compression]
level = 4 level = 4
``` ```
::: :::
## Default config ## Default config
@ -46,10 +54,12 @@ level = 4
By default, compression is enabled. By default, compression is enabled.
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[packet_compression] [packet_compression]
enabled = true enabled = true
threshold = 256 threshold = 256
level = 4 level = 4
``` ```
::: :::

View File

@ -16,7 +16,7 @@ Pumpkin aims to support the latest Minecraft Version. If you want to host a Pump
- Make sure to allow proxy connections. - Make sure to allow proxy connections.
- Pumpkin and ViaProxy have no connection; don't submit issues regarding their code. Furthermore, this is a 3rd party proxy and Pumpkin does not take any responsibility for the good or the bad. - Pumpkin and ViaProxy have no connection; don't submit issues regarding their code. Furthermore, this is a 3rd party proxy and Pumpkin does not take any responsibility for the good or the bad.
#### Key Features: #### Key Features
- Extensive Customization: Configure server settings, player behavior, world generation, and more. - Extensive Customization: Configure server settings, player behavior, world generation, and more.
- Performance Optimization: Optimize server performance through configuration tweaks. - Performance Optimization: Optimize server performance through configuration tweaks.

View File

@ -1,54 +1,67 @@
# LAN Broadcast # LAN Broadcast
Pumpkin can advertise the server across the network in order to make it easier for local players to connect to the server easier. Pumpkin can advertise the server across the network in order to make it easier for local players to connect to the server easier.
## Configuring LAN Broadcast ## Configuring LAN Broadcast
#### `enabled`: Boolean #### `enabled`: Boolean
Whether LAN broadcast is enabled or not. Whether LAN broadcast is enabled or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[lan_broadcast] [lan_broadcast]
enabled = true enabled = true
``` ```
::: :::
#### `motd`: String (optional) #### `motd`: String (optional)
The MOTD to broadcast out to clients; uses the server's MOTD by default. The MOTD to broadcast out to clients; uses the server's MOTD by default.
> [!CAUTION] > [!CAUTION]
> LAN broadcast MOTD does not support multiple lines, RGB colors, or gradients. Pumpkin does not verify the MOTD before broadcasting it. If the server MOTD is using these components, consider defining this field so that clients see a proper MOTD. > LAN broadcast MOTD does not support multiple lines, RGB colors, or gradients. Pumpkin does not verify the MOTD before broadcasting it. If the server MOTD is using these components, consider defining this field so that clients see a proper MOTD.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[lan_broadcast] [lan_broadcast]
enabled = true enabled = true
motd = "[your MOTD here]" motd = "[your MOTD here]"
``` ```
::: :::
#### `port`: Integer (0-65535) (optional) #### `port`: Integer (0-65535) (optional)
What port to bind to. If not specified, will bind to port 0 (any available port on the system). What port to bind to. If not specified, will bind to port 0 (any available port on the system).
> [!IMPORTANT] > [!IMPORTANT]
> The protocol defines what port to broadcast to. This option only exists to specify which port to bind to on the host. This option purely exists so that the port can be predictable. > The protocol defines what port to broadcast to. This option only exists to specify which port to bind to on the host. This option purely exists so that the port can be predictable.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[lan_broadcast] [lan_broadcast]
enabled = true enabled = true
port = 46733 port = 46733
``` ```
::: :::
## Default Config ## Default Config
By default, LAN broadcast is disabled. By default, LAN broadcast is disabled.
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[lan_broadcast] [lan_broadcast]
enabled = false enabled = false
motd = "[server MOTD here]" motd = "[server MOTD here]"
port = 0 port = 0
``` ```
::: :::

View File

@ -1,20 +1,26 @@
# Logging # Logging
Pumpkin allows you to customize what you want in your logs. Pumpkin allows you to customize what you want in your logs.
## Configuring Logging ## Configuring Logging
#### `enabled`: Boolean #### `enabled`: Boolean
Whether logging is enabled or not. Whether logging is enabled or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[logging] [logging]
enabled = true enabled = true
``` ```
::: :::
#### `level`: Enum #### `level`: Enum
The log verbosity level. Possible values are: The log verbosity level. Possible values are:
- Off - Off
- Error - Error
- Warn - Warn
@ -23,61 +29,77 @@ The log verbosity level. Possible values are:
- Trace - Trace
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[logging] [logging]
enabled = true enabled = true
level = "Debug" level = "Debug"
``` ```
::: :::
#### `env`: Boolean #### `env`: Boolean
Whether to allow choosing the log level by setting the `RUST_LOG` environment variable or not. Whether to allow choosing the log level by setting the `RUST_LOG` environment variable or not.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[logging] [logging]
enabled = true enabled = true
env = true env = true
``` ```
::: :::
#### `threads`: Boolean #### `threads`: Boolean
Whether to print threads in the logging message or not. Whether to print threads in the logging message or not.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[logging] [logging]
enabled = true enabled = true
threads = false threads = false
``` ```
::: :::
#### `color`: Boolean #### `color`: Boolean
Whether to print to the console with color or not. Whether to print to the console with color or not.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[logging] [logging]
enabled = true enabled = true
color = false color = false
``` ```
::: :::
#### `timestamp`: Boolean #### `timestamp`: Boolean
Whether to print the timestamp in the message or not. Whether to print the timestamp in the message or not.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[logging] [logging]
enabled = true enabled = true
timestamp = false timestamp = false
``` ```
::: :::
## Default Config ## Default Config
By default, logging is enabled at the `Info` level and will print with color, threads, and timestamps. By default, logging is enabled at the `Info` level and will print with color, threads, and timestamps.
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[logging] [logging]
enabled = true enabled = true
@ -87,4 +109,5 @@ threads = true
color = true color = true
timestamp = true timestamp = true
``` ```
::: :::

View File

@ -1,4 +1,5 @@
# Proxy # Proxy
Many servers use proxies to manage connections and distribute players across servers. Pumpkin supports the following proxy protocols: Many servers use proxies to manage connections and distribute players across servers. Pumpkin supports the following proxy protocols:
- [Velocity](https://papermc.io/software/velocity) - [Velocity](https://papermc.io/software/velocity)
@ -14,10 +15,12 @@ Many servers use proxies to manage connections and distribute players across ser
Enables support for proxies. Enables support for proxies.
:::code-group :::code-group
```toml [features.toml]{2} ```toml [features.toml]{2}
[proxy] [proxy]
enabled = true enabled = true
``` ```
::: :::
### Velocity ### Velocity
@ -27,10 +30,12 @@ enabled = true
Whether Velocity support is enabled or not. Whether Velocity support is enabled or not.
:::code-group :::code-group
```toml [features.toml]{2} ```toml [features.toml]{2}
[proxy.velocity] [proxy.velocity]
enabled = true enabled = true
``` ```
::: :::
#### `secret`: String #### `secret`: String
@ -38,32 +43,39 @@ enabled = true
The secret as configured in Velocity. The secret as configured in Velocity.
:::code-group :::code-group
```toml [features.toml]{3} ```toml [features.toml]{3}
[proxy.velocity] [proxy.velocity]
enabled = true enabled = true
secret = "[proxy secret here]" secret = "[proxy secret here]"
``` ```
::: :::
### BungeeCord ### BungeeCord
#### `enabled`: Boolean #### `enabled`: Boolean
Whether BungeeCord support is enabled or not. Whether BungeeCord support is enabled or not.
:::code-group :::code-group
```toml [features.toml]{2} ```toml [features.toml]{2}
[proxy.bungeecord] [proxy.bungeecord]
enabled = true enabled = true
``` ```
::: :::
> [!CAUTION] > [!CAUTION]
> BungeeCord can't verify if player info is from your proxy or an imposter. Ensure that the server's firewall is correctly configured. > BungeeCord can't verify if player info is from your proxy or an imposter. Ensure that the server's firewall is correctly configured.
## Default Config ## Default Config
By default, proxy support is disabled. Here is the default config: By default, proxy support is disabled. Here is the default config:
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[proxy] [proxy]
enabled = false enabled = false
@ -75,4 +87,5 @@ secret = ""
[proxy.bungeecord] [proxy.bungeecord]
enabled = false enabled = false
``` ```
::: :::

View File

@ -1,62 +1,80 @@
# PVP # PVP
PVP is a core part of the Vanilla mechanics, with even the smallest change affecting gameplay. Pumpkin allows you to fully configure PVP. PVP is a core part of the Vanilla mechanics, with even the smallest change affecting gameplay. Pumpkin allows you to fully configure PVP.
## Configuring PVP ## Configuring PVP
#### `enabled`: Boolean #### `enabled`: Boolean
Whether PVP is enabled or not. Whether PVP is enabled or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[pvp] [pvp]
enabled = true enabled = true
``` ```
::: :::
#### `hurt_animation`: Boolean #### `hurt_animation`: Boolean
Whether to show red hurt animation and FOV bobbing or not. Whether to show red hurt animation and FOV bobbing or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[pvp] [pvp]
hurt_animation = true hurt_animation = true
``` ```
::: :::
#### `protect_creative`: Boolean #### `protect_creative`: Boolean
Whether to protect players in creative against PVP or not. Whether to protect players in creative against PVP or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[pvp] [pvp]
protect_creative = true protect_creative = true
``` ```
::: :::
#### `knockback`: Boolean #### `knockback`: Boolean
Whether attacks should have knockback or not. Whether attacks should have knockback or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[pvp] [pvp]
knockback = true knockback = true
``` ```
::: :::
#### `swing`: Boolean #### `swing`: Boolean
Whether players should swing when attacking or not. Whether players should swing when attacking or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[pvp] [pvp]
swing = true swing = true
``` ```
::: :::
## Default Config ## Default Config
By default, all PVP options are enabled in order to match vanilla behavior. By default, all PVP options are enabled in order to match vanilla behavior.
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[pvp] [pvp]
enabled = true enabled = true
@ -65,4 +83,5 @@ protect_creative = true
knockback = true knockback = true
swing = true swing = true
``` ```
::: :::

View File

@ -1,36 +1,46 @@
# Query # Query
The Query protocol is a simple way to query the server about its status. Pumpkin fully supports the Query protocol. The Query protocol is a simple way to query the server about its status. Pumpkin fully supports the Query protocol.
## Configuring Query ## Configuring Query
#### `enabled`: Boolean #### `enabled`: Boolean
Whether to listen for Query protocol requests or not. Whether to listen for Query protocol requests or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[query] [query]
enabled = true enabled = true
``` ```
::: :::
#### `port`: Integer (0-65535) (optional) #### `port`: Integer (0-65535) (optional)
Which port to listen to Query protocol requests on. If not specified, it uses the same port as the server. Which port to listen to Query protocol requests on. If not specified, it uses the same port as the server.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[query] [query]
enabled = true enabled = true
port = 12345 port = 12345
``` ```
::: :::
## Default Config ## Default Config
By default, Query is disabled. It will run on the server port if enabled unless specified explicitly. By default, Query is disabled. It will run on the server port if enabled unless specified explicitly.
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[query] [query]
enabled = true enabled = true
port = 25565 port = 25565
``` ```
::: :::

View File

@ -1,4 +1,5 @@
# RCON # RCON
RCON is a protocol that allows you to remotely manage the server from a different device. Pumpkin has full support for RCON. RCON is a protocol that allows you to remotely manage the server from a different device. Pumpkin has full support for RCON.
## Configuring RCON ## Configuring RCON
@ -6,90 +7,116 @@ RCON is a protocol that allows you to remotely manage the server from a differen
#### `enabled`: Boolean #### `enabled`: Boolean
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[rcon] [rcon]
enabled = true enabled = true
``` ```
::: :::
#### `address`: String #### `address`: String
The address and port that RCON should listen to. The address and port that RCON should listen to.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[rcon] [rcon]
enabled = true enabled = true
address = "0.0.0.0:25575" address = "0.0.0.0:25575"
``` ```
::: :::
#### `password`: String #### `password`: String
The password to use for RCON authentication. The password to use for RCON authentication.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[rcon] [rcon]
enabled = true enabled = true
password = "[your safe password here]" password = "[your safe password here]"
``` ```
::: :::
#### `max_connections`: Integer #### `max_connections`: Integer
The max number of RCON connections allowed at a single time. Set this to 0 to disable the limit. The max number of RCON connections allowed at a single time. Set this to 0 to disable the limit.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[rcon] [rcon]
enabled = true enabled = true
max_connections = 5 max_connections = 5
``` ```
::: :::
### Logging ### Logging
#### `log_logged_successfully`: Boolean #### `log_logged_successfully`: Boolean
Whether successful logins should be logged to console or not. Whether successful logins should be logged to console or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[rcon.logging] [rcon.logging]
log_logged_successfully = true log_logged_successfully = true
``` ```
::: :::
#### `log_wrong_password`: Boolean #### `log_wrong_password`: Boolean
Whether wrong password attempts should be logged to console or not. Whether wrong password attempts should be logged to console or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[rcon.logging] [rcon.logging]
log_logged_successfully = true log_logged_successfully = true
``` ```
::: :::
#### `log_commands`: Boolean #### `log_commands`: Boolean
Whether to log commands ran from RCON to console or not. Whether to log commands ran from RCON to console or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[rcon.logging] [rcon.logging]
log_commands = true log_commands = true
``` ```
::: :::
#### `log_quit`: Boolean #### `log_quit`: Boolean
Whether RCON client quit should be logged or not. Whether RCON client quit should be logged or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[rcon.logging] [rcon.logging]
log_quit = true log_quit = true
``` ```
::: :::
## Default Config ## Default Config
By default, RCON is disabled. By default, RCON is disabled.
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[rcon] [rcon]
enabled = false enabled = false
@ -103,4 +130,5 @@ log_wrong_password = true
log_commands = true log_commands = true
log_quit = true log_quit = true
``` ```
::: :::

View File

@ -1,4 +1,5 @@
# Resource Pack # Resource Pack
Servers can send resource packs to clients in order to change the appearance of the game on the client. Pumpkin allows you to fully configure the resource pack. Servers can send resource packs to clients in order to change the appearance of the game on the client. Pumpkin allows you to fully configure the resource pack.
> [!TIP] > [!TIP]
@ -7,30 +8,37 @@ Servers can send resource packs to clients in order to change the appearance of
## Configuring Resource Pack ## Configuring Resource Pack
#### `enabled`: Boolean #### `enabled`: Boolean
Whether a resource pack is enabled or not. Whether a resource pack is enabled or not.
:::code-group :::code-group
```toml [features.toml] {2} ```toml [features.toml] {2}
[resource_pack] [resource_pack]
enabled = true enabled = true
``` ```
::: :::
#### `resource_pack_url`: String #### `resource_pack_url`: String
The direct download URL to the resource pack. The direct download URL to the resource pack.
> [!TIP] > [!TIP]
> You can host the resource pack for free at [MCPacks](https://mc-packs.net/). > You can host the resource pack for free at [MCPacks](https://mc-packs.net/).
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[resource_pack] [resource_pack]
enabled = true enabled = true
resource_pack_url = "[your download URL here]" resource_pack_url = "[your download URL here]"
``` ```
::: :::
#### `resource_pack_sha1`: String #### `resource_pack_sha1`: String
The SHA1 hash of the resource pack. The SHA1 hash of the resource pack.
> [!IMPORTANT] > [!IMPORTANT]
@ -41,51 +49,65 @@ The SHA1 hash of the resource pack.
::: details How do I get the SHA1 hash of my resource pack? ::: details How do I get the SHA1 hash of my resource pack?
::: code-group ::: code-group
```powershell [Windows (PowerShell)] ```powershell [Windows (PowerShell)]
Get-FileHash [file] SHA1 Get-FileHash [file] SHA1
``` ```
```shell [Mac OS] ```shell [Mac OS]
shasum -a 1 [file] shasum -a 1 [file]
``` ```
```shell [Linux] ```shell [Linux]
sha1sum [file] sha1sum [file]
``` ```
::: :::
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[resource_pack] [resource_pack]
enabled = true enabled = true
resource_pack_sha1 = "[your hash here]" resource_pack_sha1 = "[your hash here]"
``` ```
::: :::
#### `prompt_message`: String #### `prompt_message`: String
The message to show to the user when prompted to download the resource pack. The message to show to the user when prompted to download the resource pack.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[resource_pack] [resource_pack]
enabled = true enabled = true
prompt_message = "[your message here]" prompt_message = "[your message here]"
``` ```
::: :::
#### `force`: Boolean #### `force`: Boolean
Whether to force the client to download the resource pack or not. If the client declines the download, they will be kicked from the server. Whether to force the client to download the resource pack or not. If the client declines the download, they will be kicked from the server.
:::code-group :::code-group
```toml [features.toml] {3} ```toml [features.toml] {3}
[resource_pack] [resource_pack]
enabled = true enabled = true
force = false force = false
``` ```
::: :::
## Default Config ## Default Config
By default, no resource pack is sent to clients. By default, no resource pack is sent to clients.
:::code-group :::code-group
```toml [features.toml] ```toml [features.toml]
[resource_pack] [resource_pack]
enabled = false enabled = false
@ -94,4 +116,5 @@ resource_pack_sha1 = ""
prompt_message = "" prompt_message = ""
force = false force = false
``` ```
::: :::

View File

@ -1,13 +1,17 @@
### Contributing to Pumpkin # Contributing to Pumpkin
We appreciate your interest in contributing to Pumpkin! This document outlines the guidelines for submitting bug reports, feature suggestions, and code changes. We appreciate your interest in contributing to Pumpkin! This document outlines the guidelines for submitting bug reports, feature suggestions, and code changes.
### Getting Started ## Getting Started
The easiest way to get started is by asking for help in [our Discord server](https://discord.gg/wT8XjrjKkf). The easiest way to get started is by asking for help in [our Discord server](https://discord.gg/wT8XjrjKkf).
### How to Contribute ## How to Contribute
There are several ways you can contribute to Pumpkin: There are several ways you can contribute to Pumpkin:
#### Reporting Bugs ### Reporting Bugs
If you encounter a bug, please search for existing issues on the issue tracker first. If you encounter a bug, please search for existing issues on the issue tracker first.
If you can't find a duplicate issue, open a new one. If you can't find a duplicate issue, open a new one.
@ -15,12 +19,14 @@ There are several ways you can contribute to Pumpkin:
Follow the template and provide a clear description of the bug, including steps to reproduce it if possible. Follow the template and provide a clear description of the bug, including steps to reproduce it if possible.
Screenshots, logs, or code snippets can also be helpful. Screenshots, logs, or code snippets can also be helpful.
#### Suggesting Features ### Suggesting Features
Do you have an idea on how Pumpkin can be improved? Share your thoughts by opening an issue on the issue tracker. Do you have an idea on how Pumpkin can be improved? Share your thoughts by opening an issue on the issue tracker.
Describe the proposed feature in detail, including its benefits and potential implementation considerations. Describe the proposed feature in detail, including its benefits and potential implementation considerations.
#### Contributing Code ### Contributing Code
To get started with contributing code to Pumpkin, fork the repository on GitHub To get started with contributing code to Pumpkin, fork the repository on GitHub
1. First, create a GitHub account if you don't already have one 1. First, create a GitHub account if you don't already have one
@ -30,7 +36,6 @@ There are several ways you can contribute to Pumpkin:
> Creating a fork means you now have your own copy of the Pumpkin source code (this does not mean you own the copyright). > Creating a fork means you now have your own copy of the Pumpkin source code (this does not mean you own the copyright).
Now that you have a copy that you can edit, you will need a few tools. Now that you have a copy that you can edit, you will need a few tools.
3. Install [git](https://git-scm.com/downloads) for your operating system 3. Install [git](https://git-scm.com/downloads) for your operating system
- To get started with git, visit [Getting started with Git](https://docs.github.com/en/get-started/getting-started-with-git) - To get started with git, visit [Getting started with Git](https://docs.github.com/en/get-started/getting-started-with-git)
@ -46,16 +51,20 @@ There are several ways you can contribute to Pumpkin:
- If you are wanting to contribute to documentation, install [NodeJS](https://nodejs.org/en) - If you are wanting to contribute to documentation, install [NodeJS](https://nodejs.org/en)
### Decompiling Minecraft's code ### Decompiling Minecraft's code
When working at Pumpkin, we heavily rely on the official Minecraft client and utilize existing server logic. We often refer to Minecraft's official code. When working at Pumpkin, we heavily rely on the official Minecraft client and utilize existing server logic. We often refer to Minecraft's official code.
The easiest way to decompile Minecraft is by using Fabric Yarn. Make sure you have Gradle installed before running the following commands: The easiest way to decompile Minecraft is by using Fabric Yarn. Make sure you have Gradle installed before running the following commands:
```
```shell
git clone https://github.com/FabricMC/yarn.git git clone https://github.com/FabricMC/yarn.git
cd yarn cd yarn
./gradlew decompileVineflower ./gradlew decompileVineflower
``` ```
After decompiling, you can find the source code located in `build/namedSrc`. After decompiling, you can find the source code located in `build/namedSrc`.
### Additional Information ### Additional Information
We encourage you to comment on existing issues and pull requests to share your thoughts and provide feedback. We encourage you to comment on existing issues and pull requests to share your thoughts and provide feedback.
Feel free to ask questions in the issue tracker or reach out to the project maintainers if you need assistance. Feel free to ask questions in the issue tracker or reach out to the project maintainers if you need assistance.

View File

@ -1,8 +1,9 @@
### Introduction # Introduction
Welcome to the Pumpkin Documentation! Welcome to the Pumpkin Documentation!
Whether you're an internal Pumpkin developer or working on a Pumpkin plugin, this documentation is your resource for everything Pumpkin. Whether you're an internal Pumpkin developer or working on a Pumpkin plugin, this documentation is your resource for everything Pumpkin.
#### Plugin Development ## Plugin Development
For a better documentation structure, plugin development docs have been moved to a [separate category](/plugin-dev/introduction). For a better documentation structure, plugin development docs have been moved to a [separate category](/plugin-dev/introduction).

View File

@ -8,17 +8,20 @@ We recommend [Termux](https://github.com/termux/termux-app/releases) because it'
Download the needed apk file for your device's architecture and install Termux. Download the needed apk file for your device's architecture and install Termux.
After this, you need to run some commands. We use Helix for its simplicity. After this, you need to run some commands. We use Helix for its simplicity.
```bash ```bash
pkg update && pkg upgrade pkg update && pkg upgrade
pkg install build-essential git rust rust-analyzer taplo helix helix-grammar nodejs pkg install build-essential git rust rust-analyzer taplo helix helix-grammar nodejs
``` ```
If you want to contribute, you need to install the GitHub software. If you want to contribute, you need to install the GitHub software.
```bash ```bash
pkg install gh pkg install gh
``` ```
We also recommend installing the fish shell because it's more friendly than bash. We also recommend installing the fish shell because it's more friendly than bash.
```bash ```bash
pkg install fish pkg install fish
chsh -s fish chsh -s fish
@ -26,6 +29,7 @@ We also recommend installing the fish shell because it's more friendly than bash
Now that you've installed basic tools, we need to do some setup. Now that you've installed basic tools, we need to do some setup.
If you want to contribute, you need log into GitHub. If you want to contribute, you need log into GitHub.
```bash ```bash
gh auth login gh auth login
``` ```
@ -33,6 +37,7 @@ If you want to contribute, you need log into GitHub.
Also setup git: change the editor to vim, edit your credentials, etc. Also setup git: change the editor to vim, edit your credentials, etc.
After this, you need to clone the Pumpkin repo. (Before this, you can create a project directory with `mkdir proj`; it's useful) After this, you need to clone the Pumpkin repo. (Before this, you can create a project directory with `mkdir proj`; it's useful)
```bash ```bash
git clone https://github.com/Pumpkin-MC/Pumpkin.git git clone https://github.com/Pumpkin-MC/Pumpkin.git
``` ```
@ -41,29 +46,36 @@ If you want to contribute, you need to fork our repo and change `Pumpkin-MC` to
Setup's all done now! Enjoy :) Setup's all done now! Enjoy :)
# FAQ ## FAQ
### How to use the text editor?
## How to use the text editor?
Type `hx <path>`. Type `hx <path>`.
## How to navigate through the project? ### How to navigate through the project?
You can use `ls`, `cd`, and other programs. You can use `ls`, `cd`, and other programs.
You can also use `hx <dir>` to browse your directory on startup. You can also use `hx <dir>` to browse your directory on startup.
## How can I type in the editor? ### How can I type in the editor?
Press `i` if you are in normal mode. Press `i` if you are in normal mode.
## HOW EXIT FROM EDITOR???? ### HOW EXIT FROM EDITOR????
Press esc, then type `:q!` if you don't want to save, or `:wq` if you do want to save. Press esc, then type `:q!` if you don't want to save, or `:wq` if you do want to save.
## Where can I learn how to use this editor? ### Where can I learn how to use this editor?
Run `hx --tutor` or go their official website. Run `hx --tutor` or go their official website.
## Why not use VS Code? ### Why not use VS Code?
1) VS Code is hard to set up, and it works with limited functionality on web. 1) VS Code is hard to set up, and it works with limited functionality on web.
2) rust-analyzer doesn't work on it. Maybe an emulator can help with this, but that slows down code compilation. 2) rust-analyzer doesn't work on it. Maybe an emulator can help with this, but that slows down code compilation.
3) With VS Code, it's highly desirable to have a mouse, while in Helix you only need a keyboard. 3) With VS Code, it's highly desirable to have a mouse, while in Helix you only need a keyboard.
4) VS Code is laggy on some devices. 4) VS Code is laggy on some devices.
## Why is it so hard to type? ### Why is it so hard to type?
Buy a cheap bluetooth keyboard and see how much easier it becomes. Buy a cheap bluetooth keyboard and see how much easier it becomes.

View File

@ -1,28 +1,32 @@
## Authentication # Authentication
### Why authentication
## Why authentication
Offline accounts, that is, accounts generated from a player's username without contacting an authorization or authentication server, can have any nickname chosen. This, without additional plugins, means that players can impersonate other players, including those with operator permissions. Offline accounts, that is, accounts generated from a player's username without contacting an authorization or authentication server, can have any nickname chosen. This, without additional plugins, means that players can impersonate other players, including those with operator permissions.
### Offline server ## Offline server
By default, `online_mode` is enabled in the configuration. This enables authentication, disabling offline accounts. If you want to allow offline accounts, you can disable `online_mode` in `configuration.toml`. By default, `online_mode` is enabled in the configuration. This enables authentication, disabling offline accounts. If you want to allow offline accounts, you can disable `online_mode` in `configuration.toml`.
### How Yggdrasil Auth works ## How Yggdrasil Auth works
1. The client gets an authentication token and UUID from the launcher. 1. The client gets an authentication token and UUID from the launcher.
2. The client, during loading, fetches data from the authorization/authentication server using the authentication token, such as various signing keys and the list of blocked servers. 2. The client, during loading, fetches data from the authorization/authentication server using the authentication token, such as various signing keys and the list of blocked servers.
3. The client, when joining the server, sends a join request to the authorization/authentication servers. Mojang servers can deny this request if the account is banned. 3. The client, when joining the server, sends a join request to the authorization/authentication servers. Mojang servers can deny this request if the account is banned.
4. The client sends its identification to the server in a packet. 4. The client sends its identification to the server in a packet.
5. The server, based on this identification, sends a `hasJoined` request to the authorization/authentication servers. If it succeeds, it obtains the player information, such as the skin. 5. The server, based on this identification, sends a `hasJoined` request to the authorization/authentication servers. If it succeeds, it obtains the player information, such as the skin.
### Custom Authentication Server ## Custom Authentication Server
Pumpkin supports custom authentication servers. You can replace the authentication URL in `features.toml`. Pumpkin supports custom authentication servers. You can replace the authentication URL in `features.toml`.
#### How Pumpkin Authentication Works ### How Pumpkin Authentication Works
1. **GET Request:** Pumpkin sends a GET request to the specified authentication URL. 1. **GET Request:** Pumpkin sends a GET request to the specified authentication URL.
2. **Status Code 200:** If the authentication is successful, the server responds with a status code of 200. 2. **Status Code 200:** If the authentication is successful, the server responds with a status code of 200.
3. **Parse JSON Game Profile:** Pumpkin parses the JSON game profile returned in the response. 3. **Parse JSON Game Profile:** Pumpkin parses the JSON game profile returned in the response.
#### Game Profile ### Game Profile
```rust ```rust
struct GameProfile { struct GameProfile {
@ -33,7 +37,7 @@ struct GameProfile {
} }
``` ```
##### Property #### Property
```rust ```rust
struct Property { struct Property {
@ -43,7 +47,7 @@ struct Property {
} }
``` ```
##### Profile Action #### Profile Action
```rust ```rust
enum ProfileAction { enum ProfileAction {

View File

@ -28,7 +28,7 @@ Packets in the Pumpkin protocol are organized by functionality and state.
### Minecraft Protocol ### Minecraft Protocol
You can find all Minecraft Java packets at https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol. There you also can see which [state](#States) they are in. You can find all Minecraft Java packets at <https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol>. There you also can see which [state](#states) they are in.
You can also can see all the information the packets have, which we can either read or write depending on whether they are serverbound or clientbound. You can also can see all the information the packets have, which we can either read or write depending on whether they are serverbound or clientbound.
### Adding a Packet ### Adding a Packet
@ -46,22 +46,20 @@ You can also can see all the information the packets have, which we can either r
2. Next, you have to make it known that your struct represents a packet. This automatically gets the packet ID from the JSON packets file. 2. Next, you have to make it known that your struct represents a packet. This automatically gets the packet ID from the JSON packets file.
```rust ```rust
// For clientbound packets: use pumpkin_data::packet::clientbound::PLAY_DISCONNECT;
#[client_packet("play:disconnect")]
// For serverbound packets: #[packet(PLAY_DISCONNECT)]
#[server_packet("login:move_player_pos")]
``` ```
3. Now you can create the `struct`. 3. Now you can create the `struct`.
> [!IMPORTANT] > [!IMPORTANT]
> Please start the packet name with "C" or "S" for "Clientbound" or "Serverbound". > Please start the packet name with "C" or "S" for "Clientbound" or "Serverbound".
> Also, if it's a packet that can be sent in multiple [states](#States), please add the state to the name. For example, there are 3 different disconnect packets. > Also, if it's a packet that can be sent in multiple [states](#states), please add the state to the name. For example, there are 3 different disconnect packets.
> >
> - `CLoginDisconnect` > - `CLoginDisconnect`
> - `CConfigDisconnect` > - `CConfigDisconnect`
> - `CPlayDisconnect` > - `CPlayDisconnect`
Create fields within your packet structure to represent the data that will be sent. Create fields within your packet structure to represent the data that will be sent.
@ -98,7 +96,7 @@ impl CPlayDisconnect {
```rust ```rust
#[derive(Serialize)] #[derive(Serialize)]
#[client_packet("play:disconnect")] #[packet(PLAY_DISCONNECT)]
pub struct CPlayDisconnect { pub struct CPlayDisconnect {
reason: TextComponent, reason: TextComponent,
} }
@ -110,7 +108,7 @@ impl CPlayDisconnect {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
#[server_packet("login:move_player_pos")] #[packet(PLAY_MOVE_PLAYER_POS)]
pub struct SPlayerPosition { pub struct SPlayerPosition {
pub x: f64, pub x: f64,
pub feet_y: f64, pub feet_y: f64,
@ -148,17 +146,17 @@ pub struct SPlayerPosition {
Pumpkin categorizes `Client`s and `Player`s separately. Everything that is not in the play state is a simple `Client`. Here are the differences: Pumpkin categorizes `Client`s and `Player`s separately. Everything that is not in the play state is a simple `Client`. Here are the differences:
**Client** #### Client
- Can only be the states: Status, Login, Transfer, Config - Can only be the states: Status, Login, Transfer, Config
- Is not a living entity - Is not a living entity
- Has small resource consumption - Has small resource consumption
**Player** #### Player
- Can only be in the Play state - Can only be in the Play state
- Is a living entity in a world - Is a living entity in a world
- Has more data and consumes more resources - Has more data and consumes more resources
#### Sending Packets #### Sending Packets

View File

@ -1,25 +1,25 @@
### RCON # RCON (Remote Console)
### What is RCON ## What is RCON
RCON (Remote Console) is a protocol designed by Valve to allow administrators to control and manage game servers remotely. It provides a way to execute commands on a server from a different location, such as a phone or a separate computer. RCON (Remote Console) is a protocol designed by Valve to allow administrators to control and manage game servers remotely. It provides a way to execute commands on a server from a different location, such as a phone or a separate computer.
### Why RCON ## Why RCON
- **Convenience:** Manage your server from anywhere with an internet connection. - **Convenience:** Manage your server from anywhere with an internet connection.
- **Flexibility:** Execute commands without needing to be physically present at the server's location. - **Flexibility:** Execute commands without needing to be physically present at the server's location.
- **Efficiency:** Automate tasks and streamline server management. - **Efficiency:** Automate tasks and streamline server management.
### SSH vs RCON ## SSH vs RCON
**SSH** ### SSH
- Offers strong encryption to protect data transmitted between the client and server. - Offers strong encryption to protect data transmitted between the client and server.
- Primarily designed for secure remote login and execution of commands on a remote machine. - Primarily designed for secure remote login and execution of commands on a remote machine.
- Commonly used for managing Linux/Unix systems, configuring networks, and running scripts. - Commonly used for managing Linux/Unix systems, configuring networks, and running scripts.
- Provides a shell-like environment, allowing you to execute various commands and interact with the remote system. - Provides a shell-like environment, allowing you to execute various commands and interact with the remote system.
**RCON** ### RCON
- Specifically designed for remote administration of game servers, allowing you to control and manage the server's settings and operations. - Specifically designed for remote administration of game servers, allowing you to control and manage the server's settings and operations.
- Typically less secure than SSH, as it often relies on plain text passwords. - Typically less secure than SSH, as it often relies on plain text passwords.

View File

@ -1,6 +1,6 @@
### World Formats # World Formats
#### Region File Format ## Region File Format
Minecraft Beta 1.3 to Release 1.2 used a Minecraft format known as the "Region file format". Minecraft Beta 1.3 to Release 1.2 used a Minecraft format known as the "Region file format".
@ -8,7 +8,7 @@ The files stored in this format are `.mcr` files, each storing a group of 32x32
More details can be found on the [Minecraft Wiki](https://minecraft.wiki/w/Region_file_format). More details can be found on the [Minecraft Wiki](https://minecraft.wiki/w/Region_file_format).
#### Anvil File Format ## Anvil File Format
Replacing the Region File Format after Minecraft Release 1.2, this is the file format used to store modern Vanilla Minecraft: Java Edition worlds. Replacing the Region File Format after Minecraft Release 1.2, this is the file format used to store modern Vanilla Minecraft: Java Edition worlds.
@ -17,7 +17,7 @@ to a 256 height limit, then to 320, as well as a higher number of block IDs.
More details can be found on the [Minecraft Wiki](https://minecraft.wiki/w/Anvil_file_format). More details can be found on the [Minecraft Wiki](https://minecraft.wiki/w/Anvil_file_format).
#### Linear File Format ## Linear File Format
There is a more modern file format known as the Linear region file format. It saves on disk space and uses the zstd library instead of zlib. This is beneficial as zlib is extremely old and There is a more modern file format known as the Linear region file format. It saves on disk space and uses the zstd library instead of zlib. This is beneficial as zlib is extremely old and
outdated. outdated.
@ -26,7 +26,7 @@ The files stored in this format are `.linear` files, and it saves about 50% of d
More details can be found at the GitHub page for [LinearRegionFileFormatTools](https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools). More details can be found at the GitHub page for [LinearRegionFileFormatTools](https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools).
#### Slime File Format ## Slime File Format
Developed by Hypixel to fix many of the pitfalls of the Anvil file format, Slime also replaces zlib and saves space compared to Anvil. It saves the entire world in a single save Developed by Hypixel to fix many of the pitfalls of the Anvil file format, Slime also replaces zlib and saves space compared to Anvil. It saves the entire world in a single save
file, and allows that file to be loaded into multiple instances. file, and allows that file to be loaded into multiple instances.
@ -35,7 +35,7 @@ The files stored in this format are `.slime` files.
More details can be found on the GitHub page for [Slime World Manager](https://github.com/cijaaimee/Slime-World-Manager#:~:text=Slime%20World%20Manager%20is%20a,worlds%20faster%20and%20save%20space.), as well as on [Dev Blog #5](https://hypixel.net/threads/dev-blog-5-storing-your-skyblock-island.2190753/) for Hypixel. More details can be found on the GitHub page for [Slime World Manager](https://github.com/cijaaimee/Slime-World-Manager#:~:text=Slime%20World%20Manager%20is%20a,worlds%20faster%20and%20save%20space.), as well as on [Dev Blog #5](https://hypixel.net/threads/dev-blog-5-storing-your-skyblock-island.2190753/) for Hypixel.
#### Schematic File Format ## Schematic File Format
Unlike the other file formats listed, the Schematic File Format is not used for storing Minecraft worlds, but instead used within 3rd party programs such as MCEdit, WorldEdit, and Schematica. Unlike the other file formats listed, the Schematic File Format is not used for storing Minecraft worlds, but instead used within 3rd party programs such as MCEdit, WorldEdit, and Schematica.
@ -53,13 +53,13 @@ Pumpkin then calls for world generation:
`AnvilChunkReader` is called to process the region files for the given save `AnvilChunkReader` is called to process the region files for the given save
- As stated above, region files store 32x32 chunks - As stated above, region files store 32x32 chunks
> Each region file is named corresponding to coordinates of where it is in the world > Each region file is named corresponding to coordinates of where it is in the world
> r.{}.{}.mca > r.{}.{}.mca
- The location table is read from the save file, representing the chunk coordinates - The location table is read from the save file, representing the chunk coordinates
- The timestamp table is read from the save file, representing the last time the chunk was modified - The timestamp table is read from the save file, representing the last time the chunk was modified
#### No Save Present #### No Save Present
@ -67,17 +67,17 @@ The world seed is set to "0". In the future it will be set to the value in the "
`PlainsGenerator` is called, as so far `Plains` is the only biome that has been implemented. `PlainsGenerator` is called, as so far `Plains` is the only biome that has been implemented.
- `PerlinTerrainGenerator` is called to set chunk height - `PerlinTerrainGenerator` is called to set chunk height
- Stone height is set 5 below chunk height - Stone height is set 5 below chunk height
- Dirt height is set to 2 below chunk height - Dirt height is set to 2 below chunk height
- Grass blocks appear at the top of dirt - Grass blocks appear at the top of dirt
- Bedrock is set at y = -64 - Bedrock is set at y = -64
- Flowers and short grass are scattered about randomly - Flowers and short grass are scattered about randomly
`SuperflatGenerator` is also available, but is not currently callable. `SuperflatGenerator` is also available, but is not currently callable.
- Bedrock is set at y = -64 - Bedrock is set at y = -64
- Dirt is set two blocks up - Dirt is set two blocks up
- Grass blocks are set one more block up - Grass blocks are set one more block up
Blocks are able to be placed and broken, but changes are not able to be saved in any world format. Anvil worlds are currently read only. Blocks are able to be placed and broken, but changes are not able to be saved in any world format. Anvil worlds are currently read only.

View File

@ -7,7 +7,8 @@ Pre-release: Currently under development and not yet ready for official release.
To run Pumpkin with Rust, ensure you have [Rust](https://www.rust-lang.org/tools/install) installed. To run Pumpkin with Rust, ensure you have [Rust](https://www.rust-lang.org/tools/install) installed.
1. Clone the repository: 1. **Clone the repository** and navigate into the directory:
```shell ```shell
git clone https://github.com/Pumpkin-MC/Pumpkin.git git clone https://github.com/Pumpkin-MC/Pumpkin.git
cd Pumpkin cd Pumpkin
@ -25,6 +26,7 @@ cargo run --release
``` ```
4. **Optional:** If you want to use your CPU features, you can set the `target-cpu=native` Rust compiler flag. 4. **Optional:** If you want to use your CPU features, you can set the `target-cpu=native` Rust compiler flag.
```shell ```shell
RUSTFLAGS='-C target-cpu=native' cargo run --release RUSTFLAGS='-C target-cpu=native' cargo run --release
``` ```
@ -49,6 +51,7 @@ docker run --rm \
### Example ### Example
To run Pumpkin on port `25565` and store data in a directory called `./data`, you would run the following command: To run Pumpkin on port `25565` and store data in a directory called `./data`, you would run the following command:
```shell ```shell
docker run --rm \ docker run --rm \
-p 25565:25565 \ -p 25565:25565 \
@ -57,11 +60,13 @@ docker run --rm \
``` ```
## Test Server ## Test Server
Pumpkin has a test server maintained by @kralverde. Its runs on the latest commit of Pumpkin's master branch. Pumpkin has a test server maintained by @kralverde. Its runs on the latest commit of Pumpkin's master branch.
- **IP:** pumpkin.kralverde.dev - **IP:** pumpkin.kralverde.dev
**Specs:** **Specs:**
- OS: Debian GNU/Linux bookworm 12.7 x86_64 - OS: Debian GNU/Linux bookworm 12.7 x86_64
- Kernel: Linux 6.1.0-21-cloud-amd64 - Kernel: Linux 6.1.0-21-cloud-amd64
- CPU: Intel Core (Haswell, no TSX) (2) @ 2.40 GHz - CPU: Intel Core (Haswell, no TSX) (2) @ 2.40 GHz

View File

@ -1,4 +1,5 @@
# Pumpkin Plugin Development # Pumpkin Plugin Development
::: warning ::: warning
The Pumpkin Plugin API is still in a very early stage of development and may change at any time. The Pumpkin Plugin API is still in a very early stage of development and may change at any time.
If you run into any issues please reach out on [our Discord server](https://discord.gg/aaNuD6rFEe). If you run into any issues please reach out on [our Discord server](https://discord.gg/aaNuD6rFEe).
@ -7,4 +8,3 @@ If you run into any issues please reach out on [our Discord server](https://disc
Pumpkin Plugins integrate with the server software on a very deep level allowing for many things that would not be possible on other server software. Pumpkin Plugins integrate with the server software on a very deep level allowing for many things that would not be possible on other server software.
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 development, you should have a pretty easy time writing plugins for Pumpkin. :smile: 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 development, you should have a pretty easy time writing plugins for Pumpkin. :smile:

View File

@ -1,8 +1,11 @@
# Writing the basic logic # Writing the basic logic
## Plugin base ## Plugin base
Even in a basic plugin, there is a lot going on under the hood, so to greatly simplify plugin development we will use the `pumpkin-api-macros` crate to create a basic empty plugin. Even in a basic plugin, there is a lot going on under the hood, so to greatly simplify plugin development we will use the `pumpkin-api-macros` crate to create a basic empty plugin.
:::code-group :::code-group
```rs:line-numbers [lib.rs] ```rs:line-numbers [lib.rs]
use pumpkin_api_macros::plugin_impl; use pumpkin_api_macros::plugin_impl;
@ -21,20 +24,24 @@ impl Default for MyPlugin {
} }
} }
``` ```
::: :::
This will create an empty plugin and implement all the necessary methods for it to be loaded by Pumpkin. This will create an empty plugin and implement all the necessary methods for it to be loaded by Pumpkin.
We can now try to compile our plugin for the first time. To do so, run this command in your project folder: We can now try to compile our plugin for the first time. To do so, run this command in your project folder:
```bash ```bash
cargo build --release cargo build --release
``` ```
::: tip NOTICE ::: tip NOTICE
If you are using Windows, you **must** use the `--release` flag, or you will run into issues. If you are on another platform, you don't have to use it if you want to save on compile time. If you are using Windows, you **must** use the `--release` flag, or you will run into issues. If you are on another platform, you don't have to use it if you want to save on compile time.
::: :::
The initial compilation will take a bit, but don't worry, later compilations will be faster. The initial compilation will take a bit, but don't worry, later compilations will be faster.
If all went well, you should be left with a message like this: If all went well, you should be left with a message like this:
```log ```log
╰─ cargo build --release ╰─ cargo build --release
Compiling hello-pumpkin v0.1.0 (/home/vypal/Dokumenty/GitHub/hello-pumpkin) Compiling hello-pumpkin v0.1.0 (/home/vypal/Dokumenty/GitHub/hello-pumpkin)
@ -44,6 +51,7 @@ If all went well, you should be left with a message like this:
Now you can go to the `./target/release` folder (or `./target/debug` if you didn't use `--release`) and locate your plugin binary. Now you can go to the `./target/release` folder (or `./target/debug` if you didn't use `--release`) and locate your plugin binary.
Depending on your operating system, the file will have one of three possible names: Depending on your operating system, the file will have one of three possible names:
- For Windows: `hello-pumpkin.dll` - For Windows: `hello-pumpkin.dll`
- For MacOS: `libhello-pumpkin.dylib` - For MacOS: `libhello-pumpkin.dylib`
- For Linux: `libhello-pumpkin.so` - For Linux: `libhello-pumpkin.so`
@ -55,23 +63,27 @@ If you used a different project name in the `Cargo.toml` file, look for a file w
You can rename this file to whatever you like, however you must keep the file extension (`.dll`, `.dylib`, or `.so`) the same. You can rename this file to whatever you like, however you must keep the file extension (`.dll`, `.dylib`, or `.so`) the same.
## Testing the plugin ## Testing the plugin
Now that we have our plugin binary, we can go ahead and test it on the Pumpkin server. Installing a plugin is as simple as putting the plugin binary that we just built into the `plugins/` folder of your Pumpkin server! Now that we have our plugin binary, we can go ahead and test it on the Pumpkin server. Installing a plugin is as simple as putting the plugin binary that we just built into the `plugins/` folder of your Pumpkin server!
Thanks to the `#[plugin_impl]` macro, the plugin will have its details (like the name, authors, version, and description) built into the binary so that the server can read them. Thanks to the `#[plugin_impl]` macro, the plugin will have its details (like the name, authors, version, and description) built into the binary so that the server can read them.
When you start up the server and run the `/plugins` command, you should see an output like this: When you start up the server and run the `/plugins` command, you should see an output like this:
```
```text
There is 1 plugin loaded: There is 1 plugin loaded:
hello-pumpkin hello-pumpkin
``` ```
## Basic methods ## Basic methods
The Pumpkin server currently uses two "methods" to tell the plugin about its state. These methods are `on_load` and `on_unload`. The Pumpkin server currently uses two "methods" to tell the plugin about its state. These methods are `on_load` and `on_unload`.
These methods don't have to be implemented, but you will usually implement at least the `on_load` method. In this method you get access to a `Context` object which can give the plugin access to information about the server, but also allows the plugin to register command handlers and events. These methods don't have to be implemented, but you will usually implement at least the `on_load` method. In this method you get access to a `Context` object which can give the plugin access to information about the server, but also allows the plugin to register command handlers and events.
To make implementing these methods easier, there is another macro provided by the `pumpkin-api-macros` crate. To make implementing these methods easier, there is another macro provided by the `pumpkin-api-macros` crate.
:::code-group :::code-group
```rs [lib.rs] ```rs [lib.rs]
use pumpkin_api_macros::{plugin_impl, plugin_method}; // [!code ++:2] use pumpkin_api_macros::{plugin_impl, plugin_method}; // [!code ++:2]
use pumpkin::plugin::Context; use pumpkin::plugin::Context;
@ -97,6 +109,7 @@ impl Default for MyPlugin {
} }
} }
``` ```
::: :::
::: warning IMPORTANT ::: warning IMPORTANT
@ -105,32 +118,42 @@ It is important that you define any plugin methods before the `#[plugin_impl]` b
This method gets a mutable reference to its plugin object (in this case the `MyPlugin` struct) which it can use to initialize any data stored in the plugin's main struct, and a reference to a `Context` object. This object is specifically constructed for this plugin based on the plugin's metadata. This method gets a mutable reference to its plugin object (in this case the `MyPlugin` struct) which it can use to initialize any data stored in the plugin's main struct, and a reference to a `Context` object. This object is specifically constructed for this plugin based on the plugin's metadata.
### Methods implemented on the `Context` object: ### Methods implemented on the `Context` object
```rs ```rs
fn get_data_folder() -> String fn get_data_folder() -> String
``` ```
Returns the path to the folder dedicated to this plugin, which should be used for persistent data storage Returns the path to the folder dedicated to this plugin, which should be used for persistent data storage
```rs ```rs
async fn get_player_by_name(player_name: String) -> Option<Arc<Player>> async fn get_player_by_name(player_name: String) -> Option<Arc<Player>>
``` ```
If a player by the name `player_name` is found (has to be currently online), this function will return a reference to them. If a player by the name `player_name` is found (has to be currently online), this function will return a reference to them.
```rs ```rs
async fn register_command(tree: CommandTree, permission: PermissionLvl) async fn register_command(tree: CommandTree, permission: PermissionLvl)
``` ```
Registers a new command handler, with a minimum required permission level. Registers a new command handler, with a minimum required permission level.
```rs ```rs
async fn register_event(handler: Arc<H>, priority: EventPriority, blocking: bool) async fn register_event(handler: Arc<H>, priority: EventPriority, blocking: bool)
``` ```
Registers a new event handler with a set priority and if it is blocking or not. Registers a new event handler with a set priority and if it is blocking or not.
By the way, `handler` is `Arc<T>`, which means you can implement a lot of events on one handler, and then register it. By the way, `handler` is `Arc<T>`, which means you can implement a lot of events on one handler, and then register it.
## Basic on-load method ## Basic on-load method
For now we will only implement a very basic `on_load` method to be able to see that the plugin is running. For now we will only implement a very basic `on_load` method to be able to see that the plugin is running.
Here we will set up the inner Pumpkin logger and set up a "Hello, Pumpkin!" so that we can see our plugin in action. Here we will set up the inner Pumpkin logger and set up a "Hello, Pumpkin!" so that we can see our plugin in action.
Add this to the `on_load` method: Add this to the `on_load` method:
:::code-group :::code-group
```rs [lib.rs] ```rs [lib.rs]
#[plugin_method] #[plugin_method]
async fn on_load(&mut self, server: &Context) -> Result<(), String> { async fn on_load(&mut self, server: &Context) -> Result<(), String> {
@ -141,6 +164,7 @@ async fn on_load(&mut self, server: &Context) -> Result<(), String> {
Ok(()) Ok(())
} }
``` ```
::: :::
If we build the plugin again and start up the server, you should now see "Hello, Pumpkin!" somewhere in the log. If we build the plugin again and start up the server, you should now see "Hello, Pumpkin!" somewhere in the log.

View File

@ -1,23 +1,30 @@
# Creating a new project # Creating a new project
Pumpkin plugins use the [Cargo](https://doc.rust-lang.org/book/ch01-03-hello-cargo.html) build system. Pumpkin plugins use the [Cargo](https://doc.rust-lang.org/book/ch01-03-hello-cargo.html) build system.
The complete code for this plugin can be found as a [template on GitHub](https://github.com/vyPal/Hello-Pumpkin). The complete code for this plugin can be found as a [template on GitHub](https://github.com/vyPal/Hello-Pumpkin).
## Initializing a new crate ## Initializing a new crate
First we need to create a new project folder. You can do this by running this command in the folder you created: First we need to create a new project folder. You can do this by running this command in the folder you created:
```bash ```bash
cargo new <project-name> --lib cargo new <project-name> --lib
``` ```
This will create a folder with a couple files in it. The folder structure should look like this: This will create a folder with a couple files in it. The folder structure should look like this:
```
```bash
├── Cargo.toml ├── Cargo.toml
└── src └── src
└── lib.rs └── lib.rs
``` ```
## Configuring the crate ## Configuring the crate
Since Pumpkin plugins are loaded at runtime as dynamic libraries, we need to tell Cargo to build this crate as one. Since Pumpkin plugins are loaded at runtime as dynamic libraries, we need to tell Cargo to build this crate as one.
:::code-group :::code-group
```toml [Cargo.toml] ```toml [Cargo.toml]
[package] [package]
name = "hello-pumpkin" name = "hello-pumpkin"
@ -29,10 +36,12 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
``` ```
::: :::
Next we need to add some basic dependencies. Since Pumpkin is still in early development, the internal crates aren't published to crates.io, so we need to tell Cargo to download the dependencies directly from GitHub. Next we need to add some basic dependencies. Since Pumpkin is still in early development, the internal crates aren't published to crates.io, so we need to tell Cargo to download the dependencies directly from GitHub.
:::code-group :::code-group
```toml [Cargo.toml] ```toml [Cargo.toml]
[package] [package]
name = "hello-pumpkin" name = "hello-pumpkin"
@ -58,14 +67,17 @@ tokio = "1.42"
# Logging # Logging
log = "0.4" log = "0.4"
``` ```
::: :::
For improved performance and smaller file sizes, we recommend enabling Link-Time Optimization (LTO). For improved performance and smaller file sizes, we recommend enabling Link-Time Optimization (LTO).
Be aware that this will increase compilation time. Be aware that this will increase compilation time.
:::code-group :::code-group
```toml [Cargo.toml] ```toml [Cargo.toml]
[profile.release] // [!code ++:2] [profile.release] // [!code ++:2]
lto = true lto = true
``` ```
::: :::
<small>Enables LTO only for release builds.</small> <small>Enables LTO only for release builds.</small>

View File

@ -1,9 +1,11 @@
# Writing an Example Plugin # Writing an Example Plugin
This tutorial will guide you through creating a new plugin. This tutorial will guide you through creating a new plugin.
This tutorial expects that you have some experience with Rust and the command line. This tutorial expects that you have some experience with Rust and the command line.
Topics described in this tutorial: Topics described in this tutorial:
- Modifying the join message - Modifying the join message
- Creating a rock-paper-scissors command - Creating a rock-paper-scissors command
- Saving plugin data in the plugin's directory (coming soon) - Saving plugin data in the plugin's directory (coming soon)

View File

@ -1,9 +1,11 @@
# Opening a custom inventory # Opening a custom inventory
## Overview ## Overview
The inventory system in Pumpkin provides a flexible way to manage item storage and manipulation. This guide explains how to create and implement custom inventories. The inventory system in Pumpkin provides a flexible way to manage item storage and manipulation. This guide explains how to create and implement custom inventories.
## Table of Contents ## Table of Contents
- [Opening a custom inventory](#opening-a-custom-inventory) - [Opening a custom inventory](#opening-a-custom-inventory)
- [Overview](#overview) - [Overview](#overview)
- [Table of Contents](#table-of-contents) - [Table of Contents](#table-of-contents)
@ -14,7 +16,6 @@ The inventory system in Pumpkin provides a flexible way to manage item storage a
- [Screen Handlers](#screen-handlers) - [Screen Handlers](#screen-handlers)
- [Using Generic Screen Handlers](#using-generic-screen-handlers) - [Using Generic Screen Handlers](#using-generic-screen-handlers)
- [Creating Custom Screen Handlers](#creating-custom-screen-handlers) - [Creating Custom Screen Handlers](#creating-custom-screen-handlers)
- [Supported Window Types](#supported-window-types)
- [Best Practices](#best-practices) - [Best Practices](#best-practices)
- [Examples](#examples) - [Examples](#examples)
- [Basic Inventory Usage](#basic-inventory-usage) - [Basic Inventory Usage](#basic-inventory-usage)

View File

@ -1,4 +1,5 @@
# Writing a Event Handler # Writing a Event Handler
Event handlers are one of the main functions of plugins. They allow a plugin to tap into the internal workings of the server and alter its behavior to perform some other action. For a simple example, we will implement a handler for the `player_join` event. Event handlers are one of the main functions of plugins. They allow a plugin to tap into the internal workings of the server and alter its behavior to perform some other action. For a simple example, we will implement a handler for the `player_join` event.
The Pumpkin plugin event system tries to copy the Bukkit/Spigot Event system, so that developers coming from there will have a easier time learning Pumpkin. The Pumpkin plugin event system tries to copy the Bukkit/Spigot Event system, so that developers coming from there will have a easier time learning Pumpkin.
@ -9,11 +10,15 @@ The event system uses traits to dynamically handle some events: `Event`, `Cancel
Cancellable can also be an Event, because it's a trait. (TODO: verify this) Cancellable can also be an Event, because it's a trait. (TODO: verify this)
## Implementing the Join Event ## Implementing the Join Event
Individual event handlers are just structs which implement the `EventHandler<T>` trait (where `T` is a specific event implementation). Individual event handlers are just structs which implement the `EventHandler<T>` trait (where `T` is a specific event implementation).
### What are blocking events? ### What are blocking events?
The Pumpkin plugin event system differentiates between two types of events: blocking and non-blocking. Each have their benefits: The Pumpkin plugin event system differentiates between two types of events: blocking and non-blocking. Each have their benefits:
#### Blocking events #### Blocking events
```diff ```diff
Pros: Pros:
+ Can modify the event (like editing the join message) + Can modify the event (like editing the join message)
@ -23,7 +28,9 @@ Cons:
- Are executed in sequence - Are executed in sequence
- Can slow down the server if not implemented well - Can slow down the server if not implemented well
``` ```
#### Non-blocking events #### Non-blocking events
```diff ```diff
Pros: Pros:
+ Are executed concurrently + Are executed concurrently
@ -36,10 +43,12 @@ Cons:
``` ```
### Writing a handler ### Writing a handler
Since our main aim here is to change the welcome message that the player sees when they join a server, we will be choosing the blocking event type with a low priority. Since our main aim here is to change the welcome message that the player sees when they join a server, we will be choosing the blocking event type with a low priority.
Add this code above the `on_load` method: Add this code above the `on_load` method:
:::code-group :::code-group
```rs [lib.rs] ```rs [lib.rs]
use async_trait::async_trait; // [!code ++:7] use async_trait::async_trait; // [!code ++:7]
use pumpkin_api_macros::with_runtime; use pumpkin_api_macros::with_runtime;
@ -61,9 +70,11 @@ impl EventHandler<PlayerJoinEvent> for MyJoinHandler {
} }
} }
``` ```
::: :::
**Explanation**: **Explanation**:
- `struct MyJoinHandler;`: The struct for our event handler - `struct MyJoinHandler;`: The struct for our event handler
- `#[with_runtime(global)]`: Pumpkin uses the tokio async runtime, which acts in weird ways across the plugin boundary. Even though it is not necessary in this specific example, it is a good practice to wrap all async `impl`s that interact with async code with this macro. - `#[with_runtime(global)]`: Pumpkin uses the tokio async runtime, which acts in weird ways across the plugin boundary. Even though it is not necessary in this specific example, it is a good practice to wrap all async `impl`s that interact with async code with this macro.
- `#[async_trait]`: Rust doesn't have full support for traits with async methods. So, we use the `async_trait` crate to allow this. - `#[async_trait]`: Rust doesn't have full support for traits with async methods. So, we use the `async_trait` crate to allow this.
@ -74,8 +85,10 @@ It is important that the `#[with_runtime(global)]` macro is **above** the **`#[a
::: :::
### Registering the handler ### Registering the handler
Now that we have written the event handler, we need to tell the plugin to use it. We can do that by adding a single line into the `on_load` method: Now that we have written the event handler, we need to tell the plugin to use it. We can do that by adding a single line into the `on_load` method:
:::code-group :::code-group
```rs [lib.rs] ```rs [lib.rs]
use pumpkin::{ use pumpkin::{
plugin::{player::player_join::PlayerJoinEvent, Context, EventHandler, EventPriority}, // [!code ++] plugin::{player::player_join::PlayerJoinEvent, Context, EventHandler, EventPriority}, // [!code ++]
@ -97,5 +110,6 @@ async fn on_load(&mut self, server: &Context) -> Result<(), String> {
Ok(()) Ok(())
} }
``` ```
::: :::
Now if we build the plugin and join the server, we should see a green "Welcome" message with our username! Now if we build the plugin and join the server, we should see a green "Welcome" message with our username!

View File

@ -1,4 +1,5 @@
# Writing a Command Handler # Writing a Command Handler
In Minecraft, commands are the primary way for both regular players and server operators to interact with the game on a lower level. They can be used to perform a wide range of tasks, from simple chat messages to complex server management commands. In this tutorial, we will create a basic Rock-Paper-Scissors command handler that allows players to play the game against the server. In Minecraft, commands are the primary way for both regular players and server operators to interact with the game on a lower level. They can be used to perform a wide range of tasks, from simple chat messages to complex server management commands. In this tutorial, we will create a basic Rock-Paper-Scissors command handler that allows players to play the game against the server.
Pumpkin has its own system for handling commands, which is based around each command having a 'tree', which defines the exact structure of the command and its arguments. Each node in the tree represents a command or argument, and the tree is traversed to determine the command to execute and its parameters. Pumpkin has its own system for handling commands, which is based around each command having a 'tree', which defines the exact structure of the command and its arguments. Each node in the tree represents a command or argument, and the tree is traversed to determine the command to execute and its parameters.
@ -8,7 +9,8 @@ Commands in Pumpkin are asynchronous, meaning that they do not block the main th
We would also like to thank [ploxxxy](https://github.com/ploxxxy) for writing the original [Rock-Paper-Scissors plugin](https://github.com/ploxxxy/rock-paper-scissors-mc) from which this tutorial is based. We would also like to thank [ploxxxy](https://github.com/ploxxxy) for writing the original [Rock-Paper-Scissors plugin](https://github.com/ploxxxy/rock-paper-scissors-mc) from which this tutorial is based.
## Adding the basics ## Adding the basics
Each command in Pumpkin is defined as a structure that implements the `CommandExecutor` trait. This trait requires the implementation of a `execute` method, which takes the sender, server, and consumed arguments as parameters, and returns a ` -> Result<(), CommandError>`. Let's define this structure now:
Each command in Pumpkin is defined as a structure that implements the `CommandExecutor` trait. This trait requires the implementation of a `execute` method, which takes the sender, server, and consumed arguments as parameters, and returns a `-> Result<(), CommandError>`. Let's define this structure now:
```rs ```rs
use pumpkin::{ use pumpkin::{
@ -38,6 +40,7 @@ impl CommandExecutor for RockPaperScissorsExecutor {
This code defines an empty structure `RockPaperScissorsExecutor` that implements the `CommandExecutor` trait. The `execute` method is defined to return `Ok(())` when called. This code defines an empty structure `RockPaperScissorsExecutor` that implements the `CommandExecutor` trait. The `execute` method is defined to return `Ok(())` when called.
## Adding helper enums ## Adding helper enums
To make our lives easier, we will also define a couple of enums to represent the possible choices and outcomes of the game, as well as well as a couple functions to generate random choices and check the outcome. Add these to your plugin's code. To make our lives easier, we will also define a couple of enums to represent the possible choices and outcomes of the game, as well as well as a couple functions to generate random choices and check the outcome. Add these to your plugin's code.
```rs ```rs
@ -103,6 +106,7 @@ impl CommandExecutor for RockPaperScissorsExecutor {
This code will allow us to later pass in the player's choice and use it in the game logic, as well as compare it with the computer's choice to determine the outcome of the game. This code will allow us to later pass in the player's choice and use it in the game logic, as well as compare it with the computer's choice to determine the outcome of the game.
## Implementing the Game Logic ## Implementing the Game Logic
Now we can move on to actually implementing the game logic, and showing the outcome to the players. Now we can move on to actually implementing the game logic, and showing the outcome to the players.
First we will show the player their and the computer's choice. Add this code to your plugin: First we will show the player their and the computer's choice. Add this code to your plugin:
@ -181,6 +185,7 @@ impl CommandExecutor for RockPaperScissorsExecutor {
And that's it! The core logic is done. Now we only have one last thing to do. And that's it! The core logic is done. Now we only have one last thing to do.
## Building and registering a command tree ## Building and registering a command tree
As stated earlier, we need to build a command tree and register it with the server. This will allow players to execute our plugin's commands. As stated earlier, we need to build a command tree and register it with the server. This will allow players to execute our plugin's commands.
Building a command tree isn't very hard, but you have to know the exact structure of the command and its arguments. In this case, we have a command named `rock-paper-scissors`, which will take one required argument (the player's choice). Building a command tree isn't very hard, but you have to know the exact structure of the command and its arguments. In this case, we have a command named `rock-paper-scissors`, which will take one required argument (the player's choice).
@ -216,6 +221,6 @@ async fn on_load(&mut self, server: &Context) -> Result<(), String> {
And that's it! If you compile the plugin, you can test it by running the following command: And that's it! If you compile the plugin, you can test it by running the following command:
``` ```bash
/rps rock /rps rock
``` ```

View File

@ -1,6 +1,6 @@
### Common Issues # Common Issues
1. ### Failed to verify username 1. ## Failed to verify username
**Issue:** Some players reported having issues logging into the server, including encountering a "Failed to verify username" error. **Issue:** Some players reported having issues logging into the server, including encountering a "Failed to verify username" error.

View File

@ -7,7 +7,7 @@ Hier worden veelvoorkomende Minecraft-servers vergeleken met Pumpkin.
> Het is ook belangrijk om te overwegen dat andere servers jaren hebben gehad voor optimalisatie. > Het is ook belangrijk om te overwegen dat andere servers jaren hebben gehad voor optimalisatie.
> Vanilla forks, die de volledige vanilla-logica niet hoeven te herschrijven, kunnen zich uitsluitend richten op optimalisaties. > Vanilla forks, die de volledige vanilla-logica niet hoeven te herschrijven, kunnen zich uitsluitend richten op optimalisaties.
![Screenshot From 2024-10-15 16-42-53](https://github.com/user-attachments/assets/e08fbb00-42fe-4479-a03b-11bb6886c91a) ![A screenshot showing 9 Minecraft game windows](https://github.com/user-attachments/assets/e08fbb00-42fe-4479-a03b-11bb6886c91a)
## Specificaties ## Specificaties

View File

@ -39,10 +39,12 @@ You can also can see all the information the Packets have, which we can either W
#[derive(Serialize)] #[derive(Serialize)]
``` ```
2. Next, you have set the packet using the client_packet macro, This uses the Packet ID automatically sets the Packet ID from the JSON packets file 2. Next, you have set the packet using the packet macro
```rust ```rust
#[client_packet("play:disconnect")] use pumpkin_data::packet::clientbound::PLAY_DISCONNECT;
#[packet(PLAY_DISCONNECT)]
``` ```
3. Now you can create the Struct. 3. Now you can create the Struct.
@ -85,7 +87,7 @@ impl CPlayDisconnect {
```rust ```rust
#[derive(Serialize)] #[derive(Serialize)]
#[client_packet("play:disconnect")] #[packet(PLAY_DISCONNECT)]
pub struct CPlayDisconnect { pub struct CPlayDisconnect {
reason: TextComponent, reason: TextComponent,
} }
@ -112,11 +114,13 @@ impl CPlayDisconnect {
### Adding a Serverbound Packet ### Adding a Serverbound Packet
1. Adding a Packet is easy. First, you have to derive serde Deserialize for packets. You should also use the `server_packet` macro to automatically parse the Packet ID 1. Adding a Packet is easy. First, you have to derive serde Deserialize for packets.
```rust ```rust
use pumpkin_data::packet::serverbound::PLAY_MOVE_PLAYER_POS;
#[derive(Deserialize)] #[derive(Deserialize)]
#[server_packet("login:move_player_pos")] #[packet(PLAY_MOVE_PLAYER_POS)]
``` ```
2. Now you can create the Struct. 2. Now you can create the Struct.
@ -145,7 +149,7 @@ pub struct SPlayerPosition {
```rust ```rust
#[derive(Deserialize)] #[derive(Deserialize)]
#[server_packet("login:move_player_pos")] #[packet(PLAY_MOVE_PLAYER_POS)]
pub struct SPlayerPosition { pub struct SPlayerPosition {
pub x: f64, pub x: f64,
pub feet_y: f64, pub feet_y: f64,

View File

@ -7,7 +7,7 @@ Aqui, softwares de servidores Minecraft comuns são comparados com o Pumpkin.
> Também é importante considerar que outros servidores tiveram anos para otimizar. > Também é importante considerar que outros servidores tiveram anos para otimizar.
> Forks do Vanilla, que não precisam reescrever toda a lógica do Vanilla, podem se concentrar exclusivamente em otimizações. > Forks do Vanilla, que não precisam reescrever toda a lógica do Vanilla, podem se concentrar exclusivamente em otimizações.
![Screenshot From 2024-10-15 16-42-53](https://github.com/user-attachments/assets/e08fbb00-42fe-4479-a03b-11bb6886c91a) ![A screenshot showing 9 Minecraft game windows](https://github.com/user-attachments/assets/e08fbb00-42fe-4479-a03b-11bb6886c91a)
## Especificações ## Especificações

View File

@ -45,11 +45,9 @@ Você pode encontrar todos os pacotes do Minecraft Java em [Minecraft Wiki](http
2. Em seguida, você deve deixar claro que sua struct representa um pacote. Isso automaticamente obterá o ID do pacote do arquivo JSON de pacotes. 2. Em seguida, você deve deixar claro que sua struct representa um pacote. Isso automaticamente obterá o ID do pacote do arquivo JSON de pacotes.
```rust ```rust
// Para pacotes clientbound: use pumpkin_data::packet::clientbound::PLAY_DISCONNECT;
#[client_packet("play:disconnect")]
// Para pacotes serverbound: #[packet(PLAY_DISCONNECT)]
#[server_packet("login:move_player_pos")]
``` ```
3. Agora você pode criar a `struct`. 3. Agora você pode criar a `struct`.
@ -97,7 +95,7 @@ impl CPlayDisconnect {
```rust ```rust
#[derive(Serialize)] #[derive(Serialize)]
#[client_packet("play:disconnect")] #[packet(PLAY_DISCONNECT)]
pub struct CPlayDisconnect { pub struct CPlayDisconnect {
reason: TextComponent, reason: TextComponent,
} }
@ -109,7 +107,7 @@ impl CPlayDisconnect {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
#[server_packet("login:move_player_pos")] #[packet(PLAY_MOVE_PLAYER_POS)]
pub struct SPlayerPosition { pub struct SPlayerPosition {
pub x: f64, pub x: f64,
pub feet_y: f64, pub feet_y: f64,

View File

@ -7,7 +7,7 @@
> 同时也要考虑到其他服务器已经有多年的优化经验。 > 同时也要考虑到其他服务器已经有多年的优化经验。
> 原版分支不需要重写整个原版逻辑,可以专注于优化。 > 原版分支不需要重写整个原版逻辑,可以专注于优化。
![Screenshot From 2024-10-15 16-42-53](https://github.com/user-attachments/assets/e08fbb00-42fe-4479-a03b-11bb6886c91a) ![A screenshot showing 9 Minecraft game windows](https://github.com/user-attachments/assets/e08fbb00-42fe-4479-a03b-11bb6886c91a)
## 规格 ## 规格

View File

@ -1,13 +1,17 @@
### 为 Pumpkin 做贡献 ### 为 Pumpkin 做贡献
我们感谢您对 Pumpkin 贡献的兴趣!本文档概述了提交错误报告、功能建议和代码更改的指南。 我们感谢您对 Pumpkin 贡献的兴趣!本文档概述了提交错误报告、功能建议和代码更改的指南。
### 入门 ### 入门
最简单的入门方式是在[我们的 Discord 服务器](https://discord.gg/wT8XjrjKkf)上寻求帮助。 最简单的入门方式是在[我们的 Discord 服务器](https://discord.gg/wT8XjrjKkf)上寻求帮助。
### 如何贡献 ### 如何贡献
您可以通过以下几种方式为 Pumpkin 做贡献: 您可以通过以下几种方式为 Pumpkin 做贡献:
#### 报告错误 #### 报告错误
如果您遇到错误,请先在 issue tracker 上搜索现有问题。 如果您遇到错误,请先在 issue tracker 上搜索现有问题。
如果找不到重复的 issue,请创建一个新 issue。 如果找不到重复的 issue,请创建一个新 issue。
@ -16,11 +20,13 @@
屏幕截图、日志或代码片段也会有所帮助。 屏幕截图、日志或代码片段也会有所帮助。
#### 建议功能 #### 建议功能
您对如何改进 Pumpkin 有想法吗?通过在问题跟踪器上打开一个问题来分享您的想法。 您对如何改进 Pumpkin 有想法吗?通过在问题跟踪器上打开一个问题来分享您的想法。
详细描述所提议的功能,包括其好处和潜在的实现考虑。 详细描述所提议的功能,包括其好处和潜在的实现考虑。
#### 贡献代码 #### 贡献代码
要开始为 Pumpkin 贡献代码,请在 GitHub 上 fork 仓库 要开始为 Pumpkin 贡献代码,请在 GitHub 上 fork 仓库
1. 首先,如果您还没有 GitHub 账户,请创建一个 1. 首先,如果您还没有 GitHub 账户,请创建一个
@ -46,16 +52,20 @@
- 如果您想为文档做贡献,请安装 [NodeJS](https://nodejs.org/en) - 如果您想为文档做贡献,请安装 [NodeJS](https://nodejs.org/en)
### 反编译 Minecraft 代码 ### 反编译 Minecraft 代码
在 Pumpkin 工作时,我们严重依赖官方 Minecraft 客户端并利用现有的服务器逻辑。我们经常参考 Minecraft 的官方代码。 在 Pumpkin 工作时,我们严重依赖官方 Minecraft 客户端并利用现有的服务器逻辑。我们经常参考 Minecraft 的官方代码。
反编译 Minecraft 最简单的方法是使用 Fabric Yarn。在运行以下命令之前,请确保已安装 Gradle: 反编译 Minecraft 最简单的方法是使用 Fabric Yarn。在运行以下命令之前,请确保已安装 Gradle:
``` ```
git clone https://github.com/FabricMC/yarn.git git clone https://github.com/FabricMC/yarn.git
cd yarn cd yarn
./gradlew decompileVineflower ./gradlew decompileVineflower
``` ```
反编译后,您可以在 `build/namedSrc` 目录中找到源代码。 反编译后,您可以在 `build/namedSrc` 目录中找到源代码。
### 其他信息 ### 其他信息
我们鼓励您对现有 issue 和拉取请求发表评论,分享您的想法并提供反馈。 我们鼓励您对现有 issue 和拉取请求发表评论,分享您的想法并提供反馈。
如果您需要帮助,请随时在问题跟踪器中提问或联系项目维护者。 如果您需要帮助,请随时在问题跟踪器中提问或联系项目维护者。

View File

@ -5,4 +5,5 @@
无论您是 Pumpkin 内部开发者还是正在开发 Pumpkin 插件,本文档都是您了解 Pumpkin 所有内容的资源。 无论您是 Pumpkin 内部开发者还是正在开发 Pumpkin 插件,本文档都是您了解 Pumpkin 所有内容的资源。
#### 插件开发 #### 插件开发
为了更好的文档结构,插件开发文档已移至[单独的分类](/plugin-dev/introduction)。 为了更好的文档结构,插件开发文档已移至[单独的分类](/plugin-dev/introduction)。

View File

@ -8,17 +8,20 @@
下载适合您设备架构的 apk 文件并安装 Termux。 下载适合您设备架构的 apk 文件并安装 Termux。
安装后,您需要运行一些命令。我们使用 Helix 是因为它简单易用。 安装后,您需要运行一些命令。我们使用 Helix 是因为它简单易用。
```bash ```bash
pkg update && pkg upgrade pkg update && pkg upgrade
pkg install build-essential git rust rust-analyzer taplo helix helix-grammar nodejs pkg install build-essential git rust rust-analyzer taplo helix helix-grammar nodejs
``` ```
如果您想贡献代码,您需要安装 GitHub 软件。 如果您想贡献代码,您需要安装 GitHub 软件。
```bash ```bash
pkg install gh pkg install gh
``` ```
我们还推荐安装 fish shell,因为它比 bash 更友好。 我们还推荐安装 fish shell,因为它比 bash 更友好。
```bash ```bash
pkg install fish pkg install fish
chsh -s fish chsh -s fish
@ -26,6 +29,7 @@
现在您已经安装了基本工具,我们需要进行一些设置。 现在您已经安装了基本工具,我们需要进行一些设置。
如果您想贡献代码,您需要登录 GitHub。 如果您想贡献代码,您需要登录 GitHub。
```bash ```bash
gh auth login gh auth login
``` ```
@ -33,6 +37,7 @@
还要设置 git:更改编辑器为 vim,编辑您的凭据等。 还要设置 git:更改编辑器为 vim,编辑您的凭据等。
之后,您需要克隆 Pumpkin 仓库。(在此之前,您可以使用 `mkdir proj` 创建一个项目目录;这很有用) 之后,您需要克隆 Pumpkin 仓库。(在此之前,您可以使用 `mkdir proj` 创建一个项目目录;这很有用)
```bash ```bash
git clone https://github.com/Pumpkin-MC/Pumpkin.git git clone https://github.com/Pumpkin-MC/Pumpkin.git
``` ```
@ -44,26 +49,33 @@
# 常见问题 # 常见问题
## 如何使用文本编辑器? ## 如何使用文本编辑器?
输入 `hx <路径>`。 输入 `hx <路径>`。
## 如何浏览项目? ## 如何浏览项目?
您可以使用 `ls`、`cd` 和其他程序。 您可以使用 `ls`、`cd` 和其他程序。
您也可以使用 `hx <目录>` 在启动时浏览目录。 您也可以使用 `hx <目录>` 在启动时浏览目录。
## 如何在编辑器中输入? ## 如何在编辑器中输入?
如果您处于普通模式,请按 `i`。 如果您处于普通模式,请按 `i`。
## 如何退出编辑器???? ## 如何退出编辑器????
按 esc,然后如果您不想保存,输入 `:q!`;如果想保存,输入 `:wq`。 按 esc,然后如果您不想保存,输入 `:q!`;如果想保存,输入 `:wq`。
## 在哪里可以学习如何使用这个编辑器? ## 在哪里可以学习如何使用这个编辑器?
运行 `hx --tutor` 或访问他们的官方网站。 运行 `hx --tutor` 或访问他们的官方网站。
## 为什么不使用 VS Code? ## 为什么不使用 VS Code?
1) VS Code 设置困难,且在网页版上功能有限。 1) VS Code 设置困难,且在网页版上功能有限。
2) rust-analyzer 在其上不工作。也许模拟器可以解决这个问题,但那会减慢代码编译速度。 2) rust-analyzer 在其上不工作。也许模拟器可以解决这个问题,但那会减慢代码编译速度。
3) 使用 VS Code 强烈建议使用鼠标,而在 Helix 中您只需要键盘。 3) 使用 VS Code 强烈建议使用鼠标,而在 Helix 中您只需要键盘。
4) VS Code 在某些设备上运行缓慢。 4) VS Code 在某些设备上运行缓慢。
## 为什么输入这么困难? ## 为什么输入这么困难?
购买一个便宜的蓝牙键盘,看看事情会变得多么简单。 购买一个便宜的蓝牙键盘,看看事情会变得多么简单。

View File

@ -1,11 +1,15 @@
## 身份验证 ## 身份验证
### 为什么需要身份验证 ### 为什么需要身份验证
离线账户,即从玩家用户名生成而不联系授权或身份验证服务器的账户,可以选择任何昵称。在没有额外插件的情况下,这意味着玩家可以冒充其他玩家,包括那些拥有操作员权限的玩家。 离线账户,即从玩家用户名生成而不联系授权或身份验证服务器的账户,可以选择任何昵称。在没有额外插件的情况下,这意味着玩家可以冒充其他玩家,包括那些拥有操作员权限的玩家。
### 离线服务器 ### 离线服务器
默认情况下,配置中启用了 `online_mode`。这启用了身份验证,禁用离线账户。如果您想允许离线账户,可以在 `configuration.toml` 中禁用 `online_mode`。 默认情况下,配置中启用了 `online_mode`。这启用了身份验证,禁用离线账户。如果您想允许离线账户,可以在 `configuration.toml` 中禁用 `online_mode`。
### Yggdrasil 身份验证的工作原理 ### Yggdrasil 身份验证的工作原理
1. 客户端从启动器获取身份验证令牌和 UUID。 1. 客户端从启动器获取身份验证令牌和 UUID。
2. 客户端在加载过程中,使用身份验证令牌从授权/身份验证服务器获取数据,如各种签名密钥和被阻止服务器的列表。 2. 客户端在加载过程中,使用身份验证令牌从授权/身份验证服务器获取数据,如各种签名密钥和被阻止服务器的列表。
3. 客户端在加入服务器时,向授权/身份验证服务器发送加入请求。如果账户被封禁,Mojang 服务器可以拒绝此请求。 3. 客户端在加入服务器时,向授权/身份验证服务器发送加入请求。如果账户被封禁,Mojang 服务器可以拒绝此请求。

View File

@ -28,7 +28,7 @@ Pumpkin 协议中的数据包按功能和状态组织。
### Minecraft 协议 ### Minecraft 协议
您可以在 https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol 找到所有 Minecraft Java 数据包。在那里,您还可以看到它们处于哪个[状态](#状态)。 您可以在 <https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol> 找到所有 Minecraft Java 数据包。在那里,您还可以看到它们处于哪个[状态](#状态)。
您还可以看到数据包的所有信息,根据它们是服务器绑定还是客户端绑定,我们可以读取或写入这些信息。 您还可以看到数据包的所有信息,根据它们是服务器绑定还是客户端绑定,我们可以读取或写入这些信息。
### 添加数据包 ### 添加数据包
@ -46,11 +46,9 @@ Pumpkin 协议中的数据包按功能和状态组织。
2. 接下来,您必须让系统知道您的结构表示一个数据包。这会自动从 JSON 数据包文件中获取数据包 ID。 2. 接下来,您必须让系统知道您的结构表示一个数据包。这会自动从 JSON 数据包文件中获取数据包 ID。
```rust ```rust
// 对于客户端绑定数据包: use pumpkin_data::packet::clientbound::PLAY_DISCONNECT;
#[client_packet("play:disconnect")]
// 对于服务器绑定数据包: #[packet(PLAY_DISCONNECT)]
#[server_packet("login:move_player_pos")]
``` ```
3. 现在您可以创建 `struct`。 3. 现在您可以创建 `struct`。
@ -59,9 +57,9 @@ Pumpkin 协议中的数据包按功能和状态组织。
> 请以 "C" 或 "S" 开始数据包名称,分别代表"客户端绑定"或"服务器绑定"。 > 请以 "C" 或 "S" 开始数据包名称,分别代表"客户端绑定"或"服务器绑定"。
> 此外,如果这是一个可以在多个[状态](#状态)下发送的数据包,请将状态添加到名称中。例如,有 3 个不同的断开连接数据包。 > 此外,如果这是一个可以在多个[状态](#状态)下发送的数据包,请将状态添加到名称中。例如,有 3 个不同的断开连接数据包。
> >
> - `CLoginDisconnect` > - `CLoginDisconnect`
> - `CConfigDisconnect` > - `CConfigDisconnect`
> - `CPlayDisconnect` > - `CPlayDisconnect`
在您的数据包结构中创建字段,以表示将要发送的数据。 在您的数据包结构中创建字段,以表示将要发送的数据。
@ -98,7 +96,7 @@ impl CPlayDisconnect {
```rust ```rust
#[derive(Serialize)] #[derive(Serialize)]
#[client_packet("play:disconnect")] #[packet(PLAY_DISCONNECT)]
pub struct CPlayDisconnect { pub struct CPlayDisconnect {
reason: TextComponent, reason: TextComponent,
} }
@ -110,7 +108,7 @@ impl CPlayDisconnect {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
#[server_packet("login:move_player_pos")] #[packet(PLAY_MOVE_PLAYER_POS)]
pub struct SPlayerPosition { pub struct SPlayerPosition {
pub x: f64, pub x: f64,
pub feet_y: f64, pub feet_y: f64,
@ -150,15 +148,15 @@ Pumpkin 将 `Client`(客户端)和 `Player`(玩家)分开分类。不在
**客户端** **客户端**
- 只能处于状态:Status、Login、Transfer、Config - 只能处于状态:Status、Login、Transfer、Config
- 不是活动实体 - 不是活动实体
- 资源消耗小 - 资源消耗小
**玩家** **玩家**
- 只能处于 Play 状态 - 只能处于 Play 状态
- 是世界中的一个活动实体 - 是世界中的一个活动实体
- 有更多数据并消耗更多资源 - 有更多数据并消耗更多资源
#### 发送数据包 #### 发送数据包

View File

@ -50,13 +50,13 @@ Minecraft Beta 1.3 到 Release 1.2 使用一种被称为"区域文件格式"的
调用 `AnvilChunkReader` 处理给定保存的区域文件 调用 `AnvilChunkReader` 处理给定保存的区域文件
- 如上所述,区域文件存储 32x32 个区块 - 如上所述,区域文件存储 32x32 个区块
> 每个区域文件的命名对应于其在世界中的坐标 > 每个区域文件的命名对应于其在世界中的坐标
> r.{}.{}.mca > r.{}.{}.mca
- 从保存文件中读取位置表,表示区块坐标 - 从保存文件中读取位置表,表示区块坐标
- 从保存文件中读取时间戳表,表示区块最后修改的时间 - 从保存文件中读取时间戳表,表示区块最后修改的时间
#### 目前没有实现存档的保存 #### 目前没有实现存档的保存
@ -64,17 +64,17 @@ Minecraft Beta 1.3 到 Release 1.2 使用一种被称为"区域文件格式"的
调用 `PlainsGenerator`,因为到目前为止 `Plains`(平原)是唯一实现的生物群系。 调用 `PlainsGenerator`,因为到目前为止 `Plains`(平原)是唯一实现的生物群系。
- 调用 `PerlinTerrainGenerator` 设置区块高度 - 调用 `PerlinTerrainGenerator` 设置区块高度
- 石头高度设置为区块高度下方 5 格 - 石头高度设置为区块高度下方 5 格
- 泥土高度设置为区块高度下方 2 格 - 泥土高度设置为区块高度下方 2 格
- 草方块出现在泥土顶部 - 草方块出现在泥土顶部
- 基岩设置在y轴-64的高度 - 基岩设置在y轴-64的高度
- 花和矮草丛随机散布 - 花和矮草丛随机散布
`SuperflatGenerator`(超平坦生成器)也可用,但目前无法调用。 `SuperflatGenerator`(超平坦生成器)也可用,但目前无法调用。
- 基岩设置在y轴-64的高度 - 基岩设置在y轴-64的高度
- 泥土设置在基岩上方2层 - 泥土设置在基岩上方2层
- 草方块在泥土上方1层 - 草方块在泥土上方1层
可以放置和破坏方块,但无法将更改保存在任何世界格式中。Anvil 的存档文件目前是只读的。 可以放置和破坏方块,但无法将更改保存在任何世界格式中。Anvil 的存档文件目前是只读的。

View File

@ -8,6 +8,7 @@
要使用 Rust 运行 Pumpkin,请确保您已安装 [Rust](https://www.rust-lang.org/tools/install)。 要使用 Rust 运行 Pumpkin,请确保您已安装 [Rust](https://www.rust-lang.org/tools/install)。
1. 克隆仓库: 1. 克隆仓库:
```shell ```shell
git clone https://github.com/Pumpkin-MC/Pumpkin.git git clone https://github.com/Pumpkin-MC/Pumpkin.git
cd Pumpkin cd Pumpkin
@ -25,6 +26,7 @@ cargo run --release
``` ```
4. **可选:** 如果您想使用 CPU 特定功能,可以设置 `target-cpu=native` Rust 编译器标志。 4. **可选:** 如果您想使用 CPU 特定功能,可以设置 `target-cpu=native` Rust 编译器标志。
```shell ```shell
RUSTFLAGS='-C target-cpu=native' cargo run --release RUSTFLAGS='-C target-cpu=native' cargo run --release
``` ```
@ -49,6 +51,7 @@ docker run --rm \
### 示例 ### 示例
要在端口 `25565` 上运行 Pumpkin 并将数据存储在名为 `./data` 的目录中,您可以运行以下命令: 要在端口 `25565` 上运行 Pumpkin 并将数据存储在名为 `./data` 的目录中,您可以运行以下命令:
```shell ```shell
docker run --rm \ docker run --rm \
-p 25565:25565 \ -p 25565:25565 \
@ -57,11 +60,13 @@ docker run --rm \
``` ```
## 测试服务器 ## 测试服务器
Pumpkin 有一个由 @kralverde 维护的测试服务器。它运行在 Pumpkin master 分支的最新提交上。 Pumpkin 有一个由 @kralverde 维护的测试服务器。它运行在 Pumpkin master 分支的最新提交上。
- **IP:** pumpkin.kralverde.dev - **IP:** pumpkin.kralverde.dev
**配置:** **配置:**
- 操作系统: Debian GNU/Linux bookworm 12.7 x86_64 - 操作系统: Debian GNU/Linux bookworm 12.7 x86_64
- 内核: Linux 6.1.0-21-cloud-amd64 - 内核: Linux 6.1.0-21-cloud-amd64
- CPU: Intel Core (Haswell, no TSX) (2) @ 2.40 GHz - CPU: Intel Core (Haswell, no TSX) (2) @ 2.40 GHz

View File

@ -1,4 +1,5 @@
# Pumpkin 插件开发 # Pumpkin 插件开发
::: warning ::: warning
Pumpkin 插件API仍处于非常早期的开发阶段,可能随时会发生变化。 Pumpkin 插件API仍处于非常早期的开发阶段,可能随时会发生变化。
如果您遇到任何问题,请在[我们的Discord服务器](https://discord.gg/aaNuD6rFEe)上联系我们。 如果您遇到任何问题,请在[我们的Discord服务器](https://discord.gg/aaNuD6rFEe)上联系我们。

View File

@ -1,8 +1,11 @@
# 编写基本逻辑 # 编写基本逻辑
## 插件基础 ## 插件基础
即使在一个基本插件中,底层也有很多工作,因此为了大大简化插件开发,我们将使用`pumpkin-api-macros` crate来创建一个基本的空插件。 即使在一个基本插件中,底层也有很多工作,因此为了大大简化插件开发,我们将使用`pumpkin-api-macros` crate来创建一个基本的空插件。
:::code-group :::code-group
```rs:line-numbers [lib.rs] ```rs:line-numbers [lib.rs]
use pumpkin_api_macros::plugin_impl; use pumpkin_api_macros::plugin_impl;
@ -21,20 +24,24 @@ impl Default for MyPlugin {
} }
} }
``` ```
::: :::
这将创建一个空插件并实现所有必要的方法,使其能够被 Pumpkin 加载。 这将创建一个空插件并实现所有必要的方法,使其能够被 Pumpkin 加载。
现在我们可以尝试首次编译我们的插件。为此,在项目文件夹中运行以下命令: 现在我们可以尝试首次编译我们的插件。为此,在项目文件夹中运行以下命令:
```bash ```bash
cargo build --release cargo build --release
``` ```
::: tip 注意 ::: tip 注意
如果您使用的是Windows,您**必须**使用`--release`标志,否则会遇到问题。如果您使用的是其他平台,为了节省编译时间,可以不使用该标志。 如果您使用的是Windows,您**必须**使用`--release`标志,否则会遇到问题。如果您使用的是其他平台,为了节省编译时间,可以不使用该标志。
::: :::
初始编译会花费一些时间,但不用担心,后续编译会更快。 初始编译会花费一些时间,但不用担心,后续编译会更快。
如果一切顺利,您应该会看到类似这样的消息: 如果一切顺利,您应该会看到类似这样的消息:
```log ```log
╰─ cargo build --release ╰─ cargo build --release
Compiling hello-pumpkin v0.1.0 (/home/vypal/Dokumenty/GitHub/hello-pumpkin) Compiling hello-pumpkin v0.1.0 (/home/vypal/Dokumenty/GitHub/hello-pumpkin)
@ -44,6 +51,7 @@ cargo build --release
现在您可以前往`./target/release`文件夹(如果您没有使用`--release`,则为`./target/debug`)并找到您的插件二进制文件。 现在您可以前往`./target/release`文件夹(如果您没有使用`--release`,则为`./target/debug`)并找到您的插件二进制文件。
根据您的操作系统,文件名称可能是以下三种之一: 根据您的操作系统,文件名称可能是以下三种之一:
- Windows:`hello-pumpkin.dll` - Windows:`hello-pumpkin.dll`
- MacOS:`libhello-pumpkin.dylib` - MacOS:`libhello-pumpkin.dylib`
- Linux:`libhello-pumpkin.so` - Linux:`libhello-pumpkin.so`
@ -55,23 +63,27 @@ cargo build --release
您可以将此文件重命名为任何您喜欢的名称,但必须保持文件扩展名(`.dll`、`.dylib`或`.so`)不变。 您可以将此文件重命名为任何您喜欢的名称,但必须保持文件扩展名(`.dll`、`.dylib`或`.so`)不变。
## 测试插件 ## 测试插件
现在我们有了插件二进制文件,我们可以在 Pumpkin 服务器上进行测试。安装插件非常简单,只需将我们刚刚构建的插件二进制文件放入 Pumpkin 服务器的`plugins/`文件夹中! 现在我们有了插件二进制文件,我们可以在 Pumpkin 服务器上进行测试。安装插件非常简单,只需将我们刚刚构建的插件二进制文件放入 Pumpkin 服务器的`plugins/`文件夹中!
由于`#[plugin_impl]`宏的作用,插件的详细信息(如名称、作者、版本和描述)会内置在二进制文件中,以便服务器能够读取它们。 由于`#[plugin_impl]`宏的作用,插件的详细信息(如名称、作者、版本和描述)会内置在二进制文件中,以便服务器能够读取它们。
当您启动服务器并运行`/plugins`命令时,您应该会看到类似这样的输出: 当您启动服务器并运行`/plugins`命令时,您应该会看到类似这样的输出:
```
```bash
已加载1个插件: 已加载1个插件:
hello-pumpkin hello-pumpkin
``` ```
## 基本方法 ## 基本方法
Pumpkin 服务器目前使用两个"方法"来告知插件其状态。这些方法是`on_load`和`on_unload`。 Pumpkin 服务器目前使用两个"方法"来告知插件其状态。这些方法是`on_load`和`on_unload`。
这些方法不是必须实现的,但您通常至少会实现`on_load`方法。在此方法中,您可以访问一个`Context`对象,该对象可以让插件访问有关服务器的信息,同时也允许插件注册命令处理器和事件。 这些方法不是必须实现的,但您通常至少会实现`on_load`方法。在此方法中,您可以访问一个`Context`对象,该对象可以让插件访问有关服务器的信息,同时也允许插件注册命令处理器和事件。
为了使实现这些方法更容易,`pumpkin-api-macros` crate提供了另一个宏。 为了使实现这些方法更容易,`pumpkin-api-macros` crate提供了另一个宏。
:::code-group :::code-group
```rs [lib.rs] ```rs [lib.rs]
use pumpkin_api_macros::{plugin_impl, plugin_method}; // [!code ++:2] use pumpkin_api_macros::{plugin_impl, plugin_method}; // [!code ++:2]
use pumpkin::plugin::Context; use pumpkin::plugin::Context;
@ -97,6 +109,7 @@ impl Default for MyPlugin {
} }
} }
``` ```
::: :::
::: warning 重要 ::: warning 重要
@ -105,32 +118,42 @@ impl Default for MyPlugin {
此方法获取对其插件对象(在本例中为`MyPlugin`结构)的可变引用,可用于初始化存储在插件主结构中的任何数据,以及对`Context`对象的引用。该对象是根据插件的元数据专门为该插件构建的。 此方法获取对其插件对象(在本例中为`MyPlugin`结构)的可变引用,可用于初始化存储在插件主结构中的任何数据,以及对`Context`对象的引用。该对象是根据插件的元数据专门为该插件构建的。
### `Context`对象上实现的方法: ### `Context`对象上实现的方法
```rs ```rs
fn get_data_folder() -> String fn get_data_folder() -> String
``` ```
返回专用于此插件的文件夹路径,应用于持久数据存储 返回专用于此插件的文件夹路径,应用于持久数据存储
```rs ```rs
async fn get_player_by_name(player_name: String) -> Option<Arc<Player>> async fn get_player_by_name(player_name: String) -> Option<Arc<Player>>
``` ```
如果找到名为`player_name`的玩家(必须当前在线),此函数将返回对该玩家的引用。 如果找到名为`player_name`的玩家(必须当前在线),此函数将返回对该玩家的引用。
```rs ```rs
async fn register_command(tree: CommandTree, permission: PermissionLvl) async fn register_command(tree: CommandTree, permission: PermissionLvl)
``` ```
注册一个新的命令处理器,具有最低所需权限级别。 注册一个新的命令处理器,具有最低所需权限级别。
```rs ```rs
async fn register_event(handler: Arc<H>, priority: EventPriority, blocking: bool) async fn register_event(handler: Arc<H>, priority: EventPriority, blocking: bool)
``` ```
注册一个新的事件处理器,具有设定的优先级,并指定是否为阻塞。 注册一个新的事件处理器,具有设定的优先级,并指定是否为阻塞。
顺便说一下,`handler`是`Arc<T>`,这意味着您可以在一个处理器上实现多个事件,然后注册它。 顺便说一下,`handler`是`Arc<T>`,这意味着您可以在一个处理器上实现多个事件,然后注册它。
## 基本on-load方法 ## 基本on-load方法
现在我们将只实现一个非常基本的`on_load`方法,以便能够看到我们的插件正在运行。 现在我们将只实现一个非常基本的`on_load`方法,以便能够看到我们的插件正在运行。
在这里,我们将设置内部 Pumpkin 日志记录器,并设置一个"Hello, Pumpkin !"消息,以便我们能够看到我们的插件正在运行。 在这里,我们将设置内部 Pumpkin 日志记录器,并设置一个"Hello, Pumpkin !"消息,以便我们能够看到我们的插件正在运行。
在`on_load`方法中添加以下内容: 在`on_load`方法中添加以下内容:
:::code-group :::code-group
```rs [lib.rs] ```rs [lib.rs]
#[plugin_method] #[plugin_method]
async fn on_load(&mut self, server: &Context) -> Result<(), String> { async fn on_load(&mut self, server: &Context) -> Result<(), String> {
@ -141,6 +164,7 @@ async fn on_load(&mut self, server: &Context) -> Result<(), String> {
Ok(()) Ok(())
} }
``` ```
::: :::
如果我们再次构建插件并启动服务器,您现在应该能在日志中看到"你好, Pumpkin !"的消息。 如果我们再次构建插件并启动服务器,您现在应该能在日志中看到"你好, Pumpkin !"的消息。

View File

@ -1,23 +1,30 @@
# 创建新项目 # 创建新项目
Pumpkin 插件使用[Cargo](https://doc.rust-lang.org/book/ch01-03-hello-cargo.html)构建系统。 Pumpkin 插件使用[Cargo](https://doc.rust-lang.org/book/ch01-03-hello-cargo.html)构建系统。
此插件的完整代码可以在[GitHub上的模板](https://github.com/vyPal/Hello-Pumpkin)中找到。 此插件的完整代码可以在[GitHub上的模板](https://github.com/vyPal/Hello-Pumpkin)中找到。
## 初始化新的crate ## 初始化新的crate
首先我们需要创建一个新的项目文件夹。您可以通过在您创建的文件夹中运行以下命令来完成: 首先我们需要创建一个新的项目文件夹。您可以通过在您创建的文件夹中运行以下命令来完成:
```bash ```bash
cargo new <项目名称> --lib cargo new <项目名称> --lib
``` ```
这将创建一个包含几个文件的文件夹。文件夹结构应该如下所示: 这将创建一个包含几个文件的文件夹。文件夹结构应该如下所示:
```
```bash
├── Cargo.toml ├── Cargo.toml
└── src └── src
└── lib.rs └── lib.rs
``` ```
## 配置crate ## 配置crate
由于 Pumpkin 插件在运行时作为动态库加载,我们需要告诉Cargo将此crate构建为动态库。 由于 Pumpkin 插件在运行时作为动态库加载,我们需要告诉Cargo将此crate构建为动态库。
:::code-group :::code-group
```toml [Cargo.toml] ```toml [Cargo.toml]
[package] [package]
name = "hello-pumpkin" name = "hello-pumpkin"
@ -29,10 +36,12 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
``` ```
::: :::
接下来我们需要添加一些基本依赖项。由于 Pumpkin 仍处于早期开发阶段,内部crate尚未发布到crates.io,所以我们需要告诉Cargo直接从GitHub下载依赖项。 接下来我们需要添加一些基本依赖项。由于 Pumpkin 仍处于早期开发阶段,内部crate尚未发布到crates.io,所以我们需要告诉Cargo直接从GitHub下载依赖项。
:::code-group :::code-group
```toml [Cargo.toml] ```toml [Cargo.toml]
[package] [package]
name = "hello-pumpkin" name = "hello-pumpkin"
@ -58,14 +67,17 @@ tokio = "1.42"
# 日志记录 # 日志记录
log = "0.4" log = "0.4"
``` ```
::: :::
为了提高性能和减小文件大小,我们建议启用链接时优化(Link-Time Optimization,LTO)。 为了提高性能和减小文件大小,我们建议启用链接时优化(Link-Time Optimization,LTO)。
请注意,这将增加编译时间。 请注意,这将增加编译时间。
:::code-group :::code-group
```toml [Cargo.toml] ```toml [Cargo.toml]
[profile.release] // [!code ++:2] [profile.release] // [!code ++:2]
lto = true lto = true
``` ```
::: :::
<small>建议仅对发布版本启用LTO。</small> <small>建议仅对发布版本启用LTO。</small>

View File

@ -1,9 +1,11 @@
# 编写示例插件 # 编写示例插件
本教程将指导您创建一个新的插件。 本教程将指导您创建一个新的插件。
本教程假设您具有一定的Rust和命令行使用经验。 本教程假设您具有一定的Rust和命令行使用经验。
本教程涵盖的主题: 本教程涵盖的主题:
- 修改玩家加入消息 - 修改玩家加入消息
- 创建石头-剪刀-布命令(即将推出) - 创建石头-剪刀-布命令(即将推出)
- 在插件目录中保存插件数据(即将推出) - 在插件目录中保存插件数据(即将推出)

View File

@ -1,4 +1,5 @@
# 编写事件处理器 # 编写事件处理器
事件处理器是插件的主要功能之一。它们允许插件接入服务器的内部工作并改变其行为,以执行其他操作。作为一个简单的例子,我们将实现一个`player_join`事件的处理器。 事件处理器是插件的主要功能之一。它们允许插件接入服务器的内部工作并改变其行为,以执行其他操作。作为一个简单的例子,我们将实现一个`player_join`事件的处理器。
Pumpkin 插件事件系统尝试复制Bukkit/Spigot事件系统,以便来自那里的开发者能更容易地学习 Pumpkin 。 Pumpkin 插件事件系统尝试复制Bukkit/Spigot事件系统,以便来自那里的开发者能更容易地学习 Pumpkin 。
@ -9,11 +10,15 @@ Rust没有继承;它只有组合。
Cancellable也可以是Event,因为它是一个特质。(待确认) Cancellable也可以是Event,因为它是一个特质。(待确认)
## 实现加入事件 ## 实现加入事件
单个事件处理器只是实现了`EventHandler<T>`特质的结构体(其中`T`是特定的事件实现)。 单个事件处理器只是实现了`EventHandler<T>`特质的结构体(其中`T`是特定的事件实现)。
### 什么是阻塞事件? ### 什么是阻塞事件?
Pumpkin 插件事件系统区分两种类型的事件:阻塞和非阻塞。每种都有其优势: Pumpkin 插件事件系统区分两种类型的事件:阻塞和非阻塞。每种都有其优势:
#### 阻塞事件 #### 阻塞事件
```diff ```diff
优点: 优点:
+ 可以修改事件(如编辑加入消息) + 可以修改事件(如编辑加入消息)
@ -23,7 +28,9 @@ Cancellable也可以是Event,因为它是一个特质。(待确认)
- 按顺序执行 - 按顺序执行
- 如果实现不好可能会减慢服务器速度 - 如果实现不好可能会减慢服务器速度
``` ```
#### 非阻塞事件 #### 非阻塞事件
```diff ```diff
优点: 优点:
+ 并发执行 + 并发执行
@ -36,10 +43,12 @@ Cancellable也可以是Event,因为它是一个特质。(待确认)
``` ```
### 编写处理器 ### 编写处理器
由于我们的主要目标是更改玩家加入服务器时看到的欢迎消息,我们将选择具有低优先级的阻塞事件类型。 由于我们的主要目标是更改玩家加入服务器时看到的欢迎消息,我们将选择具有低优先级的阻塞事件类型。
在`on_load`方法上方添加以下代码: 在`on_load`方法上方添加以下代码:
:::code-group :::code-group
```rs [lib.rs] ```rs [lib.rs]
use async_trait::async_trait; // [!code ++:4] use async_trait::async_trait; // [!code ++:4]
use pumpkin_api_macros::with_runtime; use pumpkin_api_macros::with_runtime;
@ -58,9 +67,11 @@ impl EventHandler<PlayerJoinEvent> for MyJoinHandler {
} }
} }
``` ```
::: :::
**解释**: **解释**:
- `struct MyJoinHandler;`:我们事件处理器的结构体 - `struct MyJoinHandler;`:我们事件处理器的结构体
- `#[with_runtime(global)]`: Pumpkin 使用 tokio 异步运行时,它在插件边界上会有奇怪的行为。虽然在这个特定例子中不是必需的,但最好用这个宏包装所有与异步代码交互的异步`impl`。 - `#[with_runtime(global)]`: Pumpkin 使用 tokio 异步运行时,它在插件边界上会有奇怪的行为。虽然在这个特定例子中不是必需的,但最好用这个宏包装所有与异步代码交互的异步`impl`。
- `#[async_trait]`:Rust对具有异步方法的特质没有完全支持。因此,我们使用`async_trait`包来实现这一点。 - `#[async_trait]`:Rust对具有异步方法的特质没有完全支持。因此,我们使用`async_trait`包来实现这一点。
@ -71,8 +82,10 @@ impl EventHandler<PlayerJoinEvent> for MyJoinHandler {
::: :::
### 注册处理器 ### 注册处理器
现在我们已经编写了事件处理器,我们需要告诉插件使用它。我们可以通过在`on_load`方法中添加一行代码来实现: 现在我们已经编写了事件处理器,我们需要告诉插件使用它。我们可以通过在`on_load`方法中添加一行代码来实现:
:::code-group :::code-group
```rs [lib.rs] ```rs [lib.rs]
use pumpkin::plugin::{player::PlayerJoinEvent, Context, EventHandler, EventPriority}; // [!code ++] use pumpkin::plugin::{player::PlayerJoinEvent, Context, EventHandler, EventPriority}; // [!code ++]
use pumpkin::plugin::{player::PlayerJoinEvent, Context, EventHandler}; // [!code --] use pumpkin::plugin::{player::PlayerJoinEvent, Context, EventHandler}; // [!code --]
@ -88,5 +101,6 @@ async fn on_load(&mut self, server: &Context) -> Result<(), String> {
Ok(()) Ok(())
} }
``` ```
::: :::
现在如果我们构建插件并加入服务器,我们应该能看到一个绿色的带有我们用户名的"欢迎"消息! 现在如果我们构建插件并加入服务器,我们应该能看到一个绿色的带有我们用户名的"欢迎"消息!

View File

@ -1,6 +1,6 @@
### 常见问题 ### 常见问题
1. ### 无法验证用户名 1. ### 无法验证用户名
**问题:** 一些玩家报告在登录服务器时遇到问题,包括遇到"无法验证用户名"的错误。 **问题:** 一些玩家报告在登录服务器时遇到问题,包括遇到"无法验证用户名"的错误。

View File

@ -6,8 +6,8 @@
"preview": "vitepress preview docs" "preview": "vitepress preview docs"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.2.19", "@types/bun": "^1.2.20",
"vitepress": "^1.6.3", "vitepress": "^1.6.4",
"vue": "^3.5.18" "vue": "^3.5.18"
} }
} }