Move Chunks things from Client to Player

Also made Chunk handling more robust
This commit is contained in:
Snowiiii 2024-10-28 22:48:17 +01:00
parent ba6f50aae0
commit e0dd8d6b61
14 changed files with 309 additions and 286 deletions

View File

@ -6,6 +6,7 @@ on:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
RUSTFLAGS: "-Dwarnings"
jobs: jobs:
format: format:
@ -15,12 +16,9 @@ jobs:
matrix: matrix:
toolchain: toolchain:
- stable - stable
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- run: cargo fmt --check - run: cargo fmt --check
clippy: clippy:
name: Run lints name: Run lints
@ -29,27 +27,21 @@ jobs:
matrix: matrix:
toolchain: toolchain:
- stable - stable
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- run: cargo clippy --all-targets --all-features --no-default-features
- run: cargo clippy --all-targets --all-features --no-default-features -- -D warnings
build_and_test: build_and_test:
name: Build project and test name: Build project and test
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
toolchain: toolchain:
- stable - stable
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- run: cargo build --verbose
- run: cargo test --verbose - run: cargo test --verbose
build_release: build_release:
name: Build project in release name: Build project in release
@ -59,12 +51,10 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest] os: [ubuntu-latest, windows-latest, macos-latest]
toolchain: toolchain:
- stable - stable
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- run: cargo build --verbose --release - run: cargo build --verbose --release
- name: Export executable - name: Export executable
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@ -79,10 +69,7 @@ jobs:
matrix: matrix:
toolchain: toolchain:
- stable - stable
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- run: cargo clippy --release --all-targets --all-features --no-default-features
- run: cargo clippy --release --all-targets --all-features --no-default-features -- -D warnings

222
package-lock.json generated
View File

@ -1,5 +1,5 @@
{ {
"name": "Pumpkin", "name": "pumpkin",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
@ -848,9 +848,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.2.tgz",
"integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", "integrity": "sha512-ufoveNTKDg9t/b7nqI3lwbCG/9IJMhADBNjjz/Jn6LxIZxD7T5L8l2uO/wD99945F1Oo8FvgbbZJRguyk/BdzA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -862,9 +862,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.2.tgz",
"integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", "integrity": "sha512-iZoYCiJz3Uek4NI0J06/ZxUgwAfNzqltK0MptPDO4OR0a88R4h0DSELMsflS6ibMCJ4PnLvq8f7O1d7WexUvIA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -876,9 +876,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.2.tgz",
"integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", "integrity": "sha512-/UhrIxobHYCBfhi5paTkUDQ0w+jckjRZDZ1kcBL132WeHZQ6+S5v9jQPVGLVrLbNUebdIRpIt00lQ+4Z7ys4Rg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -890,9 +890,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.2.tgz",
"integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", "integrity": "sha512-1F/jrfhxJtWILusgx63WeTvGTwE4vmsT9+e/z7cZLKU8sBMddwqw3UV5ERfOV+H1FuRK3YREZ46J4Gy0aP3qDA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -903,10 +903,38 @@
"darwin" "darwin"
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.2.tgz",
"integrity": "sha512-1YWOpFcGuC6iGAS4EI+o3BV2/6S0H+m9kFOIlyFtp4xIX5rjSnL3AwbTBxROX0c8yWtiWM7ZI6mEPTI7VkSpZw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.2.tgz",
"integrity": "sha512-3qAqTewYrCdnOD9Gl9yvPoAoFAVmPJsBvleabvx4bnu1Kt6DrB2OALeRVag7BdWGWLhP1yooeMLEi6r2nYSOjg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.2.tgz",
"integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", "integrity": "sha512-ArdGtPHjLqWkqQuoVQ6a5UC5ebdX8INPuJuJNWRe0RGa/YNhVvxeWmCTFQ7LdmNCSUzVZzxAvUznKaYx645Rig==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -918,9 +946,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.2.tgz",
"integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", "integrity": "sha512-B6UHHeNnnih8xH6wRKB0mOcJGvjZTww1FV59HqJoTJ5da9LCG6R4SEBt6uPqzlawv1LoEXSS0d4fBlHNWl6iYw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -932,9 +960,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.2.tgz",
"integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", "integrity": "sha512-kr3gqzczJjSAncwOS6i7fpb4dlqcvLidqrX5hpGBIM1wtt0QEVtf4wFaAwVv8QygFU8iWUMYEoJZWuWxyua4GQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -946,9 +974,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.2.tgz",
"integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", "integrity": "sha512-TDdHLKCWgPuq9vQcmyLrhg/bgbOvIQ8rtWQK7MRxJ9nvaxKx38NvY7/Lo6cYuEnNHqf6rMqnivOIPIQt6H2AoA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -960,9 +988,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.2.tgz",
"integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", "integrity": "sha512-xv9vS648T3X4AxFFZGWeB5Dou8ilsv4VVqJ0+loOIgDO20zIhYfDLkk5xoQiej2RiSQkld9ijF/fhLeonrz2mw==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -974,9 +1002,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.2.tgz",
"integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", "integrity": "sha512-tbtXwnofRoTt223WUZYiUnbxhGAOVul/3StZ947U4A5NNjnQJV5irKMm76G0LGItWs6y+SCjUn/Q0WaMLkEskg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -988,9 +1016,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.2.tgz",
"integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", "integrity": "sha512-gc97UebApwdsSNT3q79glOSPdfwgwj5ELuiyuiMY3pEWMxeVqLGKfpDFoum4ujivzxn6veUPzkGuSYoh5deQ2Q==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -1002,9 +1030,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.2.tgz",
"integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", "integrity": "sha512-jOG/0nXb3z+EM6SioY8RofqqmZ+9NKYvJ6QQaa9Mvd3RQxlH68/jcB/lpyVt4lCiqr04IyaC34NzhUqcXbB5FQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1016,9 +1044,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.2.tgz",
"integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", "integrity": "sha512-XAo7cJec80NWx9LlZFEJQxqKOMz/lX3geWs2iNT5CHIERLFfd90f3RYLLjiCBm1IMaQ4VOX/lTC9lWfzzQm14Q==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1030,9 +1058,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.2.tgz",
"integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", "integrity": "sha512-A+JAs4+EhsTjnPQvo9XY/DC0ztaws3vfqzrMNMKlwQXuniBKOIIvAAI8M0fBYiTCxQnElYu7mLk7JrhlQ+HeOw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1044,9 +1072,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.2.tgz",
"integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", "integrity": "sha512-ZhcrakbqA1SCiJRMKSU64AZcYzlZ/9M5LaYil9QWxx9vLnkQ9Vnkve17Qn4SjlipqIIBFKjBES6Zxhnvh0EAEw==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -1058,9 +1086,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.2.tgz",
"integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", "integrity": "sha512-2mLH46K1u3r6uwc95hU+OR9q/ggYMpnS7pSp83Ece1HUQgF9Nh/QwTK5rcgbFnV9j+08yBrU5sA/P0RK2MSBNA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1072,57 +1100,57 @@
] ]
}, },
"node_modules/@shikijs/core": { "node_modules/@shikijs/core": {
"version": "1.22.1", "version": "1.22.2",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.22.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.22.2.tgz",
"integrity": "sha512-bqAhT/Ri5ixV4oYsvJNH8UJjpjbINWlWyXY6tBTsP4OmD6XnFv43nRJ+lTdxd2rmG5pgam/x+zGR6kLRXrpEKA==", "integrity": "sha512-bvIQcd8BEeR1yFvOYv6HDiyta2FFVePbzeowf5pPS1avczrPK+cjmaxxh0nx5QzbON7+Sv0sQfQVciO7bN72sg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/engine-javascript": "1.22.1", "@shikijs/engine-javascript": "1.22.2",
"@shikijs/engine-oniguruma": "1.22.1", "@shikijs/engine-oniguruma": "1.22.2",
"@shikijs/types": "1.22.1", "@shikijs/types": "1.22.2",
"@shikijs/vscode-textmate": "^9.3.0", "@shikijs/vscode-textmate": "^9.3.0",
"@types/hast": "^3.0.4", "@types/hast": "^3.0.4",
"hast-util-to-html": "^9.0.3" "hast-util-to-html": "^9.0.3"
} }
}, },
"node_modules/@shikijs/engine-javascript": { "node_modules/@shikijs/engine-javascript": {
"version": "1.22.1", "version": "1.22.2",
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.22.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.22.2.tgz",
"integrity": "sha512-540pyoy0LWe4jj2BVbgELwOFu1uFvRI7lg4hdsExrSXA9x7gqfzZ/Nnh4RfX86aDAgJ647gx4TCmRwACbnQSvw==", "integrity": "sha512-iOvql09ql6m+3d1vtvP8fLCVCK7BQD1pJFmHIECsujB0V32BJ0Ab6hxk1ewVSMFA58FI0pR2Had9BKZdyQrxTw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "1.22.1", "@shikijs/types": "1.22.2",
"@shikijs/vscode-textmate": "^9.3.0", "@shikijs/vscode-textmate": "^9.3.0",
"oniguruma-to-js": "0.4.3" "oniguruma-to-js": "0.4.3"
} }
}, },
"node_modules/@shikijs/engine-oniguruma": { "node_modules/@shikijs/engine-oniguruma": {
"version": "1.22.1", "version": "1.22.2",
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.22.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.22.2.tgz",
"integrity": "sha512-L+1Vmd+a2kk8HtogUFymQS6BjUfJnzcWoUp1BUgxoDiklbKSMvrsMuLZGevTOP1m0rEjgnC5MsDmsr8lX1lC+Q==", "integrity": "sha512-GIZPAGzQOy56mGvWMoZRPggn0dTlBf1gutV5TdceLCZlFNqWmuc7u+CzD0Gd9vQUTgLbrt0KLzz6FNprqYAxlA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "1.22.1", "@shikijs/types": "1.22.2",
"@shikijs/vscode-textmate": "^9.3.0" "@shikijs/vscode-textmate": "^9.3.0"
} }
}, },
"node_modules/@shikijs/transformers": { "node_modules/@shikijs/transformers": {
"version": "1.22.1", "version": "1.22.2",
"resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.22.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.22.2.tgz",
"integrity": "sha512-KvG49YFV6gV116sC4L3Sn1Rp6HXsioMKBBG373j088rw849440hm8s2r+/dgjsGLvT4p+QB7newev+5a3ARM6w==", "integrity": "sha512-8f78OiBa6pZDoZ53lYTmuvpFPlWtevn23bzG+azpPVvZg7ITax57o/K3TC91eYL3OMJOO0onPbgnQyZjRos8XQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"shiki": "1.22.1" "shiki": "1.22.2"
} }
}, },
"node_modules/@shikijs/types": { "node_modules/@shikijs/types": {
"version": "1.22.1", "version": "1.22.2",
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.22.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.22.2.tgz",
"integrity": "sha512-+45f8mu/Hxqs6Kyhfm98Nld5n7Q7lwhjU8UtdQwrOPs7BnM4VAb929O3IQ2ce+4D7SlNFlZGd8CnKRSnwbQreQ==", "integrity": "sha512-NCWDa6LGZqTuzjsGfXOBWfjS/fDIbDdmVDug+7ykVe1IKT4c1gakrvlfFYp5NhAXH/lyqLM8wsAPo5wNy73Feg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2136,9 +2164,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.24.0", "version": "4.24.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.2.tgz",
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", "integrity": "sha512-do/DFGq5g6rdDhdpPq5qb2ecoczeK6y+2UAjdJ5trjQJj5f1AiVdLRWRc9A9/fFukfvJRgM0UXzxBIYMovm5ww==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2152,22 +2180,24 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.24.0", "@rollup/rollup-android-arm-eabi": "4.24.2",
"@rollup/rollup-android-arm64": "4.24.0", "@rollup/rollup-android-arm64": "4.24.2",
"@rollup/rollup-darwin-arm64": "4.24.0", "@rollup/rollup-darwin-arm64": "4.24.2",
"@rollup/rollup-darwin-x64": "4.24.0", "@rollup/rollup-darwin-x64": "4.24.2",
"@rollup/rollup-linux-arm-gnueabihf": "4.24.0", "@rollup/rollup-freebsd-arm64": "4.24.2",
"@rollup/rollup-linux-arm-musleabihf": "4.24.0", "@rollup/rollup-freebsd-x64": "4.24.2",
"@rollup/rollup-linux-arm64-gnu": "4.24.0", "@rollup/rollup-linux-arm-gnueabihf": "4.24.2",
"@rollup/rollup-linux-arm64-musl": "4.24.0", "@rollup/rollup-linux-arm-musleabihf": "4.24.2",
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", "@rollup/rollup-linux-arm64-gnu": "4.24.2",
"@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-arm64-musl": "4.24.2",
"@rollup/rollup-linux-s390x-gnu": "4.24.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.24.2",
"@rollup/rollup-linux-x64-gnu": "4.24.0", "@rollup/rollup-linux-riscv64-gnu": "4.24.2",
"@rollup/rollup-linux-x64-musl": "4.24.0", "@rollup/rollup-linux-s390x-gnu": "4.24.2",
"@rollup/rollup-win32-arm64-msvc": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.24.2",
"@rollup/rollup-win32-ia32-msvc": "4.24.0", "@rollup/rollup-linux-x64-musl": "4.24.2",
"@rollup/rollup-win32-x64-msvc": "4.24.0", "@rollup/rollup-win32-arm64-msvc": "4.24.2",
"@rollup/rollup-win32-ia32-msvc": "4.24.2",
"@rollup/rollup-win32-x64-msvc": "4.24.2",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@ -2180,16 +2210,16 @@
"peer": true "peer": true
}, },
"node_modules/shiki": { "node_modules/shiki": {
"version": "1.22.1", "version": "1.22.2",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-1.22.1.tgz", "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.22.2.tgz",
"integrity": "sha512-PbJ6XxrWLMwB2rm3qdjIHNm3zq4SfFnOx0B3rEoi4AN8AUngsdyZ1tRe5slMPtn6jQkbUURLNZPpLR7Do3k78g==", "integrity": "sha512-3IZau0NdGKXhH2bBlUk4w1IHNxPh6A5B2sUpyY+8utLu2j/h1QpFkAaUA1bAMxOWWGtTWcAh531vnS4NJKS/lA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/core": "1.22.1", "@shikijs/core": "1.22.2",
"@shikijs/engine-javascript": "1.22.1", "@shikijs/engine-javascript": "1.22.2",
"@shikijs/engine-oniguruma": "1.22.1", "@shikijs/engine-oniguruma": "1.22.2",
"@shikijs/types": "1.22.1", "@shikijs/types": "1.22.2",
"@shikijs/vscode-textmate": "^9.3.0", "@shikijs/vscode-textmate": "^9.3.0",
"@types/hast": "^3.0.4" "@types/hast": "^3.0.4"
} }

View File

@ -1,5 +1,3 @@
use thiserror::Error;
use super::block_registry::get_block; use super::block_registry::get_block;
#[derive(Clone)] #[derive(Clone)]
@ -10,26 +8,32 @@ pub struct BlockState {
impl BlockState { impl BlockState {
pub const AIR: BlockState = BlockState { state_id: 0 }; pub const AIR: BlockState = BlockState { state_id: 0 };
pub fn new(registry_id: &str) -> Result<Self, BlockStateError> { /// Get a Block from the Vanilla Block registry at Runtime
let block_registry = get_block(registry_id).ok_or( pub fn new(registry_id: &str) -> Option<Self> {
BlockStateError::BlockIdentifierNotFound(registry_id.to_string()), let block = get_block(registry_id);
)?; block.map(|block| Self {
Ok(Self { state_id: block.default_state_id,
state_id: block_registry.default_state_id,
}) })
} }
pub fn get_id(&self) -> u16 { pub fn get_id(&self) -> u16 {
self.state_id self.state_id
} }
pub fn get_id_mojang_repr(&self) -> i32 {
self.state_id as i32
}
} }
#[derive(Error, Debug)] #[cfg(test)]
pub enum BlockStateError { mod tests {
#[error("The requested block identifier does not exist {0}")] use super::BlockState;
BlockIdentifierNotFound(String),
#[test]
fn not_existing() {
let result = BlockState::new("this_block_does_not_exist");
assert!(result.is_none());
}
#[test]
fn does_exist() {
let result = BlockState::new("minecraft:dirt");
assert!(result.is_some());
}
} }

View File

@ -91,10 +91,7 @@ impl ChunkReader for AnvilChunkReader {
save_file: &SaveFile, save_file: &SaveFile,
at: &pumpkin_core::math::vector2::Vector2<i32>, at: &pumpkin_core::math::vector2::Vector2<i32>,
) -> Result<super::ChunkData, ChunkReadingError> { ) -> Result<super::ChunkData, ChunkReadingError> {
let region = ( let region = (at.x >> 5, at.z >> 5);
((at.x as f32) / 32.0).floor() as i32,
((at.z as f32) / 32.0).floor() as i32,
);
let mut region_file = OpenOptions::new() let mut region_file = OpenOptions::new()
.read(true) .read(true)
@ -162,3 +159,28 @@ impl ChunkReader for AnvilChunkReader {
ChunkData::from_bytes(decompressed_chunk, *at).map_err(ChunkReadingError::ParsingError) ChunkData::from_bytes(decompressed_chunk, *at).map_err(ChunkReadingError::ParsingError)
} }
} }
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use pumpkin_core::math::vector2::Vector2;
use crate::{
chunk::{anvil::AnvilChunkReader, ChunkReader, ChunkReadingError},
level::SaveFile,
};
#[test]
fn not_existing() {
let region_path = PathBuf::from("not_existing");
let result = AnvilChunkReader::new().read_chunk(
&SaveFile {
root_folder: PathBuf::from(""),
region_folder: region_path,
},
&Vector2::new(0, 0),
);
assert!(matches!(result, Err(ChunkReadingError::ChunkNotExist)));
}
}

View File

@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
block::{block_state::BlockStateError, BlockId, BlockState}, block::{BlockId, BlockState},
coordinates::{ChunkRelativeBlockCoordinates, Height}, coordinates::{ChunkRelativeBlockCoordinates, Height},
level::SaveFile, level::SaveFile,
WORLD_HEIGHT, WORLD_HEIGHT,
@ -223,7 +223,8 @@ impl Index<ChunkRelativeBlockCoordinates> for ChunkBlocks {
impl ChunkData { impl ChunkData {
pub fn from_bytes(chunk_data: Vec<u8>, at: Vector2<i32>) -> Result<Self, ChunkParsingError> { pub fn from_bytes(chunk_data: Vec<u8>, at: Vector2<i32>) -> Result<Self, ChunkParsingError> {
if fastnbt::from_bytes::<ChunkStatus>(&chunk_data).expect("Failed reading chunk status.") if fastnbt::from_bytes::<ChunkStatus>(&chunk_data)
.map_err(|_| ChunkParsingError::FailedReadStatus)?
!= ChunkStatus::Full != ChunkStatus::Full
{ {
return Err(ChunkParsingError::ChunkNotGenerated); return Err(ChunkParsingError::ChunkNotGenerated);
@ -247,8 +248,8 @@ impl ChunkData {
.iter() .iter()
.map(|entry| match BlockState::new(&entry.name) { .map(|entry| match BlockState::new(&entry.name) {
// Block not found, Often the case when World has an newer or older version then block registry // Block not found, Often the case when World has an newer or older version then block registry
Err(_) => BlockState::AIR, None => BlockState::AIR,
Ok(state) => state, Some(state) => state,
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -309,8 +310,8 @@ impl ChunkData {
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ChunkParsingError { pub enum ChunkParsingError {
#[error("BlockState error: {0}")] #[error("Failed reading chunk status")]
BlockStateError(BlockStateError), FailedReadStatus,
#[error("The chunk isn't generated yet")] #[error("The chunk isn't generated yet")]
ChunkNotGenerated, ChunkNotGenerated,
#[error("Error deserializing chunk: {0}")] #[error("Error deserializing chunk: {0}")]

View File

@ -37,8 +37,7 @@ pub struct Level {
#[derive(Clone)] #[derive(Clone)]
pub struct SaveFile { pub struct SaveFile {
#[expect(dead_code)] pub root_folder: PathBuf,
root_folder: PathBuf,
pub region_folder: PathBuf, pub region_folder: PathBuf,
} }
@ -63,10 +62,6 @@ impl Level {
chunk_watchers: Arc::new(DashMap::new()), chunk_watchers: Arc::new(DashMap::new()),
} }
} else { } else {
log::warn!(
"Pumpkin currently only supports Superflat World generation. Use a vanilla ./world folder to play in a normal world."
);
Self { Self {
world_gen, world_gen,
save_file: None, save_file: None,

View File

@ -3,7 +3,7 @@ use pumpkin_core::math::vector3::Vector3;
use crate::block::block_state::BlockState; use crate::block::block_state::BlockState;
pub struct ProtoChunk { pub struct ProtoChunk {
state: GenerationState, // may want to use chunk status
} }
impl ProtoChunk { impl ProtoChunk {
@ -11,19 +11,3 @@ impl ProtoChunk {
unimplemented!() unimplemented!()
} }
} }
#[derive(Clone, PartialEq, PartialOrd)]
pub enum GenerationState {
Empty,
StructureStart,
StructureRef,
Biome,
Noise,
Surface,
Carver,
Feature,
InitLight,
Light,
Spawn,
Full,
}

View File

@ -42,7 +42,7 @@ rsa = "0.9.6"
rsa-der = "0.3.0" rsa-der = "0.3.0"
# authentication # authentication
reqwest = { version = "0.12.8", default-features = false, features = [ reqwest = { version = "0.12.9", default-features = false, features = [
"http2", "http2",
"json", "json",
"macos-system-configuration", "macos-system-configuration",

View File

@ -141,7 +141,7 @@ pub enum AuthError {
DisallowedAction, DisallowedAction,
#[error("Failed to parse JSON into Game Profile")] #[error("Failed to parse JSON into Game Profile")]
FailedParse, FailedParse,
#[error("Unknown Status Code")] #[error("Unknown Status Code {0}")]
UnknownStatusCode(StatusCode), UnknownStatusCode(StatusCode),
} }

View File

@ -1,5 +1,5 @@
use std::{ use std::{
collections::{HashMap, VecDeque}, collections::VecDeque,
net::SocketAddr, net::SocketAddr,
sync::{ sync::{
atomic::{AtomicBool, AtomicI32}, atomic::{AtomicBool, AtomicI32},
@ -16,7 +16,7 @@ use authentication::GameProfile;
use crossbeam::atomic::AtomicCell; use crossbeam::atomic::AtomicCell;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use pumpkin_config::compression::CompressionInfo; use pumpkin_config::compression::CompressionInfo;
use pumpkin_core::{math::vector2::Vector2, text::TextComponent}; use pumpkin_core::text::TextComponent;
use pumpkin_protocol::{ use pumpkin_protocol::{
bytebuf::DeserializerError, bytebuf::DeserializerError,
client::{config::CConfigDisconnect, login::CLoginDisconnect, play::CPlayDisconnect}, client::{config::CConfigDisconnect, login::CLoginDisconnect, play::CPlayDisconnect},
@ -36,12 +36,8 @@ use pumpkin_protocol::{
}, },
ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket, ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket,
}; };
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
sync::Notify,
task::JoinHandle,
};
use thiserror::Error; use thiserror::Error;
@ -93,42 +89,6 @@ impl Default for PlayerConfig {
} }
} }
pub struct ChunkHandleWrapper {
handle: Option<JoinHandle<()>>,
aborted: bool,
}
impl ChunkHandleWrapper {
#[must_use]
pub fn new(handle: JoinHandle<()>) -> Self {
Self {
handle: Some(handle),
aborted: false,
}
}
pub fn abort(&mut self) {
self.aborted = true;
if let Some(handle) = &self.handle {
handle.abort();
} else {
log::error!("Trying to abort without a handle!");
}
}
pub fn take_handle(&mut self) -> JoinHandle<()> {
self.handle.take().unwrap()
}
#[must_use]
pub fn aborted(&self) -> bool {
self.aborted
}
}
pub type PlayerPendingChunks =
Arc<parking_lot::Mutex<HashMap<Vector2<i32>, VecDeque<ChunkHandleWrapper>>>>;
/// Everything which makes a Connection with our Server is a `Client`. /// Everything which makes a Connection with our Server is a `Client`.
/// Client will become Players when they reach the `Play` state /// Client will become Players when they reach the `Play` state
pub struct Client { pub struct Client {
@ -164,18 +124,6 @@ pub struct Client {
pub client_packets_queue: Arc<Mutex<VecDeque<RawPacket>>>, pub client_packets_queue: Arc<Mutex<VecDeque<RawPacket>>>,
/// Indicates whether the client should be converted into a player. /// Indicates whether the client should be converted into a player.
pub make_player: AtomicBool, pub make_player: AtomicBool,
//TODO: Is there a way to consolidate these two?
//Need to lookup by chunk, but also would be need to contain all the stuff
//In a PendingBatch struct. Is there a cheap way to map multiple keys to a single element?
//
/// Individual chunk tasks that this client is waiting for
pub pending_chunks: PlayerPendingChunks,
/// Chunk batches that this client is waiting for
pub pending_chunk_batch: parking_lot::Mutex<HashMap<uuid::Uuid, JoinHandle<()>>>,
/// Tell tasks to stop if we are closing
cancel_tasks: Notify,
} }
impl Client { impl Client {
@ -199,9 +147,6 @@ impl Client {
closed: AtomicBool::new(false), closed: AtomicBool::new(false),
client_packets_queue: Arc::new(Mutex::new(VecDeque::new())), client_packets_queue: Arc::new(Mutex::new(VecDeque::new())),
make_player: AtomicBool::new(false), make_player: AtomicBool::new(false),
pending_chunks: Arc::new(parking_lot::Mutex::new(HashMap::new())),
pending_chunk_batch: parking_lot::Mutex::new(HashMap::new()),
cancel_tasks: Notify::new(),
} }
} }
@ -299,10 +244,6 @@ impl Client {
Ok(()) Ok(())
} }
pub async fn await_cancel(&self) {
self.cancel_tasks.notified().await;
}
/// Processes all packets send by the client /// Processes all packets send by the client
pub async fn process_packets(&self, server: &Arc<Server>) { pub async fn process_packets(&self, server: &Arc<Server>) {
let mut packet_queue = self.client_packets_queue.lock().await; let mut packet_queue = self.client_packets_queue.lock().await;
@ -311,13 +252,7 @@ impl Client {
log::debug!("Canceling client packet processing (pre)"); log::debug!("Canceling client packet processing (pre)");
return; return;
} }
tokio::select! { if let Err(error) = self.handle_packet(server, &mut packet).await {
() = self.cancel_tasks.notified() => {
log::debug!("Canceling client packet processing (interrupt)");
return;
},
packet_result = self.handle_packet(server, &mut packet) => {
if let Err(error) = packet_result {
let text = format!("Error while reading incoming packet {error}"); let text = format!("Error while reading incoming packet {error}");
log::error!( log::error!(
"Failed to read incoming packet with id {}: {}", "Failed to read incoming packet with id {}: {}",
@ -328,8 +263,6 @@ impl Client {
}; };
} }
} }
}
}
/// Handles an incoming decoded not Play state Packet /// Handles an incoming decoded not Play state Packet
pub async fn handle_packet( pub async fn handle_packet(
@ -562,26 +495,8 @@ impl Client {
pub fn close(&self) { pub fn close(&self) {
self.closed self.closed
.store(true, std::sync::atomic::Ordering::Relaxed); .store(true, std::sync::atomic::Ordering::Relaxed);
// Abort pending chunks here too because we might clean up before chunk tasks are done
self.abort_chunks("closed");
self.cancel_tasks.notify_waiters();
log::debug!("Closed connection for {}", self.id); log::debug!("Closed connection for {}", self.id);
} }
pub fn abort_chunks(&self, reason: &str) {
let mut pending_chunks = self.pending_chunks.lock();
pending_chunks.iter_mut().for_each(|(chunk, handles)| {
handles.iter_mut().enumerate().for_each(|(count, handle)| {
if !handle.aborted() {
log::debug!("Aborting chunk {:?} ({}) ({})", chunk, count, reason);
handle.abort();
}
});
});
}
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]

View File

@ -78,7 +78,7 @@ impl Player {
pos.clamp(-2.0E7, 2.0E7) pos.clamp(-2.0E7, 2.0E7)
} }
pub async fn handle_position(&self, position: SPlayerPosition) { pub async fn handle_position(self: &Arc<Self>, position: SPlayerPosition) {
if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() { if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() {
self.kick(TextComponent::text("Invalid movement")).await; self.kick(TextComponent::text("Invalid movement")).await;
return; return;
@ -133,7 +133,10 @@ impl Player {
player_chunker::update_position(self).await; player_chunker::update_position(self).await;
} }
pub async fn handle_position_rotation(&self, position_rotation: SPlayerPositionRotation) { pub async fn handle_position_rotation(
self: &Arc<Self>,
position_rotation: SPlayerPositionRotation,
) {
if position_rotation.x.is_nan() if position_rotation.x.is_nan()
|| position_rotation.feet_y.is_nan() || position_rotation.feet_y.is_nan()
|| position_rotation.z.is_nan() || position_rotation.z.is_nan()

View File

@ -1,4 +1,5 @@
use std::{ use std::{
collections::{HashMap, VecDeque},
sync::{ sync::{
atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU32, AtomicU8}, atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU32, AtomicU8},
Arc, Arc,
@ -31,14 +32,15 @@ use pumpkin_protocol::{
}, },
RawPacket, ServerPacket, VarInt, RawPacket, ServerPacket, VarInt,
}; };
use tokio::sync::Mutex; use tokio::sync::{Mutex, Notify};
use tokio::task::JoinHandle;
use pumpkin_protocol::server::play::SKeepAlive; use pumpkin_protocol::server::play::SKeepAlive;
use pumpkin_world::{cylindrical_chunk_iterator::Cylindrical, item::ItemStack}; use pumpkin_world::{cylindrical_chunk_iterator::Cylindrical, item::ItemStack};
use super::Entity; use super::Entity;
use crate::{ use crate::{
client::{authentication::GameProfile, ChunkHandleWrapper, Client, PlayerConfig}, client::{authentication::GameProfile, Client, PlayerConfig},
server::Server, server::Server,
world::World, world::World,
}; };
@ -46,6 +48,42 @@ use crate::{error::PumpkinError, world::player_chunker::get_view_distance};
use super::living::LivingEntity; use super::living::LivingEntity;
pub struct ChunkHandleWrapper {
handle: Option<JoinHandle<()>>,
aborted: bool,
}
impl ChunkHandleWrapper {
#[must_use]
pub fn new(handle: JoinHandle<()>) -> Self {
Self {
handle: Some(handle),
aborted: false,
}
}
pub fn abort(&mut self) {
self.aborted = true;
if let Some(handle) = &self.handle {
handle.abort();
} else {
log::error!("Trying to abort without a handle!");
}
}
pub fn take_handle(&mut self) -> JoinHandle<()> {
self.handle.take().unwrap()
}
#[must_use]
pub fn aborted(&self) -> bool {
self.aborted
}
}
pub type PlayerPendingChunks =
Arc<parking_lot::Mutex<HashMap<Vector2<i32>, VecDeque<ChunkHandleWrapper>>>>;
/// Represents a Minecraft player entity. /// Represents a Minecraft player entity.
/// ///
/// A `Player` is a special type of entity that represents a human player connected to the server. /// A `Player` is a special type of entity that represents a human player connected to the server.
@ -99,6 +137,18 @@ pub struct Player {
pub last_keep_alive_time: AtomicCell<Instant>, pub last_keep_alive_time: AtomicCell<Instant>,
/// Amount of ticks since last attack /// Amount of ticks since last attack
pub last_attacked_ticks: AtomicU32, pub last_attacked_ticks: AtomicU32,
//TODO: Is there a way to consolidate these two?
//Need to lookup by chunk, but also would be need to contain all the stuff
//In a PendingBatch struct. Is there a cheap way to map multiple keys to a single element?
//
/// Individual chunk tasks that this client is waiting for
pub pending_chunks: PlayerPendingChunks,
/// Chunk batches that this client is waiting for
pub pending_chunk_batch: parking_lot::Mutex<HashMap<uuid::Uuid, JoinHandle<()>>>,
/// Tell tasks to stop if we are closing
cancel_tasks: Notify,
} }
impl Player { impl Player {
@ -148,6 +198,9 @@ impl Player {
keep_alive_id: AtomicI64::new(0), keep_alive_id: AtomicI64::new(0),
last_keep_alive_time: AtomicCell::new(std::time::Instant::now()), last_keep_alive_time: AtomicCell::new(std::time::Instant::now()),
last_attacked_ticks: AtomicU32::new(0), last_attacked_ticks: AtomicU32::new(0),
pending_chunks: Arc::new(parking_lot::Mutex::new(HashMap::new())),
pending_chunk_batch: parking_lot::Mutex::new(HashMap::new()),
cancel_tasks: Notify::new(),
} }
} }
@ -155,6 +208,10 @@ impl Player {
#[allow(unused_variables)] #[allow(unused_variables)]
pub async fn remove(&self) { pub async fn remove(&self) {
let world = &self.living_entity.entity.world; let world = &self.living_entity.entity.world;
// Abort pending chunks here too because we might clean up before chunk tasks are done
self.abort_chunks("closed");
self.cancel_tasks.notify_waiters();
world.remove_player(self).await; world.remove_player(self).await;
@ -177,7 +234,7 @@ impl Player {
); );
let (watched_chunks, to_await) = { let (watched_chunks, to_await) = {
let mut pending_chunks = self.client.pending_chunks.lock(); let mut pending_chunks = self.pending_chunks.lock();
// Don't try to clean chunks that dont exist yet // Don't try to clean chunks that dont exist yet
// If they are still pending, we never sent the client the chunk, // If they are still pending, we never sent the client the chunk,
@ -230,7 +287,7 @@ impl Player {
// Allow the batch jobs to properly cull stragglers before we do our clean up // Allow the batch jobs to properly cull stragglers before we do our clean up
log::debug!("Collecting chunk batches..."); log::debug!("Collecting chunk batches...");
let batches = { let batches = {
let mut chunk_batches = self.client.pending_chunk_batch.lock(); let mut chunk_batches = self.pending_chunk_batch.lock();
let keys = chunk_batches.keys().copied().collect_vec(); let keys = chunk_batches.keys().copied().collect_vec();
let handles = keys let handles = keys
.iter() .iter()
@ -274,6 +331,10 @@ impl Player {
//self.living_entity.entity.world.level.list_cached(); //self.living_entity.entity.world.level.list_cached();
} }
pub async fn await_cancel(&self) {
self.cancel_tasks.notified().await;
}
pub async fn tick(&self) { pub async fn tick(&self) {
if self if self
.client .client
@ -469,6 +530,18 @@ impl Player {
.send_packet(&CSystemChatMessage::new(text, false)) .send_packet(&CSystemChatMessage::new(text, false))
.await; .await;
} }
pub fn abort_chunks(&self, reason: &str) {
let mut pending_chunks = self.pending_chunks.lock();
pending_chunks.iter_mut().for_each(|(chunk, handles)| {
handles.iter_mut().enumerate().for_each(|(count, handle)| {
if !handle.aborted() {
log::debug!("Aborting chunk {:?} ({}) ({})", chunk, count, reason);
handle.abort();
}
});
});
}
} }
impl Player { impl Player {
@ -478,7 +551,7 @@ impl Player {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let inst = std::time::Instant::now(); let inst = std::time::Instant::now();
tokio::select! { tokio::select! {
() = self.client.await_cancel() => { () = self.await_cancel() => {
log::debug!("Canceling player packet processing"); log::debug!("Canceling player packet processing");
return; return;
}, },

View File

@ -5,9 +5,9 @@ use std::{
pub mod player_chunker; pub mod player_chunker;
use crate::{ use crate::entity::{
client::{ChunkHandleWrapper, Client}, player::{ChunkHandleWrapper, Player},
entity::{player::Player, Entity}, Entity,
}; };
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use pumpkin_config::BasicConfiguration; use pumpkin_config::BasicConfiguration;
@ -337,8 +337,13 @@ impl World {
self.level.loaded_chunk_count() self.level.loaded_chunk_count()
} }
fn spawn_world_chunks(&self, client: Arc<Client>, chunks: &[Vector2<i32>]) { #[expect(clippy::too_many_lines)]
if client.closed.load(std::sync::atomic::Ordering::Relaxed) { fn spawn_world_chunks(&self, player: Arc<Player>, chunks: &[Vector2<i32>]) {
if player
.client
.closed
.load(std::sync::atomic::Ordering::Relaxed)
{
log::info!("The connection has closed before world chunks were spawned",); log::info!("The connection has closed before world chunks were spawned",);
return; return;
} }
@ -349,13 +354,13 @@ impl World {
let (pending, mut receiver) = self.receive_chunks(chunks); let (pending, mut receiver) = self.receive_chunks(chunks);
{ {
let mut pending_chunks = client.pending_chunks.lock(); let mut pending_chunks = player.pending_chunks.lock();
for chunk in chunks { for chunk in chunks {
if pending_chunks.contains_key(chunk) { if pending_chunks.contains_key(chunk) {
log::debug!( log::debug!(
"Client id {} is requesting chunk {:?} but its already pending!", "Client id {} is requesting chunk {:?} but its already pending!",
client.id, player.client.id,
chunk chunk
); );
} }
@ -376,9 +381,9 @@ impl World {
}; };
} }
} }
let pending_chunks = client.pending_chunks.clone(); let pending_chunks = player.pending_chunks.clone();
let level = self.level.clone(); let level = self.level.clone();
let retained_client = client.clone(); let retained_player = player.clone();
let batch_id = id; let batch_id = id;
let handle = tokio::spawn(async move { let handle = tokio::spawn(async move {
@ -434,13 +439,17 @@ impl World {
level.mark_chunk_as_newly_watched(chunk_data.position); level.mark_chunk_as_newly_watched(chunk_data.position);
}; };
if !client.closed.load(std::sync::atomic::Ordering::Relaxed) { if !player
client.send_packet(&packet).await; .client
.closed
.load(std::sync::atomic::Ordering::Relaxed)
{
player.client.send_packet(&packet).await;
} }
} }
{ {
let mut batch = client.pending_chunk_batch.lock(); let mut batch = player.pending_chunk_batch.lock();
batch.remove(&batch_id); batch.remove(&batch_id);
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -452,7 +461,7 @@ impl World {
}); });
{ {
let mut batch_handles = retained_client.pending_chunk_batch.lock(); let mut batch_handles = retained_player.pending_chunk_batch.lock();
batch_handles.insert(id, handle); batch_handles.insert(id, handle);
} }
} }

View File

@ -47,10 +47,10 @@ pub async fn player_join(world: &World, player: Arc<Player>) {
let new_cylindrical = Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance); let new_cylindrical = Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance);
let loading_chunks = new_cylindrical.all_chunks_within(); let loading_chunks = new_cylindrical.all_chunks_within();
world.spawn_world_chunks(player.client.clone(), &loading_chunks); world.spawn_world_chunks(player, &loading_chunks);
} }
pub async fn update_position(player: &Player) { pub async fn update_position(player: &Arc<Player>) {
let entity = &player.living_entity.entity; let entity = &player.living_entity.entity;
let current_watched = player.watched_section.load(); let current_watched = player.watched_section.load();
let new_watched = chunk_section_from_pos(&entity.block_pos.load()); let new_watched = chunk_section_from_pos(&entity.block_pos.load());
@ -93,7 +93,7 @@ pub async fn update_position(player: &Player) {
//let inst = std::time::Instant::now(); //let inst = std::time::Instant::now();
entity entity
.world .world
.spawn_world_chunks(player.client.clone(), &loading_chunks); .spawn_world_chunks(player.clone(), &loading_chunks);
//log::debug!("Loading chunks took {:?}", inst.elapsed()); //log::debug!("Loading chunks took {:?}", inst.elapsed());
} }
@ -104,7 +104,7 @@ pub async fn update_position(player: &Player) {
//let inst = std::time::Instant::now(); //let inst = std::time::Instant::now();
let watched_chunks: Vec<_> = { let watched_chunks: Vec<_> = {
let mut pending_chunks = player.client.pending_chunks.lock(); let mut pending_chunks = player.pending_chunks.lock();
unloading_chunks unloading_chunks
.into_iter() .into_iter()
.filter(|chunk| { .filter(|chunk| {