mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 19:02:59 +00:00
Compare commits
127 Commits
Author | SHA1 | Date | |
---|---|---|---|
2fb4704269 | |||
0c0eb72b1b | |||
466107d3b8 | |||
4f59d3487a | |||
65220b4f7f | |||
85eb6b30a5 | |||
1c2eb35025 | |||
85ed7efcb4 | |||
183489e863 | |||
ac060f2ec6 | |||
6c85d4d254 | |||
f506c922b5 | |||
a5b08fc8f2 | |||
c3c4c80b70 | |||
5695fa9086 | |||
f78808bad0 | |||
dc0082162b | |||
ff4aa148ef | |||
63e86fe806 | |||
ab05bc7379 | |||
1a395a51c9 | |||
142c8f067b | |||
cd3c96aad2 | |||
19c47fa71f | |||
d670bc8bf8 | |||
7bd8d09023 | |||
5a970541f9 | |||
e561fa6222 | |||
025dde19ce | |||
28bfe9fbb4 | |||
cd53fa162b | |||
748e9705ba | |||
219ed81389 | |||
6a7196530c | |||
01fe497c49 | |||
3bbd088a09 | |||
85effa5240 | |||
81c5b83bd9 | |||
ef31a9fc66 | |||
dc56a99473 | |||
9477034a4a | |||
5844b59b12 | |||
3af18917f0 | |||
61528393c2 | |||
59b8453228 | |||
8cb48bfe1d | |||
8fb4d7b982 | |||
13f114f30e | |||
eccd258aeb | |||
bd5f379c4c | |||
2588895ab0 | |||
432999a7d7 | |||
68699dbff9 | |||
bfbe3d83de | |||
c32c21464c | |||
16faafa1ef | |||
4d6ac57a26 | |||
73ba1ba224 | |||
8b79253d3b | |||
1122131c8d | |||
a50ef2af6f | |||
72e4660800 | |||
e6285a0312 | |||
5420e76a9a | |||
de46a81cf4 | |||
0cdc04f9b5 | |||
8b1a84f2bf | |||
155e516f74 | |||
ea0a47dff7 | |||
0a6ce18322 | |||
11d73e5bb8 | |||
492ad6bb66 | |||
82e8eb46ac | |||
c7868a810d | |||
2cc22a29c1 | |||
8e2829bdd4 | |||
af79e787ea | |||
65c53e6512 | |||
5503fadf13 | |||
99964709c9 | |||
b85f3bd149 | |||
57d274901d | |||
f3e1c82246 | |||
908b627846 | |||
afb21c1df2 | |||
988be2a96b | |||
afe67f7502 | |||
b257348a3a | |||
12c66d3362 | |||
92fd2d35a4 | |||
61077c48f1 | |||
e0c61071e1 | |||
813d431208 | |||
ee112b992d | |||
c9b33e2b9f | |||
2f2be84b12 | |||
5a7736b179 | |||
e648f1c91e | |||
5116e11cea | |||
9c05e37fbe | |||
fb4796f35e | |||
0c2ba66078 | |||
c29cd8e2eb | |||
a13b0c98a1 | |||
e6ff908e18 | |||
c47ecb55c0 | |||
c19d2fe891 | |||
f195f24f4f | |||
4b5f279a3e | |||
89260d788c | |||
a7cd081002 | |||
361be8fe36 | |||
b01e4ab417 | |||
177b963d8e | |||
8d1a1628de | |||
6f80b8979d | |||
3c8eb29d4e | |||
b94bbf6f5e | |||
314a8a1297 | |||
547503e8f4 | |||
f74ff1fcd4 | |||
6c351357ab | |||
3433406cff | |||
b307cd0aa1 | |||
c9b83d7276 | |||
e22b6ff566 | |||
af88f49a21 |
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -20,8 +20,9 @@ assignees: ''
|
||||
<!-- try the `version` command | LATEST IS NOT A VALID VERSION -->
|
||||
* PocketMine-MP:
|
||||
* PHP:
|
||||
* Using JIT: yes/no (delete as appropriate) <!-- look for the giant yellow warning in the log that says you're using JIT -->
|
||||
* Server OS:
|
||||
* Game version: PE/Win10 (delete as appropriate)
|
||||
* Game version: Android/iOS/Win10/Xbox/PS4/Switch (delete as appropriate)
|
||||
|
||||
### Plugins
|
||||
<!--- use the `plugins` command and paste the output below -->
|
||||
|
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: composer
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
113
.github/workflows/draft-release.yml
vendored
Normal file
113
.github/workflows/draft-release.yml
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
name: Draft release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: "*"
|
||||
|
||||
jobs:
|
||||
draft:
|
||||
name: Create GitHub draft release
|
||||
if: "startsWith(github.event.head_commit.message, 'Release ')"
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.12.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
|
||||
|
||||
- name: Patch VersionInfo
|
||||
run: |
|
||||
BUILD_NUMBER=2000+$GITHUB_RUN_NUMBER #to stay above jenkins
|
||||
echo "Build number: $BUILD_NUMBER"
|
||||
sed -i "s/const BUILD_NUMBER = 0/const BUILD_NUMBER = ${BUILD_NUMBER}/" src/pocketmine/VersionInfo.php
|
||||
|
||||
- name: Minify BedrockData JSON files
|
||||
run: php src/pocketmine/resources/vanilla/.minify_json.php
|
||||
|
||||
- name: Run preprocessor
|
||||
run: |
|
||||
PM_PREPROCESSOR_PATH="$GITHUB_WORKSPACE/build/preprocessor"
|
||||
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path=src --multisize || (echo "Preprocessor exited with code $?" && exit 1)
|
||||
#dump the diff of preprocessor replacements to a patch in case it has bugs
|
||||
git diff > preprocessor_diff.patch
|
||||
VENDOR_PM="$GITHUB_WORKSPACE/vendor"
|
||||
VENDOR_PM_BACKUP="$GITHUB_WORKSPACE/vendor-before-preprocess"
|
||||
cp -r "$VENDOR_PM" "$VENDOR_PM_BACKUP"
|
||||
for f in $(ls $VENDOR_PM/pocketmine); do
|
||||
echo "Processing directory \"$f\"..."
|
||||
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path="$VENDOR_PM/pocketmine/$f" --multisize || (echo "Preprocessor exited with code $?" && exit 1)
|
||||
echo "Checking for changes in \"$f\"..."
|
||||
DIFF=$(git diff --no-index "$VENDOR_PM_BACKUP/pocketmine/$f" "$VENDOR_PM/pocketmine/$f" || true)
|
||||
if [ "$DIFF" != "" ]; then
|
||||
PATCH="$GITHUB_WORKSPACE/preprocessor_diff_$f.patch"
|
||||
echo "$DIFF" > "$PATCH"
|
||||
echo "Generated patch file \"$PATCH\""
|
||||
else
|
||||
echo "No diff generated for \"$f\" (preprocessor made no changes)"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Build PocketMine-MP.phar
|
||||
run: php -dphar.readonly=0 build/server-phar.php --git ${{ github.sha }}
|
||||
|
||||
- name: Get PocketMine-MP release version
|
||||
id: get-pm-version
|
||||
run: |
|
||||
echo ::set-output name=PM_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\BASE_VERSION;')
|
||||
echo ::set-output name=MCPE_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;')
|
||||
echo ::set-output name=PM_VERSION_SHORT::$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\BASE_VERSION); array_pop($v); echo implode(".", $v);')
|
||||
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\BASE_VERSION);')
|
||||
|
||||
- name: Generate build info
|
||||
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} > build_info.json
|
||||
|
||||
- name: Upload release artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: release_artifacts
|
||||
path: |
|
||||
${{ github.workspace }}/PocketMine-MP.phar
|
||||
${{ github.workspace }}/start.*
|
||||
${{ github.workspace }}/build_info.json
|
||||
|
||||
- name: Create draft release
|
||||
uses: ncipollo/release-action@v1.8.6
|
||||
with:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||
commit: ${{ github.sha }}
|
||||
draft: true
|
||||
name: PocketMine-MP ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||
tag: ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
|
||||
|
||||
Please see the [changelogs](/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
|
||||
|
||||
- name: Upload preprocessor diffs
|
||||
uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: preprocessor_diffs
|
||||
path: ${{ github.workspace }}/preprocessor_diff*.patch
|
||||
|
33
.github/workflows/main.yml
vendored
33
.github/workflows/main.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.27, 7.4.16]
|
||||
php: [7.4.22, 8.0.9]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2 #needed for build.sh
|
||||
@ -36,8 +36,13 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.27, 7.4.16]
|
||||
include:
|
||||
- php: 8.0.9
|
||||
config: phpstan.neon.dist
|
||||
image: ubuntu-20.04
|
||||
- php: 7.4.22
|
||||
config: phpstan.php7.neon
|
||||
image: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@ -55,7 +60,7 @@ jobs:
|
||||
|
||||
- name: Install cached PHP's dependencies
|
||||
if: steps.php-build-cache.outputs.cache-hit == 'true'
|
||||
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
|
||||
run: ./tests/gh-actions/install-dependencies.sh
|
||||
|
||||
- name: Prefix PHP to PATH
|
||||
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
|
||||
@ -77,7 +82,7 @@ jobs:
|
||||
run: php composer.phar install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPStan
|
||||
run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
|
||||
run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G -c ${{ matrix.config }}
|
||||
|
||||
phpunit:
|
||||
name: PHPUnit tests
|
||||
@ -87,7 +92,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.27, 7.4.16]
|
||||
php: [7.4.22, 8.0.9]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@ -105,7 +110,7 @@ jobs:
|
||||
|
||||
- name: Install cached PHP's dependencies
|
||||
if: steps.php-build-cache.outputs.cache-hit == 'true'
|
||||
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
|
||||
run: ./tests/gh-actions/install-dependencies.sh
|
||||
|
||||
- name: Prefix PHP to PATH
|
||||
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
|
||||
@ -137,7 +142,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.27, 7.4.16]
|
||||
php: [7.4.22, 8.0.9]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@ -157,7 +162,7 @@ jobs:
|
||||
|
||||
- name: Install cached PHP's dependencies
|
||||
if: steps.php-build-cache.outputs.cache-hit == 'true'
|
||||
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
|
||||
run: ./tests/gh-actions/install-dependencies.sh
|
||||
|
||||
- name: Prefix PHP to PATH
|
||||
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
|
||||
@ -189,7 +194,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.27, 7.4.16]
|
||||
php: [7.4.22, 8.0.9]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@ -209,7 +214,7 @@ jobs:
|
||||
|
||||
- name: Install cached PHP's dependencies
|
||||
if: steps.php-build-cache.outputs.cache-hit == 'true'
|
||||
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
|
||||
run: ./tests/gh-actions/install-dependencies.sh
|
||||
|
||||
- name: Prefix PHP to PATH
|
||||
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
|
||||
@ -272,10 +277,10 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.9.0
|
||||
uses: shivammathur/setup-php@2.12.0
|
||||
with:
|
||||
php-version: 7.4
|
||||
php-version: 8.0
|
||||
tools: php-cs-fixer
|
||||
|
||||
- name: Run PHP-CS-Fixer
|
||||
run: php-cs-fixer fix --dry-run --diff --diff-format=udiff
|
||||
run: php-cs-fixer fix --dry-run --diff
|
||||
|
51
.github/workflows/update-php-versions.php
vendored
Normal file
51
.github/workflows/update-php-versions.php
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
const VERSIONS = [
|
||||
"7.3",
|
||||
"7.4",
|
||||
"8.0"
|
||||
];
|
||||
|
||||
$workflowFile = file_get_contents(__DIR__ . '/main.yml');
|
||||
$newWorkflowFile = $workflowFile;
|
||||
foreach(VERSIONS as $v){
|
||||
$releaseInfo = file_get_contents("https://secure.php.net/releases?json&version=$v");
|
||||
if($releaseInfo === false){
|
||||
throw new \RuntimeException("Failed to contact php.net API");
|
||||
}
|
||||
$data = json_decode($releaseInfo, true);
|
||||
if(!is_array($data) || !isset($data["version"]) || !is_string($data["version"]) || preg_match('/^\d+\.\d+\.\d+(-[A-Za-z\d]+)?$/', $data["version"]) === 0){
|
||||
throw new \RuntimeException("Invalid data returned by API");
|
||||
}
|
||||
$updated = preg_replace("/$v\.\d+/", $data["version"], $newWorkflowFile);
|
||||
if($updated !== $newWorkflowFile){
|
||||
echo "Updated $v revision to " . $data["version"] . "\n";
|
||||
}
|
||||
$newWorkflowFile = $updated;
|
||||
}
|
||||
|
||||
if($workflowFile !== $newWorkflowFile){
|
||||
echo "Writing modified workflow file\n";
|
||||
file_put_contents(__DIR__ . '/main.yml', $newWorkflowFile);
|
||||
}
|
45
.github/workflows/update-updater-api.yml
vendored
Normal file
45
.github/workflows/update-updater-api.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
name: Update update.pmmp.io API info
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Install jq
|
||||
run: sudo apt update && sudo apt install jq -y
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: pmmp/update.pmmp.io
|
||||
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
|
||||
|
||||
- name: Get actual tag name
|
||||
id: tag-name
|
||||
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
||||
|
||||
- name: Download new release information
|
||||
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
|
||||
|
||||
- name: Detect channel
|
||||
id: channel
|
||||
run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json)
|
||||
|
||||
- name: Copy release information
|
||||
run: |
|
||||
cp new_build_info.json channels/${{ steps.channel.outputs.CHANNEL }}.json
|
||||
rm new_build_info.json
|
||||
|
||||
- name: Commit changes
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
git add .
|
||||
git diff-index --quiet HEAD || git commit -m "New ${{ steps.channel.outputs.CHANNEL }} release: ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }}"
|
||||
|
||||
- name: Push changes
|
||||
run: git push
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -16,7 +16,9 @@ server.lock
|
||||
/phpstan.neon
|
||||
|
||||
# Common IDEs
|
||||
.idea/
|
||||
.idea/*
|
||||
!.idea/codeStyles/
|
||||
!.idea/fileTemplates/
|
||||
nbproject/*
|
||||
|
||||
# Windows image file caches
|
||||
@ -47,3 +49,4 @@ Documentation/*
|
||||
|
||||
# php-cs-fixer
|
||||
/.php_cs.cache
|
||||
/.php-cs-fixer.cache
|
||||
|
71
.idea/codeStyles/Project.xml
generated
Normal file
71
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,71 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="LINE_SEPARATOR" value=" " />
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_TEXT_WRAP" value="0" />
|
||||
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="thead,tbody,tfoot" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<PHPCodeStyleSettings>
|
||||
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="true" />
|
||||
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
|
||||
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
||||
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
||||
<option name="VARIABLE_NAMING_STYLE" value="CAMEL_CASE" />
|
||||
<option name="SPACES_WITHIN_SHORT_ECHO_TAGS" value="false" />
|
||||
<option name="SPACE_BEFORE_CLOSURE_LEFT_PARENTHESIS" value="false" />
|
||||
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_COLON_IN_RETURN_TYPE" value="true" />
|
||||
</PHPCodeStyleSettings>
|
||||
<editorconfig>
|
||||
<option name="ENABLED" value="false" />
|
||||
</editorconfig>
|
||||
<codeStyleSettings language="HTML">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="4" />
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="PHP">
|
||||
<option name="CLASS_BRACE_STYLE" value="1" />
|
||||
<option name="METHOD_BRACE_STYLE" value="1" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="ALIGN_MULTILINE_FOR" value="false" />
|
||||
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
|
||||
<option name="SPACE_AFTER_TYPE_CAST" value="true" />
|
||||
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_CLASS_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_METHOD_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_IF_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_ELSE_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_WHILE_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_FOR_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_DO_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_SWITCH_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_TRY_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_CATCH_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_FINALLY_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_ELSE_KEYWORD" value="false" />
|
||||
<option name="SPACE_BEFORE_WHILE_KEYWORD" value="false" />
|
||||
<option name="SPACE_BEFORE_CATCH_KEYWORD" value="false" />
|
||||
<option name="SPACE_BEFORE_FINALLY_KEYWORD" value="false" />
|
||||
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="neon">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
8
.idea/fileTemplates/code/PHP Constructor.php
generated
Normal file
8
.idea/fileTemplates/code/PHP Constructor.php
generated
Normal file
@ -0,0 +1,8 @@
|
||||
#if(${THROWS_DOC} != "")
|
||||
/**
|
||||
${THROWS_DOC}
|
||||
*/
|
||||
#end
|
||||
public function __construct(${PARAM_LIST}) {
|
||||
${BODY}
|
||||
}
|
6
.idea/fileTemplates/code/PHP Fluent Setter Method.php
generated
Normal file
6
.idea/fileTemplates/code/PHP Fluent Setter Method.php
generated
Normal file
@ -0,0 +1,6 @@
|
||||
/** @return $this */
|
||||
public function set${NAME}(#if (${SCALAR_TYPE_HINT})${SCALAR_TYPE_HINT} #else#end$${PARAM_NAME})#if(${RETURN_TYPE}): self#else#end
|
||||
{
|
||||
$this->${FIELD_NAME} = $${PARAM_NAME};
|
||||
return $this;
|
||||
}
|
3
.idea/fileTemplates/code/PHP Getter Method.php
generated
Normal file
3
.idea/fileTemplates/code/PHP Getter Method.php
generated
Normal file
@ -0,0 +1,3 @@
|
||||
#if(${TYPE_HINT} != ${RETURN_TYPE} && ${TYPE_HINT} != "")/** @return ${TYPE_HINT} */#end
|
||||
public ${STATIC} function ${GET_OR_IS}${NAME}()#if(${RETURN_TYPE}): ${RETURN_TYPE}#else#end
|
||||
{ return #if(${STATIC} == "static")self::$${FIELD_NAME};#else$this->${FIELD_NAME};#end }
|
2
.idea/fileTemplates/code/PHP Setter Method.php
generated
Normal file
2
.idea/fileTemplates/code/PHP Setter Method.php
generated
Normal file
@ -0,0 +1,2 @@
|
||||
public ${STATIC} function set${NAME}(#if (${SCALAR_TYPE_HINT})${SCALAR_TYPE_HINT} #end$${PARAM_NAME})#if (${VOID_RETURN_TYPE}):void #end
|
||||
{#if (${STATIC} == "static") self::$${FIELD_NAME} = $${PARAM_NAME}; #else $this->${FIELD_NAME} = $${PARAM_NAME}; #end}
|
0
.idea/fileTemplates/includes/PHP Class Doc Comment.php
generated
Normal file
0
.idea/fileTemplates/includes/PHP Class Doc Comment.php
generated
Normal file
21
.idea/fileTemplates/includes/PHP File Header.php
generated
Normal file
21
.idea/fileTemplates/includes/PHP File Header.php
generated
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
5
.idea/fileTemplates/includes/PHP Function Doc Comment.php
generated
Normal file
5
.idea/fileTemplates/includes/PHP Function Doc Comment.php
generated
Normal file
@ -0,0 +1,5 @@
|
||||
#if (${THROWS_DOC} != "")
|
||||
/**
|
||||
${THROWS_DOC}
|
||||
*/
|
||||
#end
|
0
.idea/fileTemplates/includes/PHP Interface Doc Comment.php
generated
Normal file
0
.idea/fileTemplates/includes/PHP Interface Doc Comment.php
generated
Normal file
1
.idea/fileTemplates/includes/PHP Property Doc Comment.php
generated
Normal file
1
.idea/fileTemplates/includes/PHP Property Doc Comment.php
generated
Normal file
@ -0,0 +1 @@
|
||||
/** @var ${TYPE_HINT} */
|
0
.idea/fileTemplates/includes/PHP Trait Doc Comment.php
generated
Normal file
0
.idea/fileTemplates/includes/PHP Trait Doc Comment.php
generated
Normal file
10
.idea/fileTemplates/internal/PHP Class.php
generated
Normal file
10
.idea/fileTemplates/internal/PHP Class.php
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
#parse("PHP File Header.php")
|
||||
|
||||
#if (${NAMESPACE})
|
||||
namespace ${NAMESPACE};
|
||||
#end
|
||||
|
||||
final class ${NAME} {
|
||||
|
||||
}
|
4
.idea/fileTemplates/internal/PHP File.php
generated
Normal file
4
.idea/fileTemplates/internal/PHP File.php
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
#parse("PHP File Header.php")
|
||||
|
||||
|
10
.idea/fileTemplates/internal/PHP Interface.php
generated
Normal file
10
.idea/fileTemplates/internal/PHP Interface.php
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
#parse("PHP File Header.php")
|
||||
|
||||
#if (${NAMESPACE})
|
||||
namespace ${NAMESPACE};
|
||||
#end
|
||||
|
||||
interface ${NAME} {
|
||||
|
||||
}
|
10
.idea/fileTemplates/internal/PHP Trait.php
generated
Normal file
10
.idea/fileTemplates/internal/PHP Trait.php
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
#parse("PHP File Header.php")
|
||||
|
||||
#if (${NAMESPACE})
|
||||
namespace ${NAMESPACE};
|
||||
#end
|
||||
|
||||
trait ${NAME} {
|
||||
|
||||
}
|
@ -9,7 +9,7 @@ $finder = PhpCsFixer\Finder::create()
|
||||
->notContains('#ifndef COMPILE') //preprocessor will break if these are changed
|
||||
->notName('PocketMine.php');
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
return (new PhpCsFixer\Config)
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
'align_multiline_comment' => [
|
||||
@ -41,13 +41,14 @@ return PhpCsFixer\Config::create()
|
||||
],
|
||||
'indentation_type' => true,
|
||||
'native_function_invocation' => [
|
||||
'scope' => 'namespaced'
|
||||
'scope' => 'namespaced',
|
||||
'include' => ['@all'],
|
||||
],
|
||||
'no_closing_tag' => true,
|
||||
'no_empty_phpdoc' => true,
|
||||
'no_extra_blank_lines' => true,
|
||||
'no_superfluous_phpdoc_tags' => [
|
||||
'allow_mixed' => true,
|
||||
'allow_mixed' => true,
|
||||
],
|
||||
'no_trailing_whitespace' => true,
|
||||
'no_trailing_whitespace_in_comment' => true,
|
@ -2,7 +2,7 @@
|
||||
## Pre-requisites
|
||||
- A bash shell (git bash is sufficient for Windows)
|
||||
- [`git`](https://git-scm.com) available in your shell
|
||||
- PHP 7.3 or newer available in your shell
|
||||
- PHP 7.4 or newer available in your shell
|
||||
- [`composer`](https://getcomposer.org) available in your shell
|
||||
|
||||
## Custom PHP binaries
|
||||
|
181
CONTRIBUTING.md
181
CONTRIBUTING.md
@ -2,125 +2,102 @@
|
||||
|
||||
# PocketMine-MP Contribution Guidelines
|
||||
|
||||
PocketMine-MP is an open source project, and contributions from the community are welcomed, as long as they comply with our quality standards and licensing.
|
||||
|
||||
## Creating an Issue
|
||||
- If you are reporting a bug:
|
||||
- **make sure that you are using the latest supported version** before opening an issue.
|
||||
- **test it on a clean test server, WITHOUT PLUGINS**, to see if the issue still occurs. If not then it may be a plugin issue. Please also indicate the result of such tests.
|
||||
- **[Search the issue tracker](https://github.com/pmmp/PocketMine-MP/issues?utf8=%E2%9C%93&q=is%3Aissue)** to check if anyone has already reported it, to avoid needlessly creating duplicate issues. Make sure you also check closed issues, as an issue you think is valid may already have been resolved.
|
||||
- **Do not report plugin issues here.** If your issue is related to a plugin, contact the plugin's original author instead.
|
||||
- **Support requests are not bugs.** Issues such as "How do I do this" are not bugs and will be closed. If you need help, please see [here](README.md#discussion) and do not misuse our issue tracker.
|
||||
- **No generic titles** such as "Question", "Help", "Crash Report" etc. A good issue report provides a quick summary in the title. If you just got a crash report but you don't understand it, please look for a line starting with `Message`. It summarizes the bug.
|
||||
- **Provide information in the issue body, not in the title.** No tags like `[BUG]` are allowed in the title, including `[SOLVED]` for solved issues.
|
||||
- **No generic issue reports.** For bugs, it is the issue author's responsibility to provide us an issue that is **trackable, debuggable, reproducible, reported professionally and is an actual bug**.
|
||||
<br>Valid issue reports must include instructions how to reproduce the issue or a crashdump/backtrace (unless the cause of the issue is obvious).
|
||||
<br>**If you do not provide us with a summary or instructions on how to reproduce the issue, it will be treated as spam and will therefore be closed.**
|
||||
<br>In simple words, if the issue cannot be properly confirmed to be valid or lacks required information, the issue will be closed until further information is provided.
|
||||
- To express appreciation, objection, confusion or other supported reactions on pull requests, issues or comments on them, use GitHub [reactions](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) rather than posting an individual comment with an emoji only. This helps keeping the issue/pull request conversation clean and readable.
|
||||
- If your issue is related to the PocketMine-MP website, forums, etc., please [talk to a human directly](README.md#discussion).
|
||||
Code contributions must be submitted using [GitHub Pull Requests](https://github.com/pmmp/PocketMine-MP/pulls), where they will be reviewed by maintainers.
|
||||
|
||||
Small contributions (e.g. minor bug fixes) can be submitted as pull requests directly.
|
||||
|
||||
Larger contributions like feature additions should be preceded by a [Change Proposal](#rfcs--change-proposals) to allow maintainers and other people to discuss and decide if it's a good idea or not.
|
||||
|
||||
## Contributing
|
||||
To contribute to the repository, [fork it on GitHub](https://github.com/pmmp/PocketMine-MP/fork), create a branch on your fork, and make your changes on your fork. You can then make a [pull request](https://github.com/pmmp/PocketMine-MP/pull/new) to the project to compare your branch to ours and propose your changes to our repository. We use the Pull Request system to allow members of the team to review changes before they are merged.
|
||||
## Useful documentation from github.com
|
||||
- [About pull requests](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests)
|
||||
- [About forks](https://docs.github.com/en/github/collaborating-with-pull-requests/working-with-forks/about-forks)
|
||||
- [Creating a pull request from a fork](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork)
|
||||
|
||||
### Licensing
|
||||
By proposing a pull request to the project, you agree to your code being distributed within PocketMine-MP under the [LGPL license](LICENSE).
|
||||
## Other things you'll need
|
||||
- [git](https://git-scm.com/)
|
||||
|
||||
### Contribution standards
|
||||
- **We enforce a very high standard for contributions**. This is because PocketMine-MP and its related projects are used very widely in production. While this might seem like we are being mean at times, **our priority is what is best for PocketMine-MP itself**.
|
||||
We try to ensure that our project's codebase is as clean as possible and ensure that only top-quality material makes it through to PocketMine-MP itself.
|
||||
- **If a contribution does not meet our standards, changes may be requested or the pull request may be closed.**
|
||||
## Making a pull request
|
||||
The basic procedure to create a pull request is:
|
||||
1. [Fork the repository on GitHub](https://github.com/pmmp/PocketMine-MP/fork). This gives you your own copy of the repository to make changes to.
|
||||
2. Create a branch on your fork for your changes.
|
||||
3. Make the changes you want to make on this branch.
|
||||
4. You can then make a [pull request](https://github.com/pmmp/PocketMine-MP/pull/new) to the project.
|
||||
|
||||
### Pull requests
|
||||
- **Create a new branch for each pull request.** Do not create a pull request with commits that exist in another pull request.
|
||||
## Pull request reviews
|
||||
Pull requests will be reviewed by maintainers when they are available.
|
||||
Note that there might be a long wait time before a reviewer looks at your PR.
|
||||
|
||||
Depending on the changes, maintainers might ask you to make changes to the PR to fix problems or to improve the code.
|
||||
**Do not delete your fork** while your pull request remains open, otherwise you won't be able to make any requested changes and the PR will end up being declined.
|
||||
|
||||
### Requirements
|
||||
The following are required as a minimum for pull requests. PRs that don't meet these requirements will be declined unless updated to meet them.
|
||||
|
||||
#### Licensing
|
||||
PocketMine-MP is licensed under [LGPLv3 license](LICENSE).
|
||||
By proposing a pull request, you agree to your code being distributed within PocketMine-MP under the same license.
|
||||
If you take code from other projects, that code MUST be licensed under an LGPL-compatible license.
|
||||
|
||||
#### PRs should be about exactly ONE thing
|
||||
If you want to make multiple changes, those changes should each be contributed as separate pull requests. **DO NOT** mix unrelated changes.
|
||||
|
||||
#### PRs must not include unnecessary/unrelated changes
|
||||
Do not include changes which aren't strictly necessary. This makes it harder to review a PR, because the code diff becomes larger and harder to review.
|
||||
This means:
|
||||
- don't reformat or rearrange existing code
|
||||
- don't change things that aren't related to the PR's objective
|
||||
- don't rewrite existing code just to make it "look nicer"
|
||||
- don't change PhpDocs to native types in code you didn't write
|
||||
|
||||
#### Tests must be provided
|
||||
Where possible, PHPUnit tests should be written for new or changed code.
|
||||
If that's not possible (e.g. for in-game functionality), the code must be tested manually and details of the tests done must be provided.
|
||||
**Simply saying "Tested" is not acceptable** and will lead to your PR being declined.
|
||||
|
||||
#### Comments and documentation must be written in American English
|
||||
English is the shared languages of all current maintainers.
|
||||
|
||||
#### Code must be in the PocketMine-MP style
|
||||
It's your responsibility to ensure your code matches the formatting and styling of the rest of the code.
|
||||
If you use PhpStorm, a `Project` code style is provided, which you can use to automatically format new code.
|
||||
You can also use [`php-cs-fixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to format your code.
|
||||
|
||||
### Recommendations
|
||||
|
||||
- **Do not edit code directly on github.com.** We recommend learning how to use [`git`](https://git-scm.com). `git` allows you to "clone" a repository onto your computer, so that you can make changes using an IDE.
|
||||
- **Use an IDE, not a text editor.** We recommend PhpStorm or VSCode.
|
||||
- **Create a new branch on your fork for each pull request.** This allows you to use the same fork to make multiple pull requests at the same time.
|
||||
- **Use descriptive commit titles.** You can see an example [here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||
- **Do not include multiple unrelated changes in one commit.** An atomic style for commits is preferred - this means that changes included in a commit should be part of a single distinct change set. See [this link](https://www.freshconsulting.com/atomic-commits/) for more information on atomic commits. See the [documentation on `git add`](https://git-scm.com/docs/git-add) for information on how to isolate local changes for committing.
|
||||
- **Your pull request will be checked and discussed in due time.** Since the team is scattered all around the world, your PR may not receive any attention for some time.
|
||||
- **It is inadvisable to create large pull requests with lots of changes** unless this has been discussed with the team beforehand. Large pull requests are difficult to review, and such pull requests may end up being closed. The only exception is when all features in the pull request are related to each other, and share the same core changes.
|
||||
- **You may be asked to rebase your pull request** if the branch becomes outdated and/or if possibly conflicting changes are made to the target branch. To see how to do this, read [this page](https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request).
|
||||
- **Details should be provided of tests done.** Simply saying "Tested" or equivalent is not acceptable.
|
||||
|
||||
### Code contributions
|
||||
- **Avoid committing changes directly on GitHub. This includes use of the web editor, and also uploading files.** The web editor lacks most useful GIT features and **should only be used for very minor changes**. It is immediately clear if the web editor has been used, and if so the PR is more likely to be rejected. If you want to make serious contributions, **please learn how to use [GIT version control](https://git-scm.com/)**.
|
||||
- **Do not copy-paste code**. There are potential license issues implicit with copy-pasting, and copy-paste usually indicates a lack of understanding of the actual code. Copy-pasted code is obvious a mile off and **any PR like this is likely to be closed**. If you want to use somebody else's code from a Git repository, **use [GIT's cherry-pick feature](https://git-scm.com/docs/git-cherry-pick)** to cherry-pick the commit. **Cherry-picking is the politer way to copy somebody's changes** and retains all the original accreditation, so there is no need for copy-pasted commits with descriptions like `Some code, thanks @exampleperson`.
|
||||
- **Make sure you can explain your changes**. If you can't provide a good explanation of changes, your PR may be rejected.
|
||||
- **Code should use the same style as in PocketMine-MP.** See [below](#code-syntax) for an example.
|
||||
- **The code must be clear** and written in English, comments included.
|
||||
- **Do not make large pull requests without an RFC.** Large changes should be discussed beforehand using the [RFC / Change Proposal](#rfcs--change-proposals) process. Large changes are much harder to review and are more likely to be declined if maintainers don't have a good idea what you're trying to do in advance.
|
||||
- **Do not copy-paste code**. There are potential license issues implicit with copy-pasting, and copy-paste usually indicates a lack of understanding of the actual code. Copy-pasted code is obvious a mile off and **any PR like this is likely to be closed**. If you want to use somebody else's code from a Git repository, **use [GIT's cherry-pick feature](https://git-scm.com/docs/git-cherry-pick)** to cherry-pick the commit.
|
||||
|
||||
|
||||
**Thanks for contributing to PocketMine-MP!**
|
||||
|
||||
## RFCs / Change Proposals
|
||||
Change Proposals are issues or discussions which describe a new feature proposal or behavioural change.
|
||||
They are used to get feedback from maintainers and the community about an idea for a change, to decide whether or not it's a good idea.
|
||||
|
||||
### Submitting an RFC
|
||||
RFCs should be submitted using Issues or Discussions.
|
||||
RFCs _can_ be submitted as pull requests if you've already written the code, but this is not recommended, since it's not guaranteed that an RFC will pass, in which case your effort would be wasted.
|
||||
|
||||
### Code Syntax
|
||||
RFCs should include the following:
|
||||
- A summary of what you want to change
|
||||
- Why you want to change it (e.g. what problems it solves)
|
||||
- Alternative methods you've considered to solve the problem. This should include any possible ways that what you want can be done without the change.
|
||||
|
||||
It is mainly [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) with a few exceptions.
|
||||
### Voting on RFCs
|
||||
Community members can vote on RFCs. This gives maintainers an idea of how popular the idea is.
|
||||
Votes can be cast using :+1: and :-1: reactions.
|
||||
|
||||
- Opening braces MUST go on the same line, and MUST NOT have spaces before.
|
||||
- `else if` MUST be written as `elseif`. _(It is in PSR-2, but using a SHOULD)_
|
||||
- Control structure keywords or opening braces MUST NOT have one space before or after them.
|
||||
- Code MUST use tabs for indenting.
|
||||
- Long arrays MAY be split across multiple lines, where each subsequent line is indented once.
|
||||
- Files MUST use only the `<?php` tag.
|
||||
- Files MUST NOT have an ending `?>` tag.
|
||||
- Code MUST use namespaces.
|
||||
- Strings SHOULD use the double quote `"` except when the single quote is required.
|
||||
- All code SHOULD have parameter and type declarations where possible.
|
||||
- Strict types SHOULD be enabled on new files where it is sensible to do so.
|
||||
- All constant declarations SHOULD be preceded by a visibility modifier.
|
||||
**Please don't downvote without providing a reason why!**
|
||||
|
||||
```php
|
||||
<?php
|
||||
### Implementing RFCs
|
||||
Anyone can write the code to implement an RFC, and submit a pull request for it. It doesn't have to be the RFC author.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\example;
|
||||
|
||||
class ExampleClass{
|
||||
|
||||
public const EXAMPLE_CLASS_CONSTANT = 1;
|
||||
|
||||
public $examplePublicVariable = "defaultValue";
|
||||
private $examplePrivateVariable;
|
||||
|
||||
/**
|
||||
* Creates an instance of ExampleClass
|
||||
*
|
||||
* @param string $firstArgument the first argument
|
||||
* @param string|null $secondArgument default null
|
||||
*/
|
||||
public function __construct(string $firstArgument, ?string &$secondArgument = null){
|
||||
if($firstArgument === "exampleValue"){ //Remember to use === instead of == when possible
|
||||
//do things
|
||||
}elseif($firstArgument === "otherValue"){
|
||||
$secondArgument = function(){
|
||||
$this->examplePrivateVariable = [
|
||||
0 => "value1",
|
||||
1 => "value2",
|
||||
2 => "value3",
|
||||
3 => "value4",
|
||||
4 => "value5",
|
||||
5 => "value6",
|
||||
];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public function doStuff(string $stuff) : string{
|
||||
return $stuff;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- TODO: RFC and voting on the forums instead -->
|
||||
### RFC and Voting
|
||||
* These are big Pull Requests or contributions that change important behavior.
|
||||
* RFCs will be tagged with the *Type: Request For Comments* label
|
||||
* A vote will be held once the RFC is ready. All users can vote commenting on the Pull Request
|
||||
* Comments MUST use "Yes" or "No" on the FIRST sentence to signify the vote, except when they don't want it to be counted.
|
||||
* If your comment is a voting comment, specify the reason of your vote or it won't be counted.
|
||||
* After voting has been closed, no further votes will be counted.
|
||||
* An RFC will be rejected if less than 50% + 1 (simple majority) has voted Yes.
|
||||
* If the RFC is approved, Team Members have the final word on its implementation or rejection.
|
||||
* RFCs with complex voting options will specify the vote percentage or other details.
|
||||
Implementations should be submitted as pull requests. The pull request description must include a link to the RFC.
|
||||
|
@ -1,13 +1,5 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
The following release lines are currently receiving active security updates and bug fixes:
|
||||
|
||||
| Version | Supported |
|
||||
| -------- | ------------------ |
|
||||
| 3.15.x | :white_check_mark: |
|
||||
| < 3.15.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
**DO NOT report vulnerabilities on the GitHub issue tracker.**
|
||||
|
43
build/generate-build-info-json.php
Normal file
43
build/generate-build-info-json.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if(count($argv) !== 4){
|
||||
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)>");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION),
|
||||
"base_version" => \pocketmine\BASE_VERSION,
|
||||
"build" => \pocketmine\BUILD_NUMBER,
|
||||
"is_dev" => \pocketmine\IS_DEVELOPMENT_BUILD,
|
||||
"channel" => \pocketmine\BUILD_CHANNEL,
|
||||
"git_commit" => $argv[1],
|
||||
"mcpe_version" => \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK,
|
||||
"date" => time(), //TODO: maybe we should embed this in VersionInfo?
|
||||
"details_url" => "https://github.com/$argv[3]/releases/tag/$argv[2]",
|
||||
"download_url" => "https://github.com/$argv[3]/releases/download/$argv[2]/PocketMine-MP.phar",
|
||||
"source_url" => "https://github.com/$argv[3]/tree/$argv[2]",
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
|
@ -24,20 +24,23 @@ declare(strict_types=1);
|
||||
namespace pocketmine\build\make_release;
|
||||
|
||||
use pocketmine\utils\VersionString;
|
||||
use function count;
|
||||
use function dirname;
|
||||
use function fgets;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function fwrite;
|
||||
use function preg_replace;
|
||||
use function sleep;
|
||||
use function sprintf;
|
||||
use function system;
|
||||
use const pocketmine\BASE_VERSION;
|
||||
use const STDERR;
|
||||
use const STDIN;
|
||||
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev) : void{
|
||||
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev, string $channel) : void{
|
||||
$versionInfo = file_get_contents($versionInfoPath);
|
||||
$versionInfo = preg_replace(
|
||||
$pattern = '/^const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m',
|
||||
@ -49,6 +52,11 @@ function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev
|
||||
'const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false') . ';',
|
||||
$versionInfo
|
||||
);
|
||||
$versionInfo = preg_replace(
|
||||
'/^const BUILD_CHANNEL = ".*";$/m',
|
||||
'const BUILD_CHANNEL = "' . $channel . '";',
|
||||
$versionInfo
|
||||
);
|
||||
file_put_contents($versionInfoPath, $versionInfo);
|
||||
}
|
||||
|
||||
@ -57,8 +65,12 @@ function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev
|
||||
* @phpstan-param list<string> $argv
|
||||
*/
|
||||
function main(array $argv) : void{
|
||||
if(isset($argv[1])){
|
||||
$currentVer = new VersionString($argv[1]);
|
||||
if(count($argv) < 2){
|
||||
fwrite(STDERR, "Arguments: <channel> [release version]\n");
|
||||
exit(1);
|
||||
}
|
||||
if(isset($argv[2])){
|
||||
$currentVer = new VersionString($argv[2]);
|
||||
}else{
|
||||
$currentVer = new VersionString(BASE_VERSION);
|
||||
}
|
||||
@ -69,15 +81,20 @@ function main(array $argv) : void{
|
||||
$currentVer->getPatch() + 1
|
||||
));
|
||||
|
||||
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
|
||||
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
|
||||
|
||||
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
|
||||
echo "please add appropriate notes to the changelog and press enter...";
|
||||
fgets(STDIN);
|
||||
system('git add "' . dirname(__DIR__) . '/changelogs"');
|
||||
system('git diff --cached --quiet "' . dirname(__DIR__) . '/changelogs"', $result);
|
||||
if($result === 0){
|
||||
echo "error: no changelog changes detected; aborting\n";
|
||||
exit(1);
|
||||
}
|
||||
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
|
||||
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $argv[1]);
|
||||
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
|
||||
system('git tag ' . $currentVer->getBaseVersion());
|
||||
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true);
|
||||
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, "");
|
||||
system('git add "' . $versionInfoPath . '"');
|
||||
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
|
||||
echo "pushing changes in 5 seconds\n";
|
||||
|
Submodule build/php updated: c64baa0f1c...e55c60f176
31
changelogs/3.19.md
Normal file
31
changelogs/3.19.md
Normal file
@ -0,0 +1,31 @@
|
||||
**For Minecraft: Bedrock Edition 1.16.220**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 3.19.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.16.220.
|
||||
- Removed compatibility with earlier versions.
|
||||
|
||||
## Known issues (please don't open issues for these)
|
||||
- Walls don't connect to each other
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
|
||||
# 3.19.1
|
||||
- Fixed some particles not working since 1.16.220.
|
||||
- Fixed issues with creative inventory items appearing in the wrong places since 1.16.220.
|
||||
- `Item->removeEnchantment()` now removes the `ench` tag from item NBT when removing the only enchantment on an item.
|
||||
- Fixed temporary memory leak of repeating tasks which cancelled themselves during their `onRun()` handler (they were pushed back onto the task queue even though cancelled, and only removed at their next attempted repeat).
|
||||
|
||||
# 3.19.2
|
||||
- Signs can now only be edited by the player who placed them. They will become finalized if the chunk containing them is unloaded and reloaded, or if the creating player quits the server.
|
||||
|
||||
# 3.19.3
|
||||
- Fixed `Worker->quit()` returning without stopping the thread.
|
||||
- Added some protocol constants in `SetDisplayObjectivePacket`.
|
||||
- Fixed possible client crash caused by `CraftingDataPacket`.
|
11
changelogs/3.20.md
Normal file
11
changelogs/3.20.md
Normal file
@ -0,0 +1,11 @@
|
||||
**For Minecraft: Bedrock Edition 1.17.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 3.20.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.17.0
|
||||
- Removed compatibility with earlier versions.
|
15
changelogs/3.21.md
Normal file
15
changelogs/3.21.md
Normal file
@ -0,0 +1,15 @@
|
||||
**For Minecraft: Bedrock Edition 1.17.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 3.21.0
|
||||
- PHP 7.4 is now required as a minimum.
|
||||
- A workaround for player movement added in 1.14.30 has been removed.
|
||||
|
||||
# 3.21.1
|
||||
- Fixed so-called 'pot lag' - a bug that could occur when using items while rapidly switching hotbar slots.
|
||||
- Plugins in crashdumps are now ordered alphabetically for easier reading.
|
33
changelogs/3.22.md
Normal file
33
changelogs/3.22.md
Normal file
@ -0,0 +1,33 @@
|
||||
**For Minecraft: Bedrock Edition 1.17.10**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 3.22.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.17.10.
|
||||
- Removed compatibility with earlier versions.
|
||||
|
||||
# 3.22.1
|
||||
- Added a giant yellow startup warning if using OPcache JIT on PHP 8.0. JIT is currently considered highly unstable and not recommended for production use.
|
||||
- When using a bad PHP binary, the bootstrap will now report the used `php.ini` path. This can be useful for debugging issues with extension loading when the wrong `php.ini` file is loaded for some reason.
|
||||
- Fixed `start.cmd` causing the wrong `php.ini` to be loaded on Windows when a global PHP installation is used.
|
||||
- A debug message is now logged containing expected vs. actual XUID of players when an XUID mismatch is detected.
|
||||
- Improved the documentation for `Player->getUniqueId()`.
|
||||
- Fixed a mistake in the documentation of `PlayerAuthInputFlags`.
|
||||
- Fixed incorrect encoding of `NpcDialoguePacket`.
|
||||
|
||||
# 3.22.2
|
||||
- PHP 8.0 is now the primary supported version. PHP 7.4 is still supported for now, but it will be dropped in the coming weeks. It's recommended to start testing your servers on 8.0 now so you're ready.
|
||||
- Fixed items in the crafting grid getting deleted on server-side disconnect or session timeout.
|
||||
- A warning is now logged on startup if a debug build of PHP is used to run the server (because it has a significant performance impact).
|
||||
- GitHub Actions is now used to build new releases, instead of Jenkins. You can see build logs [here](https://github.com/pmmp/PocketMine-MP/actions/workflows/draft-release.yml).
|
||||
|
||||
# 3.22.3
|
||||
- Fixed a bug in the release build of 3.22.2 which caused the crash archive to reject all crashdumps.
|
||||
- Fixed possible server crash during player spawning.
|
||||
|
||||
# 3.22.4
|
||||
- Fixed a bug which broke the build of 3.22.3.
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "pocketmine/pocketmine-mp",
|
||||
"description": "A server software for Minecraft: Pocket Edition written in PHP",
|
||||
"description": "A server software for Minecraft: Bedrock Edition written in PHP",
|
||||
"type": "project",
|
||||
"homepage": "https://pmmp.io",
|
||||
"license": "LGPL-3.0",
|
||||
"require": {
|
||||
"php": "^7.3 || ^8.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"php-64bit": "*",
|
||||
"ext-ctype": "*",
|
||||
"ext-curl": "*",
|
||||
@ -38,7 +38,7 @@
|
||||
"pocketmine/spl": "^0.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "0.12.83",
|
||||
"phpstan/phpstan": "0.12.98",
|
||||
"phpstan/phpstan-phpunit": "^0.12.6",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.2",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
@ -60,14 +60,14 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.3.0"
|
||||
"php": "7.4.0"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/DevTools/ConsoleScript.php --make tests/plugins/DevTools --out plugins/DevTools.phar",
|
||||
"make-server": [
|
||||
"@composer install --no-dev --classmap-authoritative",
|
||||
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
|
||||
"@php -dphar.readonly=0 build/server-phar.php"
|
||||
]
|
||||
}
|
||||
|
161
composer.lock
generated
161
composer.lock
generated
@ -4,20 +4,20 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c07802390fc058bf06b3a1741ef7c08e",
|
||||
"content-hash": "8fc787ba6d9029fb6daa3e8c112b76c5",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/adhocore/php-json-comment.git",
|
||||
"reference": "cf7998124d1050b83d7d985447fefd630e09c1a2"
|
||||
"reference": "fc2f76979f0a44a5f5bc2a2b600d0762fe0e78e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/cf7998124d1050b83d7d985447fefd630e09c1a2",
|
||||
"reference": "cf7998124d1050b83d7d985447fefd630e09c1a2",
|
||||
"url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/fc2f76979f0a44a5f5bc2a2b600d0762fe0e78e7",
|
||||
"reference": "fc2f76979f0a44a5f5bc2a2b600d0762fe0e78e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -51,7 +51,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/adhocore/php-json-comment/issues",
|
||||
"source": "https://github.com/adhocore/php-json-comment/tree/1.1.0"
|
||||
"source": "https://github.com/adhocore/php-json-comment/tree/1.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -59,7 +59,7 @@
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2021-04-05T13:11:13+00:00"
|
||||
"time": "2021-04-09T03:06:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -617,16 +617,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.10.4",
|
||||
"version": "v4.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e"
|
||||
"reference": "6608f01670c3cc5079e18c1dab1104e002579143"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e",
|
||||
"reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143",
|
||||
"reference": "6608f01670c3cc5079e18c1dab1104e002579143",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -667,22 +667,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0"
|
||||
},
|
||||
"time": "2020-12-20T10:01:03+00:00"
|
||||
"time": "2021-07-21T10:44:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
"version": "2.0.1",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phar-io/manifest.git",
|
||||
"reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133"
|
||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133",
|
||||
"reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133",
|
||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
|
||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -727,9 +727,9 @@
|
||||
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
|
||||
"support": {
|
||||
"issues": "https://github.com/phar-io/manifest/issues",
|
||||
"source": "https://github.com/phar-io/manifest/tree/master"
|
||||
"source": "https://github.com/phar-io/manifest/tree/2.0.3"
|
||||
},
|
||||
"time": "2020-06-27T14:33:11+00:00"
|
||||
"time": "2021-07-20T11:28:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/version",
|
||||
@ -1009,16 +1009,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "0.12.83",
|
||||
"version": "0.12.98",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "4a967cec6efb46b500dd6d768657336a3ffe699f"
|
||||
"reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/4a967cec6efb46b500dd6d768657336a3ffe699f",
|
||||
"reference": "4a967cec6efb46b500dd6d768657336a3ffe699f",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3bb7cc246c057405dd5e290c3ecc62ab51d57e00",
|
||||
"reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1049,13 +1049,17 @@
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/0.12.83"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/0.12.98"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ondrejmirtes",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/phpstan",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpstan",
|
||||
"type": "patreon"
|
||||
@ -1065,34 +1069,33 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-04-03T15:35:45+00:00"
|
||||
"time": "2021-09-02T12:33:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "0.12.18",
|
||||
"version": "0.12.22",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72"
|
||||
"reference": "7c01ef93bf128b4ac8bdad38c54b2a4fd6b0b3cc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72",
|
||||
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/7c01ef93bf128b4ac8bdad38c54b2a4fd6b0b3cc",
|
||||
"reference": "7c01ef93bf128b4ac8bdad38c54b2a4fd6b0b3cc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"phpstan/phpstan": "^0.12.60"
|
||||
"phpstan/phpstan": "^0.12.92"
|
||||
},
|
||||
"conflict": {
|
||||
"phpunit/phpunit": "<7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "^2.16.3",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.6",
|
||||
"phpunit/phpunit": "^7.5.20"
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"type": "phpstan-extension",
|
||||
"extra": {
|
||||
@ -1118,33 +1121,32 @@
|
||||
"description": "PHPUnit extensions and rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.18"
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.22"
|
||||
},
|
||||
"time": "2021-03-06T11:51:27+00:00"
|
||||
"time": "2021-08-12T10:53:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
"version": "0.12.9",
|
||||
"version": "0.12.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "0705fefc7c9168529fd130e341428f5f10f4f01d"
|
||||
"reference": "2b72e8e17d2034145f239126e876e5fb659675e2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/0705fefc7c9168529fd130e341428f5f10f4f01d",
|
||||
"reference": "0705fefc7c9168529fd130e341428f5f10f4f01d",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/2b72e8e17d2034145f239126e876e5fb659675e2",
|
||||
"reference": "2b72e8e17d2034145f239126e876e5fb659675e2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"phpstan/phpstan": "^0.12.66"
|
||||
"phpstan/phpstan": "^0.12.96"
|
||||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "^2.16.3",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/phpstan-phpunit": "^0.12.16",
|
||||
"phpunit/phpunit": "^7.5.20"
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"type": "phpstan-extension",
|
||||
"extra": {
|
||||
@ -1169,9 +1171,9 @@
|
||||
"description": "Extra strict and opinionated rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/0.12.9"
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/0.12.11"
|
||||
},
|
||||
"time": "2021-01-13T08:50:28+00:00"
|
||||
"time": "2021-08-21T11:36:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@ -1493,16 +1495,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.5.4",
|
||||
"version": "9.5.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741"
|
||||
"reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c73c6737305e779771147af66c96ca6a7ed8a741",
|
||||
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b",
|
||||
"reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1514,7 +1516,7 @@
|
||||
"ext-xml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"myclabs/deep-copy": "^1.10.1",
|
||||
"phar-io/manifest": "^2.0.1",
|
||||
"phar-io/manifest": "^2.0.3",
|
||||
"phar-io/version": "^3.0.2",
|
||||
"php": ">=7.3",
|
||||
"phpspec/prophecy": "^1.12.1",
|
||||
@ -1532,7 +1534,7 @@
|
||||
"sebastian/global-state": "^5.0.1",
|
||||
"sebastian/object-enumerator": "^4.0.3",
|
||||
"sebastian/resource-operations": "^3.0.3",
|
||||
"sebastian/type": "^2.3",
|
||||
"sebastian/type": "^2.3.4",
|
||||
"sebastian/version": "^3.0.2"
|
||||
},
|
||||
"require-dev": {
|
||||
@ -1580,7 +1582,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.4"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.9"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1592,7 +1594,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-23T07:16:29+00:00"
|
||||
"time": "2021-08-31T06:47:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@ -2100,16 +2102,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||
"reference": "a90ccbddffa067b51f574dea6eb25d5680839455"
|
||||
"reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455",
|
||||
"reference": "a90ccbddffa067b51f574dea6eb25d5680839455",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49",
|
||||
"reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2152,7 +2154,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2"
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2160,7 +2162,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-26T15:55:19+00:00"
|
||||
"time": "2021-06-11T13:31:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/lines-of-code",
|
||||
@ -2447,20 +2449,21 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2020-09-28T06:45:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/type",
|
||||
"version": "2.3.1",
|
||||
"version": "2.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/type.git",
|
||||
"reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2"
|
||||
"reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2",
|
||||
"reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914",
|
||||
"reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2495,7 +2498,7 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/type",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/type/issues",
|
||||
"source": "https://github.com/sebastianbergmann/type/tree/2.3.1"
|
||||
"source": "https://github.com/sebastianbergmann/type/tree/2.3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2503,7 +2506,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-26T13:18:59+00:00"
|
||||
"time": "2021-06-15T12:49:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
@ -2560,16 +2563,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.22.1",
|
||||
"version": "v1.23.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
|
||||
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
|
||||
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce",
|
||||
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2581,7 +2584,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.22-dev"
|
||||
"dev-main": "1.23-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@ -2619,7 +2622,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2635,20 +2638,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-01-07T16:49:33+00:00"
|
||||
"time": "2021-02-19T12:13:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "75a63c33a8577608444246075ea0af0d052e452a"
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a",
|
||||
"reference": "75a63c33a8577608444246075ea0af0d052e452a",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2677,7 +2680,7 @@
|
||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"support": {
|
||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||
"source": "https://github.com/theseer/tokenizer/tree/master"
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2685,7 +2688,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-12T23:59:07+00:00"
|
||||
"time": "2021-07-28T10:34:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
@ -2752,7 +2755,7 @@
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^7.3 || ^8.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"php-64bit": "*",
|
||||
"ext-ctype": "*",
|
||||
"ext-curl": "*",
|
||||
@ -2775,7 +2778,7 @@
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
"php": "7.3.0"
|
||||
"php": "7.4.0"
|
||||
},
|
||||
"plugin-api-version": "2.0.0"
|
||||
"plugin-api-version": "2.1.0"
|
||||
}
|
||||
|
@ -4,11 +4,13 @@ includes:
|
||||
- tests/phpstan/configs/gc-hacks.neon
|
||||
- tests/phpstan/configs/l7-baseline.neon
|
||||
- tests/phpstan/configs/l8-baseline.neon
|
||||
- tests/phpstan/configs/php74-compat.neon
|
||||
- tests/phpstan/configs/php-bugs.neon
|
||||
- tests/phpstan/configs/phpstan-bugs.neon
|
||||
- tests/phpstan/configs/phpunit-wiring-tests.neon
|
||||
- tests/phpstan/configs/pthreads-bugs.neon
|
||||
- tests/phpstan/configs/runtime-type-checks.neon
|
||||
- tests/phpstan/configs/spl-fixed-array-sucks.neon
|
||||
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||
- vendor/phpstan/phpstan-phpunit/rules.neon
|
||||
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||
@ -20,7 +22,7 @@ parameters:
|
||||
bootstrapFiles:
|
||||
- tests/phpstan/bootstrap.php
|
||||
scanDirectories:
|
||||
- tests/plugins/TesterPlugin
|
||||
- tests/plugins/TesterPlugin
|
||||
scanFiles:
|
||||
- src/pocketmine/PocketMine.php
|
||||
- build/make-release.php
|
||||
@ -42,8 +44,10 @@ parameters:
|
||||
staticReflectionClassNamePatterns:
|
||||
- "#^COM$#"
|
||||
typeAliases:
|
||||
#variadics don't work for this - mixed probably shouldn't work either, but for now it does
|
||||
#what we actually need is something that accepts an infinite number of parameters, but in the absence of that,
|
||||
#we'll just fill it with 10 - it's very unlikely to encounter a callable with 10 parameters anyway.
|
||||
anyCallable: 'callable(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed'
|
||||
anyClosure: '\Closure(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed'
|
||||
#variadics don't work for this - mixed probably shouldn't work either, but for now it does
|
||||
#what we actually need is something that accepts an infinite number of parameters, but in the absence of that,
|
||||
#we'll just fill it with 10 - it's very unlikely to encounter a callable with 10 parameters anyway.
|
||||
anyCallable: 'callable(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed'
|
||||
anyClosure: '\Closure(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed'
|
||||
PhpSocket: '\Socket'
|
||||
PhpCurlHandle: '\CurlHandle'
|
||||
|
9
phpstan.php7.neon
Normal file
9
phpstan.php7.neon
Normal file
@ -0,0 +1,9 @@
|
||||
includes:
|
||||
- phpstan.neon.dist
|
||||
- tests/phpstan/configs/php7.neon
|
||||
|
||||
parameters:
|
||||
phpVersion: 70400
|
||||
typeAliases:
|
||||
PhpSocket: resource
|
||||
PhpCurlHandle: resource
|
@ -46,6 +46,7 @@ use function is_dir;
|
||||
use function is_resource;
|
||||
use function json_encode;
|
||||
use function json_last_error_msg;
|
||||
use function ksort;
|
||||
use function max;
|
||||
use function microtime;
|
||||
use function mkdir;
|
||||
@ -81,6 +82,7 @@ use const FILE_IGNORE_NEW_LINES;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
use const PHP_EOL;
|
||||
use const PHP_OS;
|
||||
use const SORT_STRING;
|
||||
|
||||
class CrashDump{
|
||||
|
||||
@ -182,7 +184,9 @@ class CrashDump{
|
||||
$this->addLine();
|
||||
$this->addLine("Loaded plugins:");
|
||||
$this->data["plugins"] = [];
|
||||
foreach($this->server->getPluginManager()->getPlugins() as $p){
|
||||
$plugins = $this->server->getPluginManager()->getPlugins();
|
||||
ksort($plugins, SORT_STRING);
|
||||
foreach($plugins as $p){
|
||||
$d = $p->getDescription();
|
||||
$this->data["plugins"][$d->getName()] = [
|
||||
"name" => $d->getName(),
|
||||
|
@ -152,7 +152,12 @@ use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||
use pocketmine\network\mcpe\protocol\types\Experiments;
|
||||
use pocketmine\network\mcpe\protocol\types\GameMode;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\NormalTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ReleaseItemTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
use pocketmine\network\mcpe\protocol\types\PersonaPieceTintColor;
|
||||
use pocketmine\network\mcpe\protocol\types\PersonaSkinPiece;
|
||||
@ -210,6 +215,7 @@ use function min;
|
||||
use function preg_match;
|
||||
use function round;
|
||||
use function spl_object_hash;
|
||||
use function sprintf;
|
||||
use function sqrt;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
@ -413,7 +419,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
/** @var float */
|
||||
protected $lastRightClickTime = 0.0;
|
||||
/** @var \stdClass|null */
|
||||
/** @var UseItemTransactionData|null */
|
||||
protected $lastRightClickData = null;
|
||||
|
||||
/**
|
||||
@ -477,19 +483,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the player's UUID. This should be preferred over their Xbox user ID (XUID) because UUID is a standard
|
||||
* format which will never change, and all players will have one regardless of whether they are logged into Xbox
|
||||
* Live.
|
||||
* Returns the player's UUID. This should be the preferred method to identify a player.
|
||||
* It does not change if the player changes their username.
|
||||
*
|
||||
* The UUID is comprised of:
|
||||
* - when logged into XBL: a hash of their XUID (and as such will not change for the lifetime of the XBL account)
|
||||
* - when NOT logged into XBL: a hash of their name + clientID + secret device ID.
|
||||
* All players will have a UUID, regardless of whether they are logged into Xbox Live or not. However, note that
|
||||
* non-XBL players can fake their UUIDs.
|
||||
*
|
||||
* WARNING: UUIDs of players **not logged into Xbox Live** CAN BE FAKED and SHOULD NOT be trusted!
|
||||
*
|
||||
* (In the olden days this method used to return a fake UUID computed by the server, which was used by plugins such
|
||||
* as SimpleAuth for authentication. This is NOT SAFE anymore as this UUID is now what was given by the client, NOT
|
||||
* a server-computed UUID.)
|
||||
* WARNING: DO NOT trust this before PlayerLoginEvent. Before PlayerLoginEvent, the player hasn't yet been
|
||||
* authenticated, and any of their data might be faked.
|
||||
*/
|
||||
public function getUniqueId() : ?UUID{
|
||||
return parent::getUniqueId();
|
||||
@ -1072,7 +1073,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
* @return void
|
||||
*/
|
||||
public function doFirstSpawn(){
|
||||
if($this->spawned){
|
||||
if($this->spawned || !$this->constructed){
|
||||
return; //avoid player spawning twice (this can only happen on 3.x with a custom malicious client)
|
||||
}
|
||||
$this->spawned = true;
|
||||
@ -2081,6 +2082,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$checkXUID = (bool) $this->server->getProperty("player.verify-xuid", true);
|
||||
$kickForXUIDMismatch = function(string $xuid) use ($checkXUID) : bool{
|
||||
if($checkXUID && $this->xuid !== $xuid){
|
||||
$this->server->getLogger()->debug($this->getName() . " XUID mismatch: expected '$xuid', but got '$this->xuid'");
|
||||
if($this->kick("XUID does not match (possible impersonation attempt)", false)){
|
||||
//TODO: Longer term, we should be identifying playerdata using something more reliable, like XUID or UUID.
|
||||
//However, that would be a very disruptive change, so this will serve as a stopgap for now.
|
||||
@ -2274,6 +2276,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$pk->experiments = new Experiments([], false);
|
||||
$pk->itemTable = ItemTypeDictionary::getInstance()->getEntries();
|
||||
$pk->playerMovementSettings = new PlayerMovementSettings(PlayerMovementType::LEGACY, 0, false);
|
||||
$pk->serverSoftwareVersion = sprintf("%s %s", \pocketmine\NAME, \pocketmine\VERSION);
|
||||
$this->dataPacket($pk);
|
||||
|
||||
$this->sendDataPacket(new AvailableActorIdentifiersPacket());
|
||||
@ -2435,14 +2438,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
/** @var InventoryAction[] $actions */
|
||||
$actions = [];
|
||||
$isCraftingPart = false;
|
||||
foreach($packet->actions as $networkInventoryAction){
|
||||
foreach($packet->trData->getActions() as $networkInventoryAction){
|
||||
if(
|
||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_TODO and (
|
||||
$networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT or
|
||||
$networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_USE_INGREDIENT
|
||||
) or (
|
||||
$this->craftingTransaction !== null &&
|
||||
!$networkInventoryAction->oldItem->equalsExact($networkInventoryAction->newItem) &&
|
||||
!$networkInventoryAction->oldItem->getItemStack()->equalsExact($networkInventoryAction->newItem->getItemStack()) &&
|
||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER &&
|
||||
$networkInventoryAction->windowId === ContainerIds::UI &&
|
||||
$networkInventoryAction->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT
|
||||
@ -2493,321 +2496,325 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$this->craftingTransaction = null;
|
||||
}
|
||||
|
||||
switch($packet->transactionType){
|
||||
case InventoryTransactionPacket::TYPE_NORMAL:
|
||||
$this->setUsingItem(false);
|
||||
$transaction = new InventoryTransaction($this, $actions);
|
||||
if($packet->trData instanceof NormalTransactionData){
|
||||
$this->setUsingItem(false);
|
||||
$transaction = new InventoryTransaction($this, $actions);
|
||||
|
||||
try{
|
||||
$transaction->execute();
|
||||
}catch(TransactionValidationException $e){
|
||||
$this->server->getLogger()->debug("Failed to execute inventory transaction from " . $this->getName() . ": " . $e->getMessage());
|
||||
$this->server->getLogger()->debug("Actions: " . json_encode($packet->actions));
|
||||
try{
|
||||
$transaction->execute();
|
||||
}catch(TransactionValidationException $e){
|
||||
$this->server->getLogger()->debug("Failed to execute inventory transaction from " . $this->getName() . ": " . $e->getMessage());
|
||||
$this->server->getLogger()->debug("Actions: " . json_encode($packet->trData->getActions()));
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//TODO: fix achievement for getting iron from furnace
|
||||
//TODO: fix achievement for getting iron from furnace
|
||||
|
||||
return true;
|
||||
case InventoryTransactionPacket::TYPE_MISMATCH:
|
||||
if(count($packet->actions) > 0){
|
||||
$this->server->getLogger()->debug("Expected 0 actions for mismatch, got " . count($packet->actions) . ", " . json_encode($packet->actions));
|
||||
}
|
||||
$this->setUsingItem(false);
|
||||
$this->sendAllInventories();
|
||||
return true;
|
||||
}elseif($packet->trData instanceof MismatchTransactionData){
|
||||
if(count($packet->trData->getActions()) > 0){
|
||||
$this->server->getLogger()->debug("Expected 0 actions for mismatch, got " . count($packet->trData->getActions()) . ", " . json_encode($packet->trData->getActions()));
|
||||
}
|
||||
$this->setUsingItem(false);
|
||||
$this->sendAllInventories();
|
||||
|
||||
return true;
|
||||
case InventoryTransactionPacket::TYPE_USE_ITEM:
|
||||
$blockVector = new Vector3($packet->trData->x, $packet->trData->y, $packet->trData->z);
|
||||
$face = $packet->trData->face;
|
||||
return true;
|
||||
}elseif($packet->trData instanceof UseItemTransactionData){
|
||||
|
||||
$type = $packet->trData->actionType;
|
||||
switch($type){
|
||||
case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_BLOCK:
|
||||
//TODO: start hack for client spam bug
|
||||
$spamBug = ($this->lastRightClickData !== null and
|
||||
microtime(true) - $this->lastRightClickTime < 0.1 and //100ms
|
||||
$this->lastRightClickData->playerPos->distanceSquared($packet->trData->playerPos) < 0.00001 and
|
||||
$this->lastRightClickData->x === $packet->trData->x and
|
||||
$this->lastRightClickData->y === $packet->trData->y and
|
||||
$this->lastRightClickData->z === $packet->trData->z and
|
||||
$this->lastRightClickData->clickPos->distanceSquared($packet->trData->clickPos) < 0.00001 //signature spam bug has 0 distance, but allow some error
|
||||
);
|
||||
//get rid of continued spam if the player clicks and holds right-click
|
||||
$this->lastRightClickData = $packet->trData;
|
||||
$this->lastRightClickTime = microtime(true);
|
||||
if($spamBug){
|
||||
return true;
|
||||
}
|
||||
//TODO: end hack for client spam bug
|
||||
$blockVector = $packet->trData->getBlockPos();
|
||||
$face = $packet->trData->getFace();
|
||||
|
||||
$this->setUsingItem(false);
|
||||
|
||||
if(!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13)){
|
||||
}elseif($this->isCreative()){
|
||||
$item = $this->inventory->getItemInHand();
|
||||
if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->clickPos, $this, true)){
|
||||
return true;
|
||||
}
|
||||
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->itemInHand)){
|
||||
$this->inventory->sendHeldItem($this);
|
||||
}else{
|
||||
$item = $this->inventory->getItemInHand();
|
||||
$oldItem = clone $item;
|
||||
if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->clickPos, $this, true)){
|
||||
if(!$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){
|
||||
$this->inventory->setItemInHand($item);
|
||||
$this->inventory->sendHeldItem($this->hasSpawned);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->inventory->sendHeldItem($this);
|
||||
|
||||
if($blockVector->distanceSquared($this) > 10000){
|
||||
return true;
|
||||
}
|
||||
|
||||
$target = $this->level->getBlock($blockVector);
|
||||
$block = $target->getSide($face);
|
||||
|
||||
/** @var Block[] $blocks */
|
||||
$blocks = array_merge($target->getAllSides(), $block->getAllSides()); //getAllSides() on each of these will include $target and $block because they are next to each other
|
||||
|
||||
$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);
|
||||
if($this->inventory->getHeldItemIndex() !== $packet->trData->getHotbarSlot()){
|
||||
$this->inventory->equipItem($packet->trData->getHotbarSlot());
|
||||
}
|
||||
|
||||
switch($packet->trData->getActionType()){
|
||||
case UseItemTransactionData::ACTION_CLICK_BLOCK:
|
||||
//TODO: start hack for client spam bug
|
||||
$spamBug = ($this->lastRightClickData !== null and
|
||||
microtime(true) - $this->lastRightClickTime < 0.1 and //100ms
|
||||
$this->lastRightClickData->getPlayerPos()->distanceSquared($packet->trData->getPlayerPos()) < 0.00001 and
|
||||
$this->lastRightClickData->getBlockPos()->equals($packet->trData->getBlockPos()) and
|
||||
$this->lastRightClickData->getClickPos()->distanceSquared($packet->trData->getClickPos()) < 0.00001 //signature spam bug has 0 distance, but allow some error
|
||||
);
|
||||
//get rid of continued spam if the player clicks and holds right-click
|
||||
$this->lastRightClickData = $packet->trData;
|
||||
$this->lastRightClickTime = microtime(true);
|
||||
if($spamBug){
|
||||
return true;
|
||||
case InventoryTransactionPacket::USE_ITEM_ACTION_BREAK_BLOCK:
|
||||
$this->doCloseInventory();
|
||||
}
|
||||
//TODO: end hack for client spam bug
|
||||
|
||||
$this->setUsingItem(false);
|
||||
|
||||
if(!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13)){
|
||||
}elseif($this->isCreative()){
|
||||
$item = $this->inventory->getItemInHand();
|
||||
if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->getClickPos(), $this, true)){
|
||||
return true;
|
||||
}
|
||||
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->getItemInHand()->getItemStack())){
|
||||
$this->inventory->sendHeldItem($this);
|
||||
}else{
|
||||
$item = $this->inventory->getItemInHand();
|
||||
$oldItem = clone $item;
|
||||
|
||||
if($this->canInteract($blockVector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 7) and $this->level->useBreakOn($blockVector, $item, $this, true)){
|
||||
if($this->isSurvival()){
|
||||
if(!$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){
|
||||
$this->inventory->setItemInHand($item);
|
||||
$this->inventory->sendHeldItem($this->hasSpawned);
|
||||
}
|
||||
|
||||
$this->exhaust(0.025, PlayerExhaustEvent::CAUSE_MINING);
|
||||
if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->getClickPos(), $this, true)){
|
||||
if(!$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){
|
||||
$this->inventory->setItemInHand($item);
|
||||
$this->inventory->sendHeldItem($this->hasSpawned);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->inventory->sendContents($this);
|
||||
$this->inventory->sendHeldItem($this);
|
||||
|
||||
$target = $this->level->getBlock($blockVector);
|
||||
/** @var Block[] $blocks */
|
||||
$blocks = $target->getAllSides();
|
||||
$blocks[] = $target;
|
||||
|
||||
$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);
|
||||
|
||||
foreach($blocks as $b){
|
||||
$tile = $this->level->getTile($b);
|
||||
if($tile instanceof Spawnable){
|
||||
$tile->spawnTo($this);
|
||||
}
|
||||
}
|
||||
$this->inventory->sendHeldItem($this);
|
||||
|
||||
if($blockVector->distanceSquared($this) > 10000){
|
||||
return true;
|
||||
case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_AIR:
|
||||
if($this->isUsingItem()){
|
||||
$slot = $this->inventory->getItemInHand();
|
||||
if($slot instanceof Consumable and !($slot instanceof MaybeConsumable and !$slot->canBeConsumed())){
|
||||
$ev = new PlayerItemConsumeEvent($this, $slot);
|
||||
if($this->hasItemCooldown($slot)){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
$ev->call();
|
||||
if($ev->isCancelled() or !$this->consumeObject($slot)){
|
||||
$this->inventory->sendContents($this);
|
||||
return true;
|
||||
}
|
||||
$this->resetItemCooldown($slot);
|
||||
if($this->isSurvival()){
|
||||
$slot->pop();
|
||||
$this->inventory->setItemInHand($slot);
|
||||
$this->inventory->addItem($slot->getResidue());
|
||||
}
|
||||
$this->setUsingItem(false);
|
||||
}
|
||||
|
||||
$target = $this->level->getBlock($blockVector);
|
||||
$block = $target->getSide($face);
|
||||
|
||||
/** @var Block[] $blocks */
|
||||
$blocks = array_merge($target->getAllSides(), $block->getAllSides()); //getAllSides() on each of these will include $target and $block because they are next to each other
|
||||
|
||||
$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);
|
||||
|
||||
return true;
|
||||
case UseItemTransactionData::ACTION_BREAK_BLOCK:
|
||||
$this->doCloseInventory();
|
||||
|
||||
$item = $this->inventory->getItemInHand();
|
||||
$oldItem = clone $item;
|
||||
|
||||
if($this->canInteract($blockVector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 7) and $this->level->useBreakOn($blockVector, $item, $this, true)){
|
||||
if($this->isSurvival()){
|
||||
if(!$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){
|
||||
$this->inventory->setItemInHand($item);
|
||||
$this->inventory->sendHeldItem($this->hasSpawned);
|
||||
}
|
||||
}
|
||||
$directionVector = $this->getDirectionVector();
|
||||
|
||||
if($this->isCreative()){
|
||||
$item = $this->inventory->getItemInHand();
|
||||
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->itemInHand)){
|
||||
$this->inventory->sendHeldItem($this);
|
||||
return true;
|
||||
}else{
|
||||
$item = $this->inventory->getItemInHand();
|
||||
$this->exhaust(0.025, PlayerExhaustEvent::CAUSE_MINING);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$ev = new PlayerInteractEvent($this, $item, null, $directionVector, $face, PlayerInteractEvent::RIGHT_CLICK_AIR);
|
||||
if($this->hasItemCooldown($item) or $this->isSpectator()){
|
||||
$ev->setCancelled();
|
||||
$this->inventory->sendContents($this);
|
||||
$this->inventory->sendHeldItem($this);
|
||||
|
||||
$target = $this->level->getBlock($blockVector);
|
||||
/** @var Block[] $blocks */
|
||||
$blocks = $target->getAllSides();
|
||||
$blocks[] = $target;
|
||||
|
||||
$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);
|
||||
|
||||
foreach($blocks as $b){
|
||||
$tile = $this->level->getTile($b);
|
||||
if($tile instanceof Spawnable){
|
||||
$tile->spawnTo($this);
|
||||
}
|
||||
}
|
||||
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
$this->inventory->sendHeldItem($this);
|
||||
return true;
|
||||
}
|
||||
|
||||
if($item->onClickAir($this, $directionVector)){
|
||||
$this->resetItemCooldown($item);
|
||||
return true;
|
||||
case UseItemTransactionData::ACTION_CLICK_AIR:
|
||||
if($this->isUsingItem()){
|
||||
$slot = $this->inventory->getItemInHand();
|
||||
if($slot instanceof Consumable and !($slot instanceof MaybeConsumable and !$slot->canBeConsumed())){
|
||||
$ev = new PlayerItemConsumeEvent($this, $slot);
|
||||
if($this->hasItemCooldown($slot)){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
$ev->call();
|
||||
if($ev->isCancelled() or !$this->consumeObject($slot)){
|
||||
$this->inventory->sendContents($this);
|
||||
return true;
|
||||
}
|
||||
$this->resetItemCooldown($slot);
|
||||
if($this->isSurvival()){
|
||||
$slot->pop();
|
||||
$this->inventory->setItemInHand($slot);
|
||||
$this->inventory->addItem($slot->getResidue());
|
||||
}
|
||||
$this->setUsingItem(false);
|
||||
}
|
||||
}
|
||||
$directionVector = $this->getDirectionVector();
|
||||
|
||||
if($this->isCreative()){
|
||||
$item = $this->inventory->getItemInHand();
|
||||
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->getItemInHand()->getItemStack())){
|
||||
$this->inventory->sendHeldItem($this);
|
||||
return true;
|
||||
}else{
|
||||
$item = $this->inventory->getItemInHand();
|
||||
}
|
||||
|
||||
$ev = new PlayerInteractEvent($this, $item, null, $directionVector, $face, PlayerInteractEvent::RIGHT_CLICK_AIR);
|
||||
if($this->hasItemCooldown($item) or $this->isSpectator()){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
$this->inventory->sendHeldItem($this);
|
||||
return true;
|
||||
}
|
||||
|
||||
if($item->onClickAir($this, $directionVector)){
|
||||
$this->resetItemCooldown($item);
|
||||
if($this->isSurvival()){
|
||||
$this->inventory->setItemInHand($item);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setUsingItem(true);
|
||||
|
||||
return true;
|
||||
default:
|
||||
//unknown
|
||||
break;
|
||||
}
|
||||
|
||||
$this->inventory->sendContents($this);
|
||||
return false;
|
||||
}elseif($packet->trData instanceof UseItemOnEntityTransactionData){
|
||||
$target = $this->level->getEntity($packet->trData->getEntityRuntimeId());
|
||||
if($target === null){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->inventory->getHeldItemIndex() !== $packet->trData->getHotbarSlot()){
|
||||
$this->inventory->equipItem($packet->trData->getHotbarSlot());
|
||||
}
|
||||
|
||||
switch($packet->trData->getActionType()){
|
||||
case UseItemOnEntityTransactionData::ACTION_INTERACT:
|
||||
break; //TODO
|
||||
case UseItemOnEntityTransactionData::ACTION_ATTACK:
|
||||
if(!$target->isAlive()){
|
||||
return true;
|
||||
}
|
||||
if($target instanceof ItemEntity or $target instanceof Arrow){
|
||||
$this->kick("Attempting to attack an invalid entity");
|
||||
$this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidEntity", [$this->getName()]));
|
||||
return false;
|
||||
}
|
||||
|
||||
$cancelled = false;
|
||||
|
||||
$heldItem = $this->inventory->getItemInHand();
|
||||
$oldItem = clone $heldItem;
|
||||
|
||||
if(!$this->canInteract($target, 8) or $this->isSpectator()){
|
||||
$cancelled = true;
|
||||
}elseif($target instanceof Player){
|
||||
if(!$this->server->getConfigBool("pvp")){
|
||||
$cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
$ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints());
|
||||
|
||||
$meleeEnchantmentDamage = 0;
|
||||
/** @var EnchantmentInstance[] $meleeEnchantments */
|
||||
$meleeEnchantments = [];
|
||||
foreach($heldItem->getEnchantments() as $enchantment){
|
||||
$type = $enchantment->getType();
|
||||
if($type instanceof MeleeWeaponEnchantment and $type->isApplicableTo($target)){
|
||||
$meleeEnchantmentDamage += $type->getDamageBonus($enchantment->getLevel());
|
||||
$meleeEnchantments[] = $enchantment;
|
||||
}
|
||||
}
|
||||
$ev->setModifier($meleeEnchantmentDamage, EntityDamageEvent::MODIFIER_WEAPON_ENCHANTMENTS);
|
||||
|
||||
if($cancelled){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
|
||||
if(!$this->isSprinting() and !$this->isFlying() and $this->fallDistance > 0 and !$this->hasEffect(Effect::BLINDNESS) and !$this->isUnderwater()){
|
||||
$ev->setModifier($ev->getFinalDamage() / 2, EntityDamageEvent::MODIFIER_CRITICAL);
|
||||
}
|
||||
|
||||
$target->attack($ev);
|
||||
|
||||
if($ev->isCancelled()){
|
||||
if($heldItem instanceof Durable and $this->isSurvival()){
|
||||
$this->inventory->sendContents($this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0){
|
||||
$pk = new AnimatePacket();
|
||||
$pk->action = AnimatePacket::ACTION_CRITICAL_HIT;
|
||||
$pk->entityRuntimeId = $target->getId();
|
||||
$this->server->broadcastPacket($target->getViewers(), $pk);
|
||||
if($target instanceof Player){
|
||||
$target->dataPacket($pk);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($meleeEnchantments as $enchantment){
|
||||
$type = $enchantment->getType();
|
||||
assert($type instanceof MeleeWeaponEnchantment);
|
||||
$type->onPostAttack($this, $target, $enchantment->getLevel());
|
||||
}
|
||||
|
||||
if($this->isAlive()){
|
||||
//reactive damage like thorns might cause us to be killed by attacking another mob, which
|
||||
//would mean we'd already have dropped the inventory by the time we reached here
|
||||
if($heldItem->onAttackEntity($target) and $this->isSurvival() and $oldItem->equalsExact($this->inventory->getItemInHand())){ //always fire the hook, even if we are survival
|
||||
$this->inventory->setItemInHand($heldItem);
|
||||
}
|
||||
|
||||
$this->exhaust(0.3, PlayerExhaustEvent::CAUSE_ATTACK);
|
||||
}
|
||||
|
||||
return true;
|
||||
default:
|
||||
break; //unknown
|
||||
}
|
||||
|
||||
$this->inventory->sendContents($this);
|
||||
return false;
|
||||
}elseif($packet->trData instanceof ReleaseItemTransactionData){
|
||||
if($this->inventory->getHeldItemIndex() !== $packet->trData->getHotbarSlot()){
|
||||
$this->inventory->equipItem($packet->trData->getHotbarSlot());
|
||||
}
|
||||
|
||||
try{
|
||||
switch($packet->trData->getActionType()){
|
||||
case ReleaseItemTransactionData::ACTION_RELEASE:
|
||||
if($this->isUsingItem()){
|
||||
$item = $this->inventory->getItemInHand();
|
||||
if($this->hasItemCooldown($item)){
|
||||
$this->inventory->sendContents($this);
|
||||
return false;
|
||||
}
|
||||
if($item->onReleaseUsing($this)){
|
||||
$this->resetItemCooldown($item);
|
||||
$this->inventory->setItemInHand($item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->setUsingItem(true);
|
||||
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
//unknown
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case InventoryTransactionPacket::TYPE_USE_ITEM_ON_ENTITY:
|
||||
$target = $this->level->getEntity($packet->trData->entityRuntimeId);
|
||||
if($target === null){
|
||||
return false;
|
||||
}
|
||||
|
||||
$type = $packet->trData->actionType;
|
||||
|
||||
switch($type){
|
||||
case InventoryTransactionPacket::USE_ITEM_ON_ENTITY_ACTION_INTERACT:
|
||||
break; //TODO
|
||||
case InventoryTransactionPacket::USE_ITEM_ON_ENTITY_ACTION_ATTACK:
|
||||
if(!$target->isAlive()){
|
||||
return true;
|
||||
}
|
||||
if($target instanceof ItemEntity or $target instanceof Arrow){
|
||||
$this->kick("Attempting to attack an invalid entity");
|
||||
$this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidEntity", [$this->getName()]));
|
||||
return false;
|
||||
}
|
||||
|
||||
$cancelled = false;
|
||||
|
||||
$heldItem = $this->inventory->getItemInHand();
|
||||
$oldItem = clone $heldItem;
|
||||
|
||||
if(!$this->canInteract($target, 8) or $this->isSpectator()){
|
||||
$cancelled = true;
|
||||
}elseif($target instanceof Player){
|
||||
if(!$this->server->getConfigBool("pvp")){
|
||||
$cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
$ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints());
|
||||
|
||||
$meleeEnchantmentDamage = 0;
|
||||
/** @var EnchantmentInstance[] $meleeEnchantments */
|
||||
$meleeEnchantments = [];
|
||||
foreach($heldItem->getEnchantments() as $enchantment){
|
||||
$type = $enchantment->getType();
|
||||
if($type instanceof MeleeWeaponEnchantment and $type->isApplicableTo($target)){
|
||||
$meleeEnchantmentDamage += $type->getDamageBonus($enchantment->getLevel());
|
||||
$meleeEnchantments[] = $enchantment;
|
||||
}
|
||||
}
|
||||
$ev->setModifier($meleeEnchantmentDamage, EntityDamageEvent::MODIFIER_WEAPON_ENCHANTMENTS);
|
||||
|
||||
if($cancelled){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
|
||||
if(!$this->isSprinting() and !$this->isFlying() and $this->fallDistance > 0 and !$this->hasEffect(Effect::BLINDNESS) and !$this->isUnderwater()){
|
||||
$ev->setModifier($ev->getFinalDamage() / 2, EntityDamageEvent::MODIFIER_CRITICAL);
|
||||
}
|
||||
|
||||
$target->attack($ev);
|
||||
|
||||
if($ev->isCancelled()){
|
||||
if($heldItem instanceof Durable and $this->isSurvival()){
|
||||
$this->inventory->sendContents($this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0){
|
||||
$pk = new AnimatePacket();
|
||||
$pk->action = AnimatePacket::ACTION_CRITICAL_HIT;
|
||||
$pk->entityRuntimeId = $target->getId();
|
||||
$this->server->broadcastPacket($target->getViewers(), $pk);
|
||||
if($target instanceof Player){
|
||||
$target->dataPacket($pk);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($meleeEnchantments as $enchantment){
|
||||
$type = $enchantment->getType();
|
||||
assert($type instanceof MeleeWeaponEnchantment);
|
||||
$type->onPostAttack($this, $target, $enchantment->getLevel());
|
||||
}
|
||||
|
||||
if($this->isAlive()){
|
||||
//reactive damage like thorns might cause us to be killed by attacking another mob, which
|
||||
//would mean we'd already have dropped the inventory by the time we reached here
|
||||
if($heldItem->onAttackEntity($target) and $this->isSurvival() and $oldItem->equalsExact($this->inventory->getItemInHand())){ //always fire the hook, even if we are survival
|
||||
$this->inventory->setItemInHand($heldItem);
|
||||
}
|
||||
|
||||
$this->exhaust(0.3, PlayerExhaustEvent::CAUSE_ATTACK);
|
||||
}
|
||||
|
||||
return true;
|
||||
default:
|
||||
break; //unknown
|
||||
}
|
||||
|
||||
break;
|
||||
case InventoryTransactionPacket::TYPE_RELEASE_ITEM:
|
||||
try{
|
||||
$type = $packet->trData->actionType;
|
||||
switch($type){
|
||||
case InventoryTransactionPacket::RELEASE_ITEM_ACTION_RELEASE:
|
||||
if($this->isUsingItem()){
|
||||
$item = $this->inventory->getItemInHand();
|
||||
if($this->hasItemCooldown($item)){
|
||||
$this->inventory->sendContents($this);
|
||||
return false;
|
||||
}
|
||||
if($item->onReleaseUsing($this)){
|
||||
$this->resetItemCooldown($item);
|
||||
$this->inventory->setItemInHand($item);
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}finally{
|
||||
$this->setUsingItem(false);
|
||||
}
|
||||
|
||||
$this->inventory->sendContents($this);
|
||||
break;
|
||||
default:
|
||||
$this->inventory->sendContents($this);
|
||||
break;
|
||||
}finally{
|
||||
$this->setUsingItem(false);
|
||||
}
|
||||
|
||||
$this->inventory->sendContents($this);
|
||||
return false;
|
||||
}else{
|
||||
$this->inventory->sendContents($this);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false; //TODO
|
||||
}
|
||||
|
||||
public function handleMobEquipment(MobEquipmentPacket $packet) : bool{
|
||||
@ -2817,8 +2824,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$item = $this->inventory->getItem($packet->hotbarSlot);
|
||||
|
||||
if(!$item->equals($packet->item)){
|
||||
$this->server->getLogger()->debug("Tried to equip " . $packet->item . " but have " . $item . " in target slot");
|
||||
if(!$item->equals($packet->item->getItemStack())){
|
||||
$this->server->getLogger()->debug("Tried to equip " . $packet->item->getItemStack() . " but have " . $item . " in target slot");
|
||||
$this->inventory->sendContents($this);
|
||||
return false;
|
||||
}
|
||||
@ -3698,6 +3705,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$this->stopSleep();
|
||||
|
||||
if($this->spawned){
|
||||
$this->doCloseInventory();
|
||||
|
||||
$ev = new PlayerQuitEvent($this, $message, $reason);
|
||||
$ev->call();
|
||||
if($ev->getQuitMessage() != ""){
|
||||
|
@ -36,7 +36,7 @@ namespace pocketmine {
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
const MIN_PHP_VERSION = "7.3.0";
|
||||
const MIN_PHP_VERSION = "7.4.0";
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
@ -127,6 +127,9 @@ namespace pocketmine {
|
||||
* @return void
|
||||
*/
|
||||
function emit_performance_warnings(\Logger $logger){
|
||||
if(PHP_DEBUG !== 0){
|
||||
$logger->warning("This PHP binary was compiled in debug mode. This has a major impact on performance.");
|
||||
}
|
||||
if(extension_loaded("xdebug")){
|
||||
$logger->warning("Xdebug extension is enabled. This has a major impact on performance.");
|
||||
}
|
||||
@ -139,6 +142,24 @@ namespace pocketmine {
|
||||
if(\Phar::running(true) === ""){
|
||||
$logger->warning("Non-packaged installation detected. This will degrade autoloading speed and make startup times longer.");
|
||||
}
|
||||
if(function_exists('opcache_get_status') && ($opcacheStatus = opcache_get_status(false)) !== false){
|
||||
$jitEnabled = $opcacheStatus["jit"]["on"] ?? false;
|
||||
if($jitEnabled !== false){
|
||||
$logger->warning(<<<'JIT_WARNING'
|
||||
|
||||
|
||||
--------------------------------------- ! WARNING ! ---------------------------------------
|
||||
You're using PHP 8.0 with JIT enabled. This provides significant performance improvements.
|
||||
HOWEVER, it is EXPERIMENTAL, and has already been seen to cause weird and unexpected bugs.
|
||||
Proceed with caution.
|
||||
If you want to report any bugs, make sure to mention that you are using PHP 8.0 with JIT.
|
||||
To turn off JIT, change `opcache.jit` to `0` in your php.ini file.
|
||||
-------------------------------------------------------------------------------------------
|
||||
|
||||
JIT_WARNING
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,10 +180,12 @@ namespace pocketmine {
|
||||
if(count($messages = check_platform_dependencies()) > 0){
|
||||
echo PHP_EOL;
|
||||
$binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
|
||||
critical_error("Selected PHP binary ($binary) does not satisfy some requirements.");
|
||||
critical_error("Selected PHP binary does not satisfy some requirements.");
|
||||
foreach($messages as $m){
|
||||
echo " - $m" . PHP_EOL;
|
||||
}
|
||||
critical_error("PHP binary used: " . $binary);
|
||||
critical_error("Loaded php.ini: " . (($file = php_ini_loaded_file()) !== false ? $file : "none"));
|
||||
critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
|
||||
echo PHP_EOL;
|
||||
exit(1);
|
||||
|
@ -33,6 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
|
||||
const _VERSION_INFO_INCLUDED = true;
|
||||
|
||||
const NAME = "PocketMine-MP";
|
||||
const BASE_VERSION = "3.18.2";
|
||||
const BASE_VERSION = "3.22.4";
|
||||
const IS_DEVELOPMENT_BUILD = false;
|
||||
const BUILD_NUMBER = 0;
|
||||
const BUILD_CHANNEL = "stable";
|
||||
|
@ -95,7 +95,7 @@ abstract class Worker extends \Worker{
|
||||
public function quit(){
|
||||
$this->isKilled = true;
|
||||
|
||||
if($this->isRunning()){
|
||||
if(!$this->isShutdown()){
|
||||
while($this->unstack() !== null);
|
||||
$this->notify();
|
||||
$this->shutdown();
|
||||
|
@ -68,7 +68,10 @@ class SignPost extends Transparent{
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::SIGN, $this->getLevelNonNull(), TileSign::createNBT($this, $face, $item, $player));
|
||||
$sign = Tile::createTile(Tile::SIGN, $this->getLevelNonNull(), TileSign::createNBT($this, $face, $item, $player));
|
||||
if($player !== null && $sign instanceof TileSign){
|
||||
$sign->setEditorEntityRuntimeId($player->getId());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ use function fstat;
|
||||
use function is_resource;
|
||||
use function microtime;
|
||||
use function preg_replace;
|
||||
use function readline;
|
||||
use function stream_isatty;
|
||||
use function stream_select;
|
||||
use function trim;
|
||||
|
@ -51,9 +51,9 @@ use pocketmine\network\mcpe\protocol\ActorEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
|
||||
use pocketmine\Player;
|
||||
@ -813,7 +813,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
$pk->motion = $this->getMotion();
|
||||
$pk->yaw = $this->yaw;
|
||||
$pk->pitch = $this->pitch;
|
||||
$pk->item = $this->getInventory()->getItemInHand();
|
||||
$pk->item = ItemStackWrapper::legacy($this->getInventory()->getItemInHand());
|
||||
$pk->metadata = $this->propertyManager->getAll();
|
||||
$player->dataPacket($pk);
|
||||
|
||||
@ -830,23 +830,6 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
}
|
||||
}
|
||||
|
||||
public function broadcastMovement(bool $teleport = false) : void{
|
||||
//TODO: workaround 1.14.30 bug: MoveActor(Absolute|Delta)Packet don't work on players anymore :(
|
||||
$pk = new MovePlayerPacket();
|
||||
$pk->entityRuntimeId = $this->getId();
|
||||
$pk->position = $this->getOffsetPosition($this);
|
||||
$pk->yaw = $this->yaw;
|
||||
$pk->pitch = $this->pitch;
|
||||
$pk->headYaw = $this->yaw;
|
||||
$pk->mode = $teleport ? MovePlayerPacket::MODE_TELEPORT : MovePlayerPacket::MODE_NORMAL;
|
||||
|
||||
//we can't assume that everyone who is using our chunk wants to see this movement,
|
||||
//because this human might be a player who shouldn't be receiving his own movement.
|
||||
//this didn't matter when we were able to use MoveActorPacket because
|
||||
//the client just ignored MoveActor for itself, but it doesn't ignore MovePlayer for itself.
|
||||
$this->server->broadcastPacket($this->hasSpawned, $pk);
|
||||
}
|
||||
|
||||
public function close() : void{
|
||||
if(!$this->closed){
|
||||
if($this->inventory !== null){
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\event\inventory\InventoryPickupItemEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\Player;
|
||||
use function get_class;
|
||||
|
||||
@ -173,7 +174,7 @@ class ItemEntity extends Entity{
|
||||
$pk->entityRuntimeId = $this->getId();
|
||||
$pk->position = $this->asVector3();
|
||||
$pk->motion = $this->getMotion();
|
||||
$pk->item = $this->getItem();
|
||||
$pk->item = ItemStackWrapper::legacy($this->getItem());
|
||||
$pk->metadata = $this->propertyManager->getAll();
|
||||
|
||||
$player->dataPacket($pk);
|
||||
|
@ -98,10 +98,10 @@ class ArmorInventory extends BaseInventory{
|
||||
|
||||
$pk = new MobArmorEquipmentPacket();
|
||||
$pk->entityRuntimeId = $this->getHolder()->getId();
|
||||
$pk->head = $this->getHelmet();
|
||||
$pk->chest = $this->getChestplate();
|
||||
$pk->legs = $this->getLeggings();
|
||||
$pk->feet = $this->getBoots();
|
||||
$pk->head = ItemStackWrapper::legacy($this->getHelmet());
|
||||
$pk->chest = ItemStackWrapper::legacy($this->getChestplate());
|
||||
$pk->legs = ItemStackWrapper::legacy($this->getLeggings());
|
||||
$pk->feet = ItemStackWrapper::legacy($this->getBoots());
|
||||
$pk->encode();
|
||||
|
||||
foreach($target as $player){
|
||||
@ -126,10 +126,10 @@ class ArmorInventory extends BaseInventory{
|
||||
|
||||
$pk = new MobArmorEquipmentPacket();
|
||||
$pk->entityRuntimeId = $this->getHolder()->getId();
|
||||
$pk->head = $this->getHelmet();
|
||||
$pk->chest = $this->getChestplate();
|
||||
$pk->legs = $this->getLeggings();
|
||||
$pk->feet = $this->getBoots();
|
||||
$pk->head = ItemStackWrapper::legacy($this->getHelmet());
|
||||
$pk->chest = ItemStackWrapper::legacy($this->getChestplate());
|
||||
$pk->legs = ItemStackWrapper::legacy($this->getLeggings());
|
||||
$pk->feet = ItemStackWrapper::legacy($this->getBoots());
|
||||
$pk->encode();
|
||||
|
||||
foreach($target as $player){
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\network\mcpe\protocol\CreativeContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\Player;
|
||||
use function array_map;
|
||||
use function in_array;
|
||||
@ -165,7 +166,7 @@ class PlayerInventory extends BaseInventory{
|
||||
|
||||
$pk = new MobEquipmentPacket();
|
||||
$pk->entityRuntimeId = $this->getHolder()->getId();
|
||||
$pk->item = $item;
|
||||
$pk->item = ItemStackWrapper::legacy($item);
|
||||
$pk->inventorySlot = $pk->hotbarSlot = $this->getHeldItemIndex();
|
||||
$pk->windowId = ContainerIds::INVENTORY;
|
||||
|
||||
|
@ -339,7 +339,11 @@ class Item implements ItemIds, \JsonSerializable{
|
||||
}
|
||||
}
|
||||
|
||||
$this->setNamedTagEntry($ench);
|
||||
if($ench->getCount() > 0){
|
||||
$this->setNamedTagEntry($ench);
|
||||
}else{
|
||||
$this->removeNamedTagEntry(self::TAG_ENCH);
|
||||
}
|
||||
}
|
||||
|
||||
public function removeEnchantments() : void{
|
||||
|
@ -144,16 +144,9 @@ class Normal extends Generator{
|
||||
return Biome::BIRCH_FOREST;
|
||||
}
|
||||
}else{
|
||||
//FIXME: This will always cause River to be used since the rainfall is always greater than 0.8 if we
|
||||
//reached this branch. However I don't think that substituting temperature for rainfall is correct given
|
||||
//that mountain biomes are supposed to be pretty cold.
|
||||
if($rainfall < 0.25){
|
||||
return Biome::MOUNTAINS;
|
||||
}elseif($rainfall < 0.70){
|
||||
return Biome::SMALL_MOUNTAINS;
|
||||
}else{
|
||||
return Biome::RIVER;
|
||||
}
|
||||
//Previously here, we had a (broken) condition to generate mountains, but fixing it would have
|
||||
//caused generation changes on a patch release, so we can't keep it here for now.
|
||||
return Biome::RIVER;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -31,6 +31,7 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
|
||||
use pocketmine\utils\UUID;
|
||||
@ -104,7 +105,7 @@ class FloatingTextParticle extends Particle{
|
||||
$pk->username = $name;
|
||||
$pk->entityRuntimeId = $this->entityId;
|
||||
$pk->position = $this->asVector3(); //TODO: check offset
|
||||
$pk->item = ItemFactory::get(Item::AIR, 0, 0);
|
||||
$pk->item = ItemStackWrapper::legacy(ItemFactory::get(Item::AIR, 0, 0));
|
||||
|
||||
$flags = (
|
||||
1 << Entity::DATA_FLAG_IMMOBILE
|
||||
|
@ -36,65 +36,79 @@ abstract class Particle extends Vector3{
|
||||
public const TYPE_EXPLODE = 6;
|
||||
public const TYPE_EVAPORATION = 7;
|
||||
public const TYPE_FLAME = 8;
|
||||
public const TYPE_LAVA = 9;
|
||||
public const TYPE_LARGE_SMOKE = 10;
|
||||
public const TYPE_REDSTONE = 11;
|
||||
public const TYPE_RISING_RED_DUST = 12;
|
||||
public const TYPE_ITEM_BREAK = 13;
|
||||
public const TYPE_SNOWBALL_POOF = 14;
|
||||
public const TYPE_HUGE_EXPLODE = 15;
|
||||
public const TYPE_HUGE_EXPLODE_SEED = 16;
|
||||
public const TYPE_MOB_FLAME = 17;
|
||||
public const TYPE_HEART = 18;
|
||||
public const TYPE_TERRAIN = 19;
|
||||
public const TYPE_SUSPENDED_TOWN = 20, TYPE_TOWN_AURA = 20;
|
||||
public const TYPE_PORTAL = 21;
|
||||
//22 same as 21
|
||||
public const TYPE_SPLASH = 23, TYPE_WATER_SPLASH = 23;
|
||||
public const TYPE_WATER_SPLASH_MANUAL = 24;
|
||||
public const TYPE_WATER_WAKE = 25;
|
||||
public const TYPE_DRIP_WATER = 26;
|
||||
public const TYPE_DRIP_LAVA = 27;
|
||||
public const TYPE_DRIP_HONEY = 28;
|
||||
public const TYPE_FALLING_DUST = 29, TYPE_DUST = 29;
|
||||
public const TYPE_MOB_SPELL = 30;
|
||||
public const TYPE_MOB_SPELL_AMBIENT = 31;
|
||||
public const TYPE_MOB_SPELL_INSTANTANEOUS = 32;
|
||||
public const TYPE_INK = 33;
|
||||
public const TYPE_SLIME = 34;
|
||||
public const TYPE_RAIN_SPLASH = 35;
|
||||
public const TYPE_VILLAGER_ANGRY = 36;
|
||||
public const TYPE_VILLAGER_HAPPY = 37;
|
||||
public const TYPE_ENCHANTMENT_TABLE = 38;
|
||||
public const TYPE_TRACKING_EMITTER = 39;
|
||||
public const TYPE_NOTE = 40;
|
||||
public const TYPE_WITCH_SPELL = 41;
|
||||
public const TYPE_CARROT = 42;
|
||||
public const TYPE_MOB_APPEARANCE = 43;
|
||||
public const TYPE_END_ROD = 44;
|
||||
public const TYPE_DRAGONS_BREATH = 45;
|
||||
public const TYPE_SPIT = 46;
|
||||
public const TYPE_TOTEM = 47;
|
||||
public const TYPE_FOOD = 48;
|
||||
public const TYPE_FIREWORKS_STARTER = 49;
|
||||
public const TYPE_FIREWORKS_SPARK = 50;
|
||||
public const TYPE_FIREWORKS_OVERLAY = 51;
|
||||
public const TYPE_BALLOON_GAS = 52;
|
||||
public const TYPE_COLORED_FLAME = 53;
|
||||
public const TYPE_SPARKLER = 54;
|
||||
public const TYPE_CONDUIT = 55;
|
||||
public const TYPE_BUBBLE_COLUMN_UP = 56;
|
||||
public const TYPE_BUBBLE_COLUMN_DOWN = 57;
|
||||
public const TYPE_SNEEZE = 58;
|
||||
public const TYPE_SHULKER_BULLET = 59;
|
||||
public const TYPE_BLEACH = 60;
|
||||
public const TYPE_DRAGON_DESTROY_BLOCK = 61;
|
||||
public const TYPE_MYCELIUM_DUST = 62;
|
||||
public const TYPE_FALLING_RED_DUST = 63;
|
||||
public const TYPE_CAMPFIRE_SMOKE = 64;
|
||||
public const TYPE_TALL_CAMPFIRE_SMOKE = 65;
|
||||
public const TYPE_DRAGON_BREATH_FIRE = 66;
|
||||
public const TYPE_DRAGON_BREATH_TRAIL = 67;
|
||||
public const TYPE_CANDLE_FLAME = 9;
|
||||
public const TYPE_LAVA = 10;
|
||||
public const TYPE_LARGE_SMOKE = 11;
|
||||
public const TYPE_REDSTONE = 12;
|
||||
public const TYPE_RISING_RED_DUST = 13;
|
||||
public const TYPE_ITEM_BREAK = 14;
|
||||
public const TYPE_SNOWBALL_POOF = 15;
|
||||
public const TYPE_HUGE_EXPLODE = 16;
|
||||
public const TYPE_HUGE_EXPLODE_SEED = 17;
|
||||
public const TYPE_MOB_FLAME = 18;
|
||||
public const TYPE_HEART = 19;
|
||||
public const TYPE_TERRAIN = 20;
|
||||
public const TYPE_SUSPENDED_TOWN = 21, TYPE_TOWN_AURA = 21;
|
||||
public const TYPE_PORTAL = 22;
|
||||
//23 same as 22
|
||||
public const TYPE_SPLASH = 24, TYPE_WATER_SPLASH = 24;
|
||||
public const TYPE_WATER_SPLASH_MANUAL = 25;
|
||||
public const TYPE_WATER_WAKE = 26;
|
||||
public const TYPE_DRIP_WATER = 27;
|
||||
public const TYPE_DRIP_LAVA = 28;
|
||||
public const TYPE_DRIP_HONEY = 29;
|
||||
public const TYPE_STALACTITE_DRIP_WATER = 30;
|
||||
public const TYPE_STALACTITE_DRIP_LAVA = 31;
|
||||
public const TYPE_FALLING_DUST = 32, TYPE_DUST = 32;
|
||||
public const TYPE_MOB_SPELL = 33;
|
||||
public const TYPE_MOB_SPELL_AMBIENT = 34;
|
||||
public const TYPE_MOB_SPELL_INSTANTANEOUS = 35;
|
||||
public const TYPE_INK = 36;
|
||||
public const TYPE_SLIME = 37;
|
||||
public const TYPE_RAIN_SPLASH = 38;
|
||||
public const TYPE_VILLAGER_ANGRY = 39;
|
||||
public const TYPE_VILLAGER_HAPPY = 40;
|
||||
public const TYPE_ENCHANTMENT_TABLE = 41;
|
||||
public const TYPE_TRACKING_EMITTER = 42;
|
||||
public const TYPE_NOTE = 43;
|
||||
public const TYPE_WITCH_SPELL = 44;
|
||||
public const TYPE_CARROT = 45;
|
||||
public const TYPE_MOB_APPEARANCE = 46;
|
||||
public const TYPE_END_ROD = 47;
|
||||
public const TYPE_DRAGONS_BREATH = 48;
|
||||
public const TYPE_SPIT = 49;
|
||||
public const TYPE_TOTEM = 50;
|
||||
public const TYPE_FOOD = 51;
|
||||
public const TYPE_FIREWORKS_STARTER = 52;
|
||||
public const TYPE_FIREWORKS_SPARK = 53;
|
||||
public const TYPE_FIREWORKS_OVERLAY = 54;
|
||||
public const TYPE_BALLOON_GAS = 55;
|
||||
public const TYPE_COLORED_FLAME = 56;
|
||||
public const TYPE_SPARKLER = 57;
|
||||
public const TYPE_CONDUIT = 58;
|
||||
public const TYPE_BUBBLE_COLUMN_UP = 59;
|
||||
public const TYPE_BUBBLE_COLUMN_DOWN = 60;
|
||||
public const TYPE_SNEEZE = 61;
|
||||
public const TYPE_SHULKER_BULLET = 62;
|
||||
public const TYPE_BLEACH = 63;
|
||||
public const TYPE_DRAGON_DESTROY_BLOCK = 64;
|
||||
public const TYPE_MYCELIUM_DUST = 65;
|
||||
public const TYPE_FALLING_RED_DUST = 66;
|
||||
public const TYPE_CAMPFIRE_SMOKE = 67;
|
||||
public const TYPE_TALL_CAMPFIRE_SMOKE = 68;
|
||||
public const TYPE_DRAGON_BREATH_FIRE = 69;
|
||||
public const TYPE_DRAGON_BREATH_TRAIL = 70;
|
||||
public const TYPE_BLUE_FLAME = 71;
|
||||
public const TYPE_SOUL = 72;
|
||||
public const TYPE_OBSIDIAN_TEAR = 73;
|
||||
public const TYPE_PORTAL_REVERSE = 74;
|
||||
public const TYPE_SNOWFLAKE = 75;
|
||||
public const TYPE_VIBRATION_SIGNAL = 76;
|
||||
public const TYPE_SCULK_SENSOR_REDSTONE = 77;
|
||||
public const TYPE_SPORE_BLOSSOM_SHOWER = 78;
|
||||
public const TYPE_SPORE_BLOSSOM_AMBIENT = 79;
|
||||
public const TYPE_WAX = 80;
|
||||
public const TYPE_ELECTRIC_SPARK = 81;
|
||||
|
||||
/**
|
||||
* @return DataPacket|DataPacket[]
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\block\BlockIds;
|
||||
use pocketmine\entity\Attribute;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Durable;
|
||||
@ -32,12 +33,14 @@ use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\ItemIds;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\LittleEndianNBTStream;
|
||||
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\NamedTag;
|
||||
use pocketmine\network\mcpe\convert\ItemTranslator;
|
||||
use pocketmine\network\mcpe\convert\ItemTypeDictionary;
|
||||
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
|
||||
use pocketmine\network\mcpe\protocol\types\EntityLink;
|
||||
use pocketmine\network\mcpe\protocol\types\GameRuleType;
|
||||
@ -58,6 +61,7 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
|
||||
private const DAMAGE_TAG = "Damage"; //TAG_Int
|
||||
private const DAMAGE_TAG_CONFLICT_RESOLUTION = "___Damage_ProtocolCollisionResolution___";
|
||||
private const PM_META_TAG = "___Meta___";
|
||||
|
||||
public function getString() : string{
|
||||
return $this->get($this->getUnsignedVarInt());
|
||||
@ -193,83 +197,134 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
$this->putString($image->getData());
|
||||
}
|
||||
|
||||
public function getSlot() : Item{
|
||||
public function getItemStackWithoutStackId() : Item{
|
||||
return $this->getItemStack(function() : void{
|
||||
//NOOP
|
||||
});
|
||||
}
|
||||
|
||||
public function putItemStackWithoutStackId(Item $item) : void{
|
||||
$this->putItemStack($item, function() : void{
|
||||
//NOOP
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param \Closure(NetworkBinaryStream) : void $readExtraCrapInTheMiddle
|
||||
*/
|
||||
public function getItemStack(\Closure $readExtraCrapInTheMiddle) : Item{
|
||||
$netId = $this->getVarInt();
|
||||
if($netId === 0){
|
||||
return ItemFactory::get(0, 0, 0);
|
||||
}
|
||||
|
||||
$auxValue = $this->getVarInt();
|
||||
$netData = $auxValue >> 8;
|
||||
$cnt = $auxValue & 0xff;
|
||||
$cnt = $this->getLShort();
|
||||
$netData = $this->getUnsignedVarInt();
|
||||
|
||||
[$id, $meta] = ItemTranslator::getInstance()->fromNetworkId($netId, $netData);
|
||||
|
||||
$nbtLen = $this->getLShort();
|
||||
$readExtraCrapInTheMiddle($this);
|
||||
|
||||
/** @var CompoundTag|null $nbt */
|
||||
$nbt = null;
|
||||
if($nbtLen === 0xffff){
|
||||
$nbtDataVersion = $this->getByte();
|
||||
if($nbtDataVersion !== 1){
|
||||
throw new \UnexpectedValueException("Unexpected NBT data version $nbtDataVersion");
|
||||
$this->getVarInt();
|
||||
|
||||
$extraData = new NetworkBinaryStream($this->getString());
|
||||
return (static function() use ($extraData, $netId, $id, $meta, $cnt) : Item{
|
||||
$nbtLen = $extraData->getLShort();
|
||||
|
||||
/** @var CompoundTag|null $nbt */
|
||||
$nbt = null;
|
||||
if($nbtLen === 0xffff){
|
||||
$nbtDataVersion = $extraData->getByte();
|
||||
if($nbtDataVersion !== 1){
|
||||
throw new \UnexpectedValueException("Unexpected NBT data version $nbtDataVersion");
|
||||
}
|
||||
$decodedNBT = (new LittleEndianNBTStream())->read($extraData->buffer, false, $extraData->offset, 512);
|
||||
if(!($decodedNBT instanceof CompoundTag)){
|
||||
throw new \UnexpectedValueException("Unexpected root tag type for itemstack");
|
||||
}
|
||||
$nbt = $decodedNBT;
|
||||
}elseif($nbtLen !== 0){
|
||||
throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen");
|
||||
}
|
||||
$decodedNBT = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
|
||||
if(!($decodedNBT instanceof CompoundTag)){
|
||||
throw new \UnexpectedValueException("Unexpected root tag type for itemstack");
|
||||
|
||||
//TODO
|
||||
for($i = 0, $canPlaceOn = $extraData->getLInt(); $i < $canPlaceOn; ++$i){
|
||||
$extraData->get($extraData->getLShort());
|
||||
}
|
||||
$nbt = $decodedNBT;
|
||||
}elseif($nbtLen !== 0){
|
||||
throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen");
|
||||
}
|
||||
|
||||
//TODO
|
||||
for($i = 0, $canPlaceOn = $this->getVarInt(); $i < $canPlaceOn; ++$i){
|
||||
$this->getString();
|
||||
}
|
||||
//TODO
|
||||
for($i = 0, $canDestroy = $extraData->getLInt(); $i < $canDestroy; ++$i){
|
||||
$extraData->get($extraData->getLShort());
|
||||
}
|
||||
|
||||
//TODO
|
||||
for($i = 0, $canDestroy = $this->getVarInt(); $i < $canDestroy; ++$i){
|
||||
$this->getString();
|
||||
}
|
||||
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
|
||||
$extraData->getLLong(); //"blocking tick" (ffs mojang)
|
||||
}
|
||||
|
||||
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
|
||||
$this->getVarLong(); //"blocking tick" (ffs mojang)
|
||||
}
|
||||
if($nbt !== null){
|
||||
if($nbt->hasTag(self::DAMAGE_TAG, IntTag::class)){
|
||||
$meta = $nbt->getInt(self::DAMAGE_TAG);
|
||||
$nbt->removeTag(self::DAMAGE_TAG);
|
||||
if(($conflicted = $nbt->getTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION)) !== null){
|
||||
$nbt->removeTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
|
||||
$conflicted->setName(self::DAMAGE_TAG);
|
||||
$nbt->setTag($conflicted);
|
||||
}elseif($nbt->count() === 0){
|
||||
$nbt = null;
|
||||
if(!$extraData->feof()){
|
||||
throw new \UnexpectedValueException("Unexpected trailing extradata for network item $netId");
|
||||
}
|
||||
|
||||
if($nbt !== null){
|
||||
if($nbt->hasTag(self::DAMAGE_TAG, IntTag::class)){
|
||||
$meta = $nbt->getInt(self::DAMAGE_TAG);
|
||||
$nbt->removeTag(self::DAMAGE_TAG);
|
||||
if(($conflicted = $nbt->getTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION)) !== null){
|
||||
$nbt->removeTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
|
||||
$conflicted->setName(self::DAMAGE_TAG);
|
||||
$nbt->setTag($conflicted);
|
||||
}elseif($nbt->count() === 0){
|
||||
$nbt = null;
|
||||
}
|
||||
}elseif(($metaTag = $nbt->getTag(self::PM_META_TAG)) instanceof IntTag){
|
||||
//TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the
|
||||
//client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata
|
||||
//client-side. Aside from being very annoying, this also breaks various server-side behaviours.
|
||||
$meta = $metaTag->getValue();
|
||||
$nbt->removeTag(self::PM_META_TAG);
|
||||
if($nbt->count() === 0){
|
||||
$nbt = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ItemFactory::get($id, $meta, $cnt, $nbt);
|
||||
return ItemFactory::get($id, $meta, $cnt, $nbt);
|
||||
})();
|
||||
}
|
||||
|
||||
public function putSlot(Item $item) : void{
|
||||
/**
|
||||
* @phpstan-param \Closure(NetworkBinaryStream) : void $writeExtraCrapInTheMiddle
|
||||
*/
|
||||
public function putItemStack(Item $item, \Closure $writeExtraCrapInTheMiddle) : void{
|
||||
if($item->getId() === 0){
|
||||
$this->putVarInt(0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[$netId, $netData] = ItemTranslator::getInstance()->toNetworkId($item->getId(), $item->getDamage());
|
||||
$coreData = $item->getDamage();
|
||||
[$netId, $netData] = ItemTranslator::getInstance()->toNetworkId($item->getId(), $coreData);
|
||||
|
||||
$this->putVarInt($netId);
|
||||
$auxValue = (($netData & 0x7fff) << 8) | $item->getCount();
|
||||
$this->putVarInt($auxValue);
|
||||
$this->putLShort($item->getCount());
|
||||
$this->putUnsignedVarInt($netData);
|
||||
|
||||
$writeExtraCrapInTheMiddle($this);
|
||||
|
||||
$blockRuntimeId = 0;
|
||||
$isBlockItem = $item->getId() < 256;
|
||||
if($isBlockItem){
|
||||
$block = $item->getBlock();
|
||||
if($block->getId() !== BlockIds::AIR){
|
||||
$blockRuntimeId = RuntimeBlockMapping::toStaticRuntimeId($block->getId(), $block->getDamage());
|
||||
}
|
||||
}
|
||||
$this->putVarInt($blockRuntimeId);
|
||||
|
||||
$nbt = null;
|
||||
if($item->hasCompoundTag()){
|
||||
$nbt = clone $item->getNamedTag();
|
||||
}
|
||||
if($item instanceof Durable and $item->getDamage() > 0){
|
||||
if($item instanceof Durable and $coreData > 0){
|
||||
if($nbt !== null){
|
||||
if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){
|
||||
$nbt->removeTag(self::DAMAGE_TAG);
|
||||
@ -279,23 +334,37 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
}else{
|
||||
$nbt = new CompoundTag();
|
||||
}
|
||||
$nbt->setInt(self::DAMAGE_TAG, $item->getDamage());
|
||||
$nbt->setInt(self::DAMAGE_TAG, $coreData);
|
||||
}elseif($isBlockItem && $coreData !== 0){
|
||||
//TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the
|
||||
//client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata
|
||||
//client-side. Aside from being very annoying, this also breaks various server-side behaviours.
|
||||
if($nbt === null){
|
||||
$nbt = new CompoundTag();
|
||||
}
|
||||
$nbt->setInt(self::PM_META_TAG, $coreData);
|
||||
}
|
||||
|
||||
if($nbt !== null){
|
||||
$this->putLShort(0xffff);
|
||||
$this->putByte(1); //TODO: NBT data version (?)
|
||||
$this->put((new NetworkLittleEndianNBTStream())->write($nbt));
|
||||
}else{
|
||||
$this->putLShort(0);
|
||||
}
|
||||
$this->putString(
|
||||
(static function() use ($nbt, $netId) : string{
|
||||
$extraData = new NetworkBinaryStream();
|
||||
|
||||
$this->putVarInt(0); //CanPlaceOn entry count (TODO)
|
||||
$this->putVarInt(0); //CanDestroy entry count (TODO)
|
||||
if($nbt !== null){
|
||||
$extraData->putLShort(0xffff);
|
||||
$extraData->putByte(1); //TODO: NBT data version (?)
|
||||
$extraData->put((new LittleEndianNBTStream())->write($nbt));
|
||||
}else{
|
||||
$extraData->putLShort(0);
|
||||
}
|
||||
|
||||
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
|
||||
$this->putVarLong(0); //"blocking tick" (ffs mojang)
|
||||
}
|
||||
$extraData->putLInt(0); //CanPlaceOn entry count (TODO)
|
||||
$extraData->putLInt(0); //CanDestroy entry count (TODO)
|
||||
|
||||
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
|
||||
$extraData->putLLong(0); //"blocking tick" (ffs mojang)
|
||||
}
|
||||
return $extraData->getBuffer();
|
||||
})());
|
||||
}
|
||||
|
||||
public function getRecipeIngredient() : Item{
|
||||
@ -602,14 +671,15 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
* Reads gamerules
|
||||
* TODO: implement this properly
|
||||
*
|
||||
* @return mixed[][], members are in the structure [name => [type, value]]
|
||||
* @phpstan-return array<string, array{0: int, 1: bool|int|float}>
|
||||
* @return mixed[][], members are in the structure [name => [type, value, isPlayerModifiable]]
|
||||
* @phpstan-return array<string, array{0: int, 1: bool|int|float, 2: bool}>
|
||||
*/
|
||||
public function getGameRules() : array{
|
||||
$count = $this->getUnsignedVarInt();
|
||||
$rules = [];
|
||||
for($i = 0; $i < $count; ++$i){
|
||||
$name = $this->getString();
|
||||
$isPlayerModifiable = $this->getBool();
|
||||
$type = $this->getUnsignedVarInt();
|
||||
$value = null;
|
||||
switch($type){
|
||||
@ -624,23 +694,24 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
break;
|
||||
}
|
||||
|
||||
$rules[$name] = [$type, $value];
|
||||
$rules[$name] = [$type, $value, $isPlayerModifiable];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a gamerule array, members should be in the structure [name => [type, value]]
|
||||
* Writes a gamerule array, members should be in the structure [name => [type, value, isPlayerModifiable]]
|
||||
* TODO: implement this properly
|
||||
*
|
||||
* @param mixed[][] $rules
|
||||
* @phpstan-param array<string, array{0: int, 1: bool|int|float}> $rules
|
||||
* @phpstan-param array<string, array{0: int, 1: bool|int|float, 2: bool}> $rules
|
||||
*/
|
||||
public function putGameRules(array $rules) : void{
|
||||
$this->putUnsignedVarInt(count($rules));
|
||||
foreach($rules as $name => $rule){
|
||||
$this->putString($name);
|
||||
$this->putBool($rule[2]);
|
||||
$this->putUnsignedVarInt($rule[0]);
|
||||
switch($rule[0]){
|
||||
case GameRuleType::BOOL:
|
||||
|
@ -31,6 +31,7 @@ use pocketmine\network\mcpe\protocol\AddEntityPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddPaintingPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddVolumeEntityPacket;
|
||||
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\AnimateEntityPacket;
|
||||
use pocketmine\network\mcpe\protocol\AnimatePacket;
|
||||
@ -109,6 +110,7 @@ use pocketmine\network\mcpe\protocol\MultiplayerSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
|
||||
use pocketmine\network\mcpe\protocol\NetworkSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
|
||||
use pocketmine\network\mcpe\protocol\NpcDialoguePacket;
|
||||
use pocketmine\network\mcpe\protocol\NpcRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\OnScreenTextureAnimationPacket;
|
||||
use pocketmine\network\mcpe\protocol\PacketViolationWarningPacket;
|
||||
@ -130,6 +132,7 @@ use pocketmine\network\mcpe\protocol\PurchaseReceiptPacket;
|
||||
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\RemoveEntityPacket;
|
||||
use pocketmine\network\mcpe\protocol\RemoveObjectivePacket;
|
||||
use pocketmine\network\mcpe\protocol\RemoveVolumeEntityPacket;
|
||||
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
|
||||
use pocketmine\network\mcpe\protocol\ResourcePackChunkDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\ResourcePackChunkRequestPacket;
|
||||
@ -164,6 +167,7 @@ use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
|
||||
use pocketmine\network\mcpe\protocol\ShowProfilePacket;
|
||||
use pocketmine\network\mcpe\protocol\ShowStoreOfferPacket;
|
||||
use pocketmine\network\mcpe\protocol\SimpleEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\SimulationTypePacket;
|
||||
use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket;
|
||||
use pocketmine\network\mcpe\protocol\SpawnParticleEffectPacket;
|
||||
use pocketmine\network\mcpe\protocol\StartGamePacket;
|
||||
@ -172,6 +176,7 @@ use pocketmine\network\mcpe\protocol\StructureBlockUpdatePacket;
|
||||
use pocketmine\network\mcpe\protocol\StructureTemplateDataRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\StructureTemplateDataResponsePacket;
|
||||
use pocketmine\network\mcpe\protocol\SubClientLoginPacket;
|
||||
use pocketmine\network\mcpe\protocol\SyncActorPropertyPacket;
|
||||
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\TextPacket;
|
||||
use pocketmine\network\mcpe\protocol\TickSyncPacket;
|
||||
@ -826,4 +831,24 @@ abstract class NetworkSession{
|
||||
public function handleClientboundDebugRenderer(ClientboundDebugRendererPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleSyncActorProperty(SyncActorPropertyPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleAddVolumeEntity(AddVolumeEntityPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleRemoveVolumeEntity(RemoveVolumeEntityPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleSimulationType(SimulationTypePacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleNpcDialogue(NpcDialoguePacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,10 @@ final class ItemTranslator{
|
||||
if(!is_string($oldId) || !is_string($newId)){
|
||||
throw new AssumptionFailedError("Invalid item table format");
|
||||
}
|
||||
if(!isset($legacyStringToIntMap[$oldId])){
|
||||
//new item without a fixed legacy ID - we can't handle this right now
|
||||
continue;
|
||||
}
|
||||
$simpleMappings[$newId] = $legacyStringToIntMap[$oldId];
|
||||
}
|
||||
foreach($legacyStringToIntMap as $stringId => $intId){
|
||||
@ -128,8 +132,9 @@ final class ItemTranslator{
|
||||
}elseif(isset($simpleMappings[$stringId])){
|
||||
$this->simpleCoreToNetMapping[$simpleMappings[$stringId]] = $netId;
|
||||
$this->simpleNetToCoreMapping[$netId] = $simpleMappings[$stringId];
|
||||
}elseif($stringId !== "minecraft:unknown"){
|
||||
throw new \InvalidArgumentException("Unmapped entry " . $stringId);
|
||||
}else{
|
||||
//not all items have a legacy mapping - for now, we only support the ones that do
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,24 +31,24 @@ class AddEntityPacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::ADD_ENTITY_PACKET;
|
||||
|
||||
/** @var int */
|
||||
private $uvarint1;
|
||||
private $entityNetId;
|
||||
|
||||
public static function create(int $uvarint1) : self{
|
||||
public static function create(int $entityNetId) : self{
|
||||
$result = new self;
|
||||
$result->uvarint1 = $uvarint1;
|
||||
$result->entityNetId = $entityNetId;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUvarint1() : int{
|
||||
return $this->uvarint1;
|
||||
public function getEntityNetId() : int{
|
||||
return $this->entityNetId;
|
||||
}
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->uvarint1 = $this->getUnsignedVarInt();
|
||||
$this->entityNetId = $this->getUnsignedVarInt();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putUnsignedVarInt($this->uvarint1);
|
||||
$this->putUnsignedVarInt($this->entityNetId);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
|
@ -25,9 +25,9 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
|
||||
class AddItemActorPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::ADD_ITEM_ACTOR_PACKET;
|
||||
@ -36,7 +36,7 @@ class AddItemActorPacket extends DataPacket{
|
||||
public $entityUniqueId = null; //TODO
|
||||
/** @var int */
|
||||
public $entityRuntimeId;
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $item;
|
||||
/** @var Vector3 */
|
||||
public $position;
|
||||
@ -53,7 +53,7 @@ class AddItemActorPacket extends DataPacket{
|
||||
protected function decodePayload(){
|
||||
$this->entityUniqueId = $this->getEntityUniqueId();
|
||||
$this->entityRuntimeId = $this->getEntityRuntimeId();
|
||||
$this->item = $this->getSlot();
|
||||
$this->item = ItemStackWrapper::read($this);
|
||||
$this->position = $this->getVector3();
|
||||
$this->motion = $this->getVector3();
|
||||
$this->metadata = $this->getEntityMetadata();
|
||||
@ -63,7 +63,7 @@ class AddItemActorPacket extends DataPacket{
|
||||
protected function encodePayload(){
|
||||
$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
|
||||
$this->putEntityRuntimeId($this->entityRuntimeId);
|
||||
$this->putSlot($this->item);
|
||||
$this->item->write($this);
|
||||
$this->putVector3($this->position);
|
||||
$this->putVector3Nullable($this->motion);
|
||||
$this->putEntityMetadata($this->metadata);
|
||||
|
@ -25,11 +25,11 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\DeviceOS;
|
||||
use pocketmine\network\mcpe\protocol\types\EntityLink;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\utils\UUID;
|
||||
use function count;
|
||||
|
||||
@ -56,7 +56,7 @@ class AddPlayerPacket extends DataPacket{
|
||||
public $yaw = 0.0;
|
||||
/** @var float|null */
|
||||
public $headYaw = null; //TODO
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $item;
|
||||
/**
|
||||
* @var mixed[][]
|
||||
@ -98,7 +98,7 @@ class AddPlayerPacket extends DataPacket{
|
||||
$this->pitch = $this->getLFloat();
|
||||
$this->yaw = $this->getLFloat();
|
||||
$this->headYaw = $this->getLFloat();
|
||||
$this->item = $this->getSlot();
|
||||
$this->item = ItemStackWrapper::read($this);
|
||||
$this->metadata = $this->getEntityMetadata();
|
||||
|
||||
$this->uvarint1 = $this->getUnsignedVarInt();
|
||||
@ -129,7 +129,7 @@ class AddPlayerPacket extends DataPacket{
|
||||
$this->putLFloat($this->pitch);
|
||||
$this->putLFloat($this->yaw);
|
||||
$this->putLFloat($this->headYaw ?? $this->yaw);
|
||||
$this->putSlot($this->item);
|
||||
$this->item->write($this);
|
||||
$this->putEntityMetadata($this->metadata);
|
||||
|
||||
$this->putUnsignedVarInt($this->uvarint1);
|
||||
|
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class AddVolumeEntityPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::ADD_VOLUME_ENTITY_PACKET;
|
||||
|
||||
/** @var int */
|
||||
private $entityNetId;
|
||||
/** @var CompoundTag */
|
||||
private $data;
|
||||
|
||||
public static function create(int $entityNetId, CompoundTag $data) : self{
|
||||
$result = new self;
|
||||
$result->entityNetId = $entityNetId;
|
||||
$result->data = $data;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getEntityNetId() : int{ return $this->entityNetId; }
|
||||
|
||||
public function getData() : CompoundTag{ return $this->data; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->entityNetId = $this->getUnsignedVarInt();
|
||||
$this->data = $this->getNbtCompoundRoot();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putUnsignedVarInt($this->entityNetId);
|
||||
$this->put((new NetworkLittleEndianNBTStream())->write($this->data));
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleAddVolumeEntity($this);
|
||||
}
|
||||
}
|
@ -281,7 +281,7 @@ class AvailableCommandsPacket extends DataPacket{
|
||||
$retval = new CommandData();
|
||||
$retval->commandName = $this->getString();
|
||||
$retval->commandDescription = $this->getString();
|
||||
$retval->flags = $this->getByte();
|
||||
$retval->flags = $this->getLShort();
|
||||
$retval->permission = $this->getByte();
|
||||
$retval->aliases = $enums[$this->getLInt()] ?? null;
|
||||
|
||||
@ -324,7 +324,7 @@ class AvailableCommandsPacket extends DataPacket{
|
||||
protected function putCommandData(CommandData $data, array $enumIndexes, array $postfixIndexes) : void{
|
||||
$this->putString($data->commandName);
|
||||
$this->putString($data->commandDescription);
|
||||
$this->putByte($data->flags);
|
||||
$this->putLShort($data->flags);
|
||||
$this->putByte($data->permission);
|
||||
|
||||
if($data->aliases !== null){
|
||||
|
@ -91,7 +91,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
$resultCount = $this->getUnsignedVarInt();
|
||||
$entry["output"] = [];
|
||||
for($k = 0; $k < $resultCount; ++$k){
|
||||
$entry["output"][] = $this->getSlot();
|
||||
$entry["output"][] = $this->getItemStackWithoutStackId();
|
||||
}
|
||||
$entry["uuid"] = $this->getUUID()->toString();
|
||||
$entry["block"] = $this->getString();
|
||||
@ -113,7 +113,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
$resultCount = $this->getUnsignedVarInt();
|
||||
$entry["output"] = [];
|
||||
for($k = 0; $k < $resultCount; ++$k){
|
||||
$entry["output"][] = $this->getSlot();
|
||||
$entry["output"][] = $this->getItemStackWithoutStackId();
|
||||
}
|
||||
$entry["uuid"] = $this->getUUID()->toString();
|
||||
$entry["block"] = $this->getString();
|
||||
@ -131,7 +131,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
[$inputId, $inputData] = ItemTranslator::getInstance()->fromNetworkIdWithWildcardHandling($inputIdNet, $inputMetaNet);
|
||||
}
|
||||
$entry["input"] = ItemFactory::get($inputId, $inputData);
|
||||
$entry["output"] = $out = $this->getSlot();
|
||||
$entry["output"] = $out = $this->getItemStackWithoutStackId();
|
||||
if($out->getDamage() === 0x7fff){
|
||||
$out->setDamage(0); //TODO HACK: some 1.12 furnace recipe outputs have wildcard damage values
|
||||
}
|
||||
@ -198,7 +198,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
$results = $recipe->getResults();
|
||||
$stream->putUnsignedVarInt(count($results));
|
||||
foreach($results as $item){
|
||||
$stream->putSlot($item);
|
||||
$stream->putItemStackWithoutStackId($item);
|
||||
}
|
||||
|
||||
$stream->put(str_repeat("\x00", 16)); //Null UUID
|
||||
@ -223,7 +223,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
$results = $recipe->getResults();
|
||||
$stream->putUnsignedVarInt(count($results));
|
||||
foreach($results as $item){
|
||||
$stream->putSlot($item);
|
||||
$stream->putItemStackWithoutStackId($item);
|
||||
}
|
||||
|
||||
$stream->put(str_repeat("\x00", 16)); //Null UUID
|
||||
@ -244,7 +244,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
}
|
||||
$stream->putVarInt($netId);
|
||||
$stream->putVarInt($netData);
|
||||
$stream->putSlot($recipe->getResult());
|
||||
$stream->putItemStackWithoutStackId($recipe->getResult());
|
||||
$stream->putString("furnace"); //TODO: blocktype (no prefix) (this might require internal API breaks)
|
||||
return CraftingDataPacket::ENTRY_FURNACE_DATA;
|
||||
}
|
||||
@ -276,7 +276,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
$writer = new NetworkBinaryStream();
|
||||
$counter = 0;
|
||||
foreach($this->entries as $d){
|
||||
$entryType = self::writeEntry($d, $writer, $counter++);
|
||||
$entryType = self::writeEntry($d, $writer, ++$counter);
|
||||
if($entryType >= 0){
|
||||
$this->putVarInt($entryType);
|
||||
$this->put($writer->getBuffer());
|
||||
|
@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\utils\UUID;
|
||||
use function count;
|
||||
|
||||
@ -39,9 +39,9 @@ class CraftingEventPacket extends DataPacket{
|
||||
public $type;
|
||||
/** @var UUID */
|
||||
public $id;
|
||||
/** @var Item[] */
|
||||
/** @var ItemStackWrapper[] */
|
||||
public $input = [];
|
||||
/** @var Item[] */
|
||||
/** @var ItemStackWrapper[] */
|
||||
public $output = [];
|
||||
|
||||
public function clean(){
|
||||
@ -57,12 +57,12 @@ class CraftingEventPacket extends DataPacket{
|
||||
|
||||
$size = $this->getUnsignedVarInt();
|
||||
for($i = 0; $i < $size and $i < 128; ++$i){
|
||||
$this->input[] = $this->getSlot();
|
||||
$this->input[] = ItemStackWrapper::read($this);
|
||||
}
|
||||
|
||||
$size = $this->getUnsignedVarInt();
|
||||
for($i = 0; $i < $size and $i < 128; ++$i){
|
||||
$this->output[] = $this->getSlot();
|
||||
$this->output[] = ItemStackWrapper::read($this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,12 +73,12 @@ class CraftingEventPacket extends DataPacket{
|
||||
|
||||
$this->putUnsignedVarInt(count($this->input));
|
||||
foreach($this->input as $item){
|
||||
$this->putSlot($item);
|
||||
$item->write($this);
|
||||
}
|
||||
|
||||
$this->putUnsignedVarInt(count($this->output));
|
||||
foreach($this->output as $item){
|
||||
$this->putSlot($item);
|
||||
$item->write($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ class GameRulesChangedPacket extends DataPacket{
|
||||
|
||||
/**
|
||||
* @var mixed[][]
|
||||
* @phpstan-var array<string, array{0: int, 1: bool|int|float}>
|
||||
* @phpstan-var array<string, array{0: int, 1: bool|int|float, 2: bool}>
|
||||
*/
|
||||
public $gameRules = [];
|
||||
|
||||
|
@ -25,9 +25,15 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\NetworkSession as PacketHandlerInterface;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\InventoryTransactionChangedSlotsHack;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\NormalTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ReleaseItemTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\TransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData;
|
||||
use UnexpectedValueException as PacketDecodeException;
|
||||
use function count;
|
||||
|
||||
class InventoryTransactionPacket extends DataPacket{
|
||||
@ -39,137 +45,64 @@ class InventoryTransactionPacket extends DataPacket{
|
||||
public const TYPE_USE_ITEM_ON_ENTITY = 3;
|
||||
public const TYPE_RELEASE_ITEM = 4;
|
||||
|
||||
public const USE_ITEM_ACTION_CLICK_BLOCK = 0;
|
||||
public const USE_ITEM_ACTION_CLICK_AIR = 1;
|
||||
public const USE_ITEM_ACTION_BREAK_BLOCK = 2;
|
||||
|
||||
public const RELEASE_ITEM_ACTION_RELEASE = 0; //bow shoot
|
||||
public const RELEASE_ITEM_ACTION_CONSUME = 1; //eat food, drink potion
|
||||
|
||||
public const USE_ITEM_ON_ENTITY_ACTION_INTERACT = 0;
|
||||
public const USE_ITEM_ON_ENTITY_ACTION_ATTACK = 1;
|
||||
|
||||
/** @var int */
|
||||
public $requestId;
|
||||
/** @var InventoryTransactionChangedSlotsHack[] */
|
||||
public $requestChangedSlots;
|
||||
|
||||
/** @var int */
|
||||
public $transactionType;
|
||||
/** @var bool */
|
||||
public $hasItemStackIds;
|
||||
|
||||
/** @var NetworkInventoryAction[] */
|
||||
public $actions = [];
|
||||
|
||||
/** @var \stdClass */
|
||||
/** @var TransactionData */
|
||||
public $trData;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->requestId = $this->readGenericTypeNetworkId();
|
||||
protected function decodePayload() : void{
|
||||
$in = $this;
|
||||
$this->requestId = $in->readGenericTypeNetworkId();
|
||||
$this->requestChangedSlots = [];
|
||||
if($this->requestId !== 0){
|
||||
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$this->requestChangedSlots[] = InventoryTransactionChangedSlotsHack::read($this);
|
||||
for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$this->requestChangedSlots[] = InventoryTransactionChangedSlotsHack::read($in);
|
||||
}
|
||||
}
|
||||
|
||||
$this->transactionType = $this->getUnsignedVarInt();
|
||||
$transactionType = $in->getUnsignedVarInt();
|
||||
|
||||
$this->hasItemStackIds = $this->getBool();
|
||||
|
||||
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
|
||||
$this->actions[] = $action = (new NetworkInventoryAction())->read($this, $this->hasItemStackIds);
|
||||
}
|
||||
|
||||
$this->trData = new \stdClass();
|
||||
|
||||
switch($this->transactionType){
|
||||
switch($transactionType){
|
||||
case self::TYPE_NORMAL:
|
||||
$this->trData = new NormalTransactionData();
|
||||
break;
|
||||
case self::TYPE_MISMATCH:
|
||||
//Regular ComplexInventoryTransaction doesn't read any extra data
|
||||
$this->trData = new MismatchTransactionData();
|
||||
break;
|
||||
case self::TYPE_USE_ITEM:
|
||||
$this->trData->actionType = $this->getUnsignedVarInt();
|
||||
$this->getBlockPosition($this->trData->x, $this->trData->y, $this->trData->z);
|
||||
$this->trData->face = $this->getVarInt();
|
||||
$this->trData->hotbarSlot = $this->getVarInt();
|
||||
$this->trData->itemInHand = $this->getSlot();
|
||||
$this->trData->playerPos = $this->getVector3();
|
||||
$this->trData->clickPos = $this->getVector3();
|
||||
$this->trData->blockRuntimeId = $this->getUnsignedVarInt();
|
||||
$this->trData = new UseItemTransactionData();
|
||||
break;
|
||||
case self::TYPE_USE_ITEM_ON_ENTITY:
|
||||
$this->trData->entityRuntimeId = $this->getEntityRuntimeId();
|
||||
$this->trData->actionType = $this->getUnsignedVarInt();
|
||||
$this->trData->hotbarSlot = $this->getVarInt();
|
||||
$this->trData->itemInHand = $this->getSlot();
|
||||
$this->trData->playerPos = $this->getVector3();
|
||||
$this->trData->clickPos = $this->getVector3();
|
||||
$this->trData = new UseItemOnEntityTransactionData();
|
||||
break;
|
||||
case self::TYPE_RELEASE_ITEM:
|
||||
$this->trData->actionType = $this->getUnsignedVarInt();
|
||||
$this->trData->hotbarSlot = $this->getVarInt();
|
||||
$this->trData->itemInHand = $this->getSlot();
|
||||
$this->trData->headPos = $this->getVector3();
|
||||
$this->trData = new ReleaseItemTransactionData();
|
||||
break;
|
||||
default:
|
||||
throw new \UnexpectedValueException("Unknown transaction type $this->transactionType");
|
||||
throw new PacketDecodeException("Unknown transaction type $transactionType");
|
||||
}
|
||||
|
||||
$this->trData->decode($in);
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->writeGenericTypeNetworkId($this->requestId);
|
||||
protected function encodePayload() : void{
|
||||
$out = $this;
|
||||
$out->writeGenericTypeNetworkId($this->requestId);
|
||||
if($this->requestId !== 0){
|
||||
$this->putUnsignedVarInt(count($this->requestChangedSlots));
|
||||
$out->putUnsignedVarInt(count($this->requestChangedSlots));
|
||||
foreach($this->requestChangedSlots as $changedSlots){
|
||||
$changedSlots->write($this);
|
||||
$changedSlots->write($out);
|
||||
}
|
||||
}
|
||||
|
||||
$this->putUnsignedVarInt($this->transactionType);
|
||||
$out->putUnsignedVarInt($this->trData->getTypeId());
|
||||
|
||||
$this->putBool($this->hasItemStackIds);
|
||||
|
||||
$this->putUnsignedVarInt(count($this->actions));
|
||||
foreach($this->actions as $action){
|
||||
$action->write($this, $this->hasItemStackIds);
|
||||
}
|
||||
|
||||
switch($this->transactionType){
|
||||
case self::TYPE_NORMAL:
|
||||
case self::TYPE_MISMATCH:
|
||||
break;
|
||||
case self::TYPE_USE_ITEM:
|
||||
$this->putUnsignedVarInt($this->trData->actionType);
|
||||
$this->putBlockPosition($this->trData->x, $this->trData->y, $this->trData->z);
|
||||
$this->putVarInt($this->trData->face);
|
||||
$this->putVarInt($this->trData->hotbarSlot);
|
||||
$this->putSlot($this->trData->itemInHand);
|
||||
$this->putVector3($this->trData->playerPos);
|
||||
$this->putVector3($this->trData->clickPos);
|
||||
$this->putUnsignedVarInt($this->trData->blockRuntimeId);
|
||||
break;
|
||||
case self::TYPE_USE_ITEM_ON_ENTITY:
|
||||
$this->putEntityRuntimeId($this->trData->entityRuntimeId);
|
||||
$this->putUnsignedVarInt($this->trData->actionType);
|
||||
$this->putVarInt($this->trData->hotbarSlot);
|
||||
$this->putSlot($this->trData->itemInHand);
|
||||
$this->putVector3($this->trData->playerPos);
|
||||
$this->putVector3($this->trData->clickPos);
|
||||
break;
|
||||
case self::TYPE_RELEASE_ITEM:
|
||||
$this->putUnsignedVarInt($this->trData->actionType);
|
||||
$this->putVarInt($this->trData->hotbarSlot);
|
||||
$this->putSlot($this->trData->itemInHand);
|
||||
$this->putVector3($this->trData->headPos);
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException("Unknown transaction type $this->transactionType");
|
||||
}
|
||||
$this->trData->encode($out);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
return $session->handleInventoryTransaction($this);
|
||||
public function handle(PacketHandlerInterface $handler) : bool{
|
||||
return $handler->handleInventoryTransaction($this);
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
|
||||
class MobArmorEquipmentPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET;
|
||||
@ -36,29 +36,29 @@ class MobArmorEquipmentPacket extends DataPacket{
|
||||
|
||||
//this intentionally doesn't use an array because we don't want any implicit dependencies on internal order
|
||||
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $head;
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $chest;
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $legs;
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $feet;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->entityRuntimeId = $this->getEntityRuntimeId();
|
||||
$this->head = $this->getSlot();
|
||||
$this->chest = $this->getSlot();
|
||||
$this->legs = $this->getSlot();
|
||||
$this->feet = $this->getSlot();
|
||||
$this->head = ItemStackWrapper::read($this);
|
||||
$this->chest = ItemStackWrapper::read($this);
|
||||
$this->legs = ItemStackWrapper::read($this);
|
||||
$this->feet = ItemStackWrapper::read($this);
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->putEntityRuntimeId($this->entityRuntimeId);
|
||||
$this->putSlot($this->head);
|
||||
$this->putSlot($this->chest);
|
||||
$this->putSlot($this->legs);
|
||||
$this->putSlot($this->feet);
|
||||
$this->head->write($this);
|
||||
$this->chest->write($this);
|
||||
$this->legs->write($this);
|
||||
$this->feet->write($this);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
|
@ -25,15 +25,15 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
|
||||
class MobEquipmentPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::MOB_EQUIPMENT_PACKET;
|
||||
|
||||
/** @var int */
|
||||
public $entityRuntimeId;
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $item;
|
||||
/** @var int */
|
||||
public $inventorySlot;
|
||||
@ -44,7 +44,7 @@ class MobEquipmentPacket extends DataPacket{
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->entityRuntimeId = $this->getEntityRuntimeId();
|
||||
$this->item = $this->getSlot();
|
||||
$this->item = ItemStackWrapper::read($this);
|
||||
$this->inventorySlot = $this->getByte();
|
||||
$this->hotbarSlot = $this->getByte();
|
||||
$this->windowId = $this->getByte();
|
||||
@ -52,7 +52,7 @@ class MobEquipmentPacket extends DataPacket{
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->putEntityRuntimeId($this->entityRuntimeId);
|
||||
$this->putSlot($this->item);
|
||||
$this->item->write($this);
|
||||
$this->putByte($this->inventorySlot);
|
||||
$this->putByte($this->hotbarSlot);
|
||||
$this->putByte($this->windowId);
|
||||
|
87
src/pocketmine/network/mcpe/protocol/NpcDialoguePacket.php
Normal file
87
src/pocketmine/network/mcpe/protocol/NpcDialoguePacket.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class NpcDialoguePacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::NPC_DIALOGUE_PACKET;
|
||||
|
||||
public const ACTION_OPEN = 0;
|
||||
public const ACTION_CLOSE = 1;
|
||||
|
||||
private int $npcActorUniqueId;
|
||||
private int $actionType;
|
||||
private string $dialogue;
|
||||
private string $sceneName;
|
||||
private string $npcName;
|
||||
private string $actionJson;
|
||||
|
||||
public static function create(int $npcActorUniqueId, int $actionType, string $dialogue, string $sceneName, string $npcName, string $actionJson) : self{
|
||||
$result = new self;
|
||||
$result->npcActorUniqueId = $npcActorUniqueId;
|
||||
$result->actionType = $actionType;
|
||||
$result->dialogue = $dialogue;
|
||||
$result->sceneName = $sceneName;
|
||||
$result->npcName = $npcName;
|
||||
$result->actionJson = $actionJson;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getNpcActorUniqueId() : int{ return $this->npcActorUniqueId; }
|
||||
|
||||
public function getActionType() : int{ return $this->actionType; }
|
||||
|
||||
public function getDialogue() : string{ return $this->dialogue; }
|
||||
|
||||
public function getSceneName() : string{ return $this->sceneName; }
|
||||
|
||||
public function getNpcName() : string{ return $this->npcName; }
|
||||
|
||||
public function getActionJson() : string{ return $this->actionJson; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->npcActorUniqueId = $this->getLLong(); //WHY NOT USING STANDARD METHODS, MOJANG
|
||||
$this->actionType = $this->getVarInt();
|
||||
$this->dialogue = $this->getString();
|
||||
$this->sceneName = $this->getString();
|
||||
$this->npcName = $this->getString();
|
||||
$this->actionJson = $this->getString();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putLLong($this->npcActorUniqueId);
|
||||
$this->putVarInt($this->actionType);
|
||||
$this->putString($this->dialogue);
|
||||
$this->putString($this->sceneName);
|
||||
$this->putString($this->npcName);
|
||||
$this->putString($this->actionJson);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleNpcDialogue($this);
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@ class NpcRequestPacket extends DataPacket{
|
||||
public const REQUEST_SET_NAME = 3;
|
||||
public const REQUEST_SET_SKIN = 4;
|
||||
public const REQUEST_SET_INTERACTION_TEXT = 5;
|
||||
public const REQUEST_EXECUTE_OPENING_COMMANDS = 6;
|
||||
|
||||
/** @var int */
|
||||
public $entityRuntimeId;
|
||||
@ -45,12 +46,14 @@ class NpcRequestPacket extends DataPacket{
|
||||
public $commandString;
|
||||
/** @var int */
|
||||
public $actionType;
|
||||
public string $sceneName;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->entityRuntimeId = $this->getEntityRuntimeId();
|
||||
$this->requestType = $this->getByte();
|
||||
$this->commandString = $this->getString();
|
||||
$this->actionType = $this->getByte();
|
||||
$this->sceneName = $this->getString();
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
@ -58,6 +61,7 @@ class NpcRequestPacket extends DataPacket{
|
||||
$this->putByte($this->requestType);
|
||||
$this->putString($this->commandString);
|
||||
$this->putByte($this->actionType);
|
||||
$this->putString($this->sceneName);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
|
@ -195,6 +195,11 @@ class PacketPool{
|
||||
static::registerPacket(new ItemComponentPacket());
|
||||
static::registerPacket(new FilterTextPacket());
|
||||
static::registerPacket(new ClientboundDebugRendererPacket());
|
||||
static::registerPacket(new SyncActorPropertyPacket());
|
||||
static::registerPacket(new AddVolumeEntityPacket());
|
||||
static::registerPacket(new RemoveVolumeEntityPacket());
|
||||
static::registerPacket(new SimulationTypePacket());
|
||||
static::registerPacket(new NpcDialoguePacket());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,11 +37,11 @@ interface ProtocolInfo{
|
||||
*/
|
||||
|
||||
/** Actual Minecraft: PE protocol version */
|
||||
public const CURRENT_PROTOCOL = 428;
|
||||
public const CURRENT_PROTOCOL = 448;
|
||||
/** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */
|
||||
public const MINECRAFT_VERSION = 'v1.16.210';
|
||||
public const MINECRAFT_VERSION = 'v1.17.10';
|
||||
/** Version number sent to clients in ping responses. */
|
||||
public const MINECRAFT_VERSION_NETWORK = '1.16.210';
|
||||
public const MINECRAFT_VERSION_NETWORK = '1.17.10';
|
||||
|
||||
public const LOGIN_PACKET = 0x01;
|
||||
public const PLAY_STATUS_PACKET = 0x02;
|
||||
@ -207,5 +207,10 @@ interface ProtocolInfo{
|
||||
public const ITEM_COMPONENT_PACKET = 0xa2;
|
||||
public const FILTER_TEXT_PACKET = 0xa3;
|
||||
public const CLIENTBOUND_DEBUG_RENDERER_PACKET = 0xa4;
|
||||
public const SYNC_ACTOR_PROPERTY_PACKET = 0xa5;
|
||||
public const ADD_VOLUME_ENTITY_PACKET = 0xa6;
|
||||
public const REMOVE_VOLUME_ENTITY_PACKET = 0xa7;
|
||||
public const SIMULATION_TYPE_PACKET = 0xa8;
|
||||
public const NPC_DIALOGUE_PACKET = 0xa9;
|
||||
|
||||
}
|
||||
|
@ -31,24 +31,24 @@ class RemoveEntityPacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::REMOVE_ENTITY_PACKET;
|
||||
|
||||
/** @var int */
|
||||
private $uvarint1;
|
||||
private $entityNetId;
|
||||
|
||||
public static function create(int $uvarint1) : self{
|
||||
public static function create(int $entityNetId) : self{
|
||||
$result = new self;
|
||||
$result->uvarint1 = $uvarint1;
|
||||
$result->entityNetId = $entityNetId;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUvarint1() : int{
|
||||
return $this->uvarint1;
|
||||
public function getEntityNetId() : int{
|
||||
return $this->entityNetId;
|
||||
}
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->uvarint1 = $this->getUnsignedVarInt();
|
||||
$this->entityNetId = $this->getUnsignedVarInt();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putUnsignedVarInt($this->uvarint1);
|
||||
$this->putUnsignedVarInt($this->entityNetId);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class RemoveVolumeEntityPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::REMOVE_VOLUME_ENTITY_PACKET;
|
||||
|
||||
/** @var int */
|
||||
private $entityNetId;
|
||||
|
||||
public static function create(int $entityNetId) : self{
|
||||
$result = new self;
|
||||
$result->entityNetId = $entityNetId;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getEntityNetId() : int{ return $this->entityNetId; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->entityNetId = $this->getUnsignedVarInt();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putUnsignedVarInt($this->entityNetId);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleRemoveVolumeEntity($this);
|
||||
}
|
||||
}
|
@ -33,9 +33,11 @@ class ResourcePacksInfoPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::RESOURCE_PACKS_INFO_PACKET;
|
||||
|
||||
/** @var bool */
|
||||
public $mustAccept = false; //if true, forces client to use selected resource packs
|
||||
public $mustAccept = false; //if true, forces client to choose between accepting packs or being disconnected
|
||||
/** @var bool */
|
||||
public $hasScripts = false; //if true, causes disconnect for any platform that doesn't support scripts yet
|
||||
|
||||
public bool $forceServerPacks = false;
|
||||
/** @var ResourcePack[] */
|
||||
public $behaviorPackEntries = [];
|
||||
/** @var ResourcePack[] */
|
||||
@ -44,6 +46,7 @@ class ResourcePacksInfoPacket extends DataPacket{
|
||||
protected function decodePayload(){
|
||||
$this->mustAccept = $this->getBool();
|
||||
$this->hasScripts = $this->getBool();
|
||||
$this->forceServerPacks = $this->getBool();
|
||||
$behaviorPackCount = $this->getLShort();
|
||||
while($behaviorPackCount-- > 0){
|
||||
$this->getString();
|
||||
@ -71,6 +74,7 @@ class ResourcePacksInfoPacket extends DataPacket{
|
||||
protected function encodePayload(){
|
||||
$this->putBool($this->mustAccept);
|
||||
$this->putBool($this->hasScripts);
|
||||
$this->putBool($this->forceServerPacks);
|
||||
$this->putLShort(count($this->behaviorPackEntries));
|
||||
foreach($this->behaviorPackEntries as $entry){
|
||||
$this->putString($entry->getPackId());
|
||||
|
@ -30,6 +30,13 @@ use pocketmine\network\mcpe\NetworkSession;
|
||||
class SetDisplayObjectivePacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::SET_DISPLAY_OBJECTIVE_PACKET;
|
||||
|
||||
public const DISPLAY_SLOT_LIST = "list";
|
||||
public const DISPLAY_SLOT_SIDEBAR = "sidebar";
|
||||
public const DISPLAY_SLOT_BELOW_NAME = "belowname";
|
||||
|
||||
public const SORT_ORDER_ASCENDING = 0;
|
||||
public const SORT_ORDER_DESCENDING = 1;
|
||||
|
||||
/** @var string */
|
||||
public $displaySlot;
|
||||
/** @var string */
|
||||
|
@ -50,6 +50,8 @@ class SetTitlePacket extends DataPacket{
|
||||
public $stayTime = 0;
|
||||
/** @var int */
|
||||
public $fadeOutTime = 0;
|
||||
public string $xuid = "";
|
||||
public string $platformOnlineId = "";
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->type = $this->getVarInt();
|
||||
@ -57,6 +59,8 @@ class SetTitlePacket extends DataPacket{
|
||||
$this->fadeInTime = $this->getVarInt();
|
||||
$this->stayTime = $this->getVarInt();
|
||||
$this->fadeOutTime = $this->getVarInt();
|
||||
$this->xuid = $this->getString();
|
||||
$this->platformOnlineId = $this->getString();
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
@ -65,6 +69,8 @@ class SetTitlePacket extends DataPacket{
|
||||
$this->putVarInt($this->fadeInTime);
|
||||
$this->putVarInt($this->stayTime);
|
||||
$this->putVarInt($this->fadeOutTime);
|
||||
$this->putString($this->xuid);
|
||||
$this->putString($this->platformOnlineId);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
|
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class SimulationTypePacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::SIMULATION_TYPE_PACKET;
|
||||
|
||||
public const GAME = 0;
|
||||
public const EDITOR = 1;
|
||||
public const TEST = 2;
|
||||
|
||||
private int $type;
|
||||
|
||||
public static function create(int $type) : self{
|
||||
$result = new self;
|
||||
$result->type = $type;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getType() : int{ return $this->type; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->type = $this->getByte();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putByte($this->type);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleSimulationType($this);
|
||||
}
|
||||
}
|
@ -104,10 +104,10 @@ class StartGamePacket extends DataPacket{
|
||||
public $isTexturePacksRequired = true;
|
||||
/**
|
||||
* @var mixed[][]
|
||||
* @phpstan-var array<string, array{0: int, 1: bool|int|float}>
|
||||
* @phpstan-var array<string, array{0: int, 1: bool|int|float, 2: bool}>
|
||||
*/
|
||||
public $gameRules = [ //TODO: implement this
|
||||
"naturalregeneration" => [GameRuleType::BOOL, false] //Hack for client side regeneration
|
||||
"naturalregeneration" => [GameRuleType::BOOL, false, false] //Hack for client side regeneration
|
||||
];
|
||||
/** @var Experiments */
|
||||
public $experiments;
|
||||
@ -176,6 +176,8 @@ class StartGamePacket extends DataPacket{
|
||||
public $itemTable;
|
||||
/** @var bool */
|
||||
public $enableNewInventorySystem = false; //TODO
|
||||
/** @var string */
|
||||
public $serverSoftwareVersion;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->entityUniqueId = $this->getEntityUniqueId();
|
||||
@ -258,6 +260,7 @@ class StartGamePacket extends DataPacket{
|
||||
|
||||
$this->multiplayerCorrelationId = $this->getString();
|
||||
$this->enableNewInventorySystem = $this->getBool();
|
||||
$this->serverSoftwareVersion = $this->getString();
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
@ -337,6 +340,7 @@ class StartGamePacket extends DataPacket{
|
||||
|
||||
$this->putString($this->multiplayerCorrelationId);
|
||||
$this->putBool($this->enableNewInventorySystem);
|
||||
$this->putString($this->serverSoftwareVersion);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
|
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class SyncActorPropertyPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::SYNC_ACTOR_PROPERTY_PACKET;
|
||||
|
||||
/** @var CompoundTag */
|
||||
private $data;
|
||||
|
||||
public static function create(CompoundTag $data) : self{
|
||||
$result = new self;
|
||||
$result->data = $data;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getData() : CompoundTag{ return $this->data; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->data = $this->getNbtCompoundRoot();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->put((new NetworkLittleEndianNBTStream())->write($this->data));
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleSyncActorProperty($this);
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ use pocketmine\inventory\transaction\action\InventoryAction;
|
||||
use pocketmine\inventory\transaction\action\SlotChangeAction;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
|
||||
use pocketmine\Player;
|
||||
use function array_key_exists;
|
||||
@ -79,17 +80,15 @@ class NetworkInventoryAction{
|
||||
public $sourceFlags = 0;
|
||||
/** @var int */
|
||||
public $inventorySlot;
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $oldItem;
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $newItem;
|
||||
/** @var int|null */
|
||||
public $newItemStackId = null;
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function read(NetworkBinaryStream $packet, bool $hasItemStackIds){
|
||||
public function read(NetworkBinaryStream $packet){
|
||||
$this->sourceType = $packet->getUnsignedVarInt();
|
||||
|
||||
switch($this->sourceType){
|
||||
@ -109,11 +108,8 @@ class NetworkInventoryAction{
|
||||
}
|
||||
|
||||
$this->inventorySlot = $packet->getUnsignedVarInt();
|
||||
$this->oldItem = $packet->getSlot();
|
||||
$this->newItem = $packet->getSlot();
|
||||
if($hasItemStackIds){
|
||||
$this->newItemStackId = $packet->readGenericTypeNetworkId();
|
||||
}
|
||||
$this->oldItem = ItemStackWrapper::read($packet);
|
||||
$this->newItem = ItemStackWrapper::read($packet);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -121,7 +117,7 @@ class NetworkInventoryAction{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function write(NetworkBinaryStream $packet, bool $hasItemStackIds){
|
||||
public function write(NetworkBinaryStream $packet){
|
||||
$packet->putUnsignedVarInt($this->sourceType);
|
||||
|
||||
switch($this->sourceType){
|
||||
@ -141,14 +137,8 @@ class NetworkInventoryAction{
|
||||
}
|
||||
|
||||
$packet->putUnsignedVarInt($this->inventorySlot);
|
||||
$packet->putSlot($this->oldItem);
|
||||
$packet->putSlot($this->newItem);
|
||||
if($hasItemStackIds){
|
||||
if($this->newItemStackId === null){
|
||||
throw new \InvalidStateException("Item stack ID for newItem must be provided");
|
||||
}
|
||||
$packet->writeGenericTypeNetworkId($this->newItemStackId);
|
||||
}
|
||||
$this->oldItem->write($packet);
|
||||
$this->newItem->write($packet);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,7 +147,9 @@ class NetworkInventoryAction{
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
public function createInventoryAction(Player $player){
|
||||
if($this->oldItem->equalsExact($this->newItem)){
|
||||
$oldItem = $this->oldItem->getItemStack();
|
||||
$newItem = $this->newItem->getItemStack();
|
||||
if($oldItem->equalsExact($newItem)){
|
||||
//filter out useless noise in 1.13
|
||||
return null;
|
||||
}
|
||||
@ -187,7 +179,7 @@ class NetworkInventoryAction{
|
||||
$slot = $this->inventorySlot;
|
||||
}
|
||||
if($window !== null){
|
||||
return new SlotChangeAction($window, $slot, $this->oldItem, $this->newItem);
|
||||
return new SlotChangeAction($window, $slot, $oldItem, $newItem);
|
||||
}
|
||||
|
||||
throw new \UnexpectedValueException("Player " . $player->getName() . " has no open container with window ID $this->windowId");
|
||||
@ -196,7 +188,7 @@ class NetworkInventoryAction{
|
||||
throw new \UnexpectedValueException("Only expecting drop-item world actions from the client!");
|
||||
}
|
||||
|
||||
return new DropItemAction($this->newItem);
|
||||
return new DropItemAction($newItem);
|
||||
case self::SOURCE_CREATIVE:
|
||||
switch($this->inventorySlot){
|
||||
case self::ACTION_MAGIC_SLOT_CREATIVE_DELETE_ITEM:
|
||||
@ -210,7 +202,7 @@ class NetworkInventoryAction{
|
||||
|
||||
}
|
||||
|
||||
return new CreativeInventoryAction($this->oldItem, $this->newItem, $type);
|
||||
return new CreativeInventoryAction($oldItem, $newItem, $type);
|
||||
case self::SOURCE_TODO:
|
||||
//These types need special handling.
|
||||
switch($this->windowId){
|
||||
|
@ -30,7 +30,7 @@ use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
|
||||
* The flags should be written as
|
||||
* `flags |= (1 << flag)`
|
||||
* and read as
|
||||
* `(flags & (1 & flag)) !== 0`
|
||||
* `(flags & (1 << flag)) !== 0`
|
||||
*
|
||||
* @see PlayerAuthInputPacket
|
||||
*/
|
||||
@ -56,8 +56,8 @@ final class PlayerAuthInputFlags{
|
||||
public const WANT_DOWN_SLOW = 18;
|
||||
public const WANT_UP_SLOW = 19;
|
||||
public const SPRINTING = 20;
|
||||
public const ASCEND_SCAFFOLDING = 21;
|
||||
public const DESCEND_SCAFFOLDING = 22;
|
||||
public const ASCEND_BLOCK = 21;
|
||||
public const DESCEND_BLOCK = 22;
|
||||
public const SNEAK_TOGGLE_DOWN = 23;
|
||||
public const PERSIST_SNEAK = 24;
|
||||
public const START_SPRINTING = 25;
|
||||
|
@ -44,12 +44,12 @@ final class CreativeContentEntry{
|
||||
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$entryId = $in->readGenericTypeNetworkId();
|
||||
$item = $in->getSlot();
|
||||
$item = $in->getItemStackWithoutStackId();
|
||||
return new self($entryId, $item);
|
||||
}
|
||||
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->writeGenericTypeNetworkId($this->entryId);
|
||||
$out->putSlot($this->item);
|
||||
$out->putItemStackWithoutStackId($this->item);
|
||||
}
|
||||
}
|
||||
|
@ -47,13 +47,22 @@ final class ItemStackWrapper{
|
||||
public function getItemStack() : Item{ return $this->itemStack; }
|
||||
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$stackId = $in->readGenericTypeNetworkId();
|
||||
$stack = $in->getSlot();
|
||||
$stackId = 0;
|
||||
$stack = $in->getItemStack(function(NetworkBinaryStream $in) use (&$stackId) : void{
|
||||
$hasNetId = $in->getBool();
|
||||
if($hasNetId){
|
||||
$stackId = $in->readGenericTypeNetworkId();
|
||||
}
|
||||
});
|
||||
return new self($stackId, $stack);
|
||||
}
|
||||
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->writeGenericTypeNetworkId($this->stackId);
|
||||
$out->putSlot($this->itemStack);
|
||||
$out->putItemStack($this->itemStack, function(NetworkBinaryStream $out) : void{
|
||||
$out->putBool($this->stackId !== 0);
|
||||
if($this->stackId !== 0){
|
||||
$out->writeGenericTypeNetworkId($this->stackId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use UnexpectedValueException as PacketDecodeException;
|
||||
use function count;
|
||||
|
||||
class MismatchTransactionData extends TransactionData{
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
protected function decodeData(PacketSerializer $stream) : void{
|
||||
if(count($this->actions) > 0){
|
||||
throw new PacketDecodeException("Mismatch transaction type should not have any actions associated with it, but got " . count($this->actions));
|
||||
}
|
||||
}
|
||||
|
||||
protected function encodeData(PacketSerializer $stream) : void{
|
||||
|
||||
}
|
||||
|
||||
public static function new() : self{
|
||||
return new self; //no arguments
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
|
||||
class NormalTransactionData extends TransactionData{
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_NORMAL;
|
||||
}
|
||||
|
||||
protected function decodeData(PacketSerializer $stream) : void{
|
||||
|
||||
}
|
||||
|
||||
protected function encodeData(PacketSerializer $stream) : void{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NetworkInventoryAction[] $actions
|
||||
*
|
||||
* @return NormalTransactionData
|
||||
*/
|
||||
public static function new(array $actions) : self{
|
||||
$result = new self();
|
||||
$result->actions = $actions;
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
|
||||
class ReleaseItemTransactionData extends TransactionData{
|
||||
public const ACTION_RELEASE = 0; //bow shoot
|
||||
public const ACTION_CONSUME = 1; //eat food, drink potion
|
||||
|
||||
/** @var int */
|
||||
private $actionType;
|
||||
/** @var int */
|
||||
private $hotbarSlot;
|
||||
/** @var ItemStackWrapper */
|
||||
private $itemInHand;
|
||||
/** @var Vector3 */
|
||||
private $headPos;
|
||||
|
||||
public function getActionType() : int{
|
||||
return $this->actionType;
|
||||
}
|
||||
|
||||
public function getHotbarSlot() : int{
|
||||
return $this->hotbarSlot;
|
||||
}
|
||||
|
||||
public function getItemInHand() : ItemStackWrapper{
|
||||
return $this->itemInHand;
|
||||
}
|
||||
|
||||
public function getHeadPos() : Vector3{
|
||||
return $this->headPos;
|
||||
}
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_RELEASE_ITEM;
|
||||
}
|
||||
|
||||
protected function decodeData(PacketSerializer $stream) : void{
|
||||
$this->actionType = $stream->getUnsignedVarInt();
|
||||
$this->hotbarSlot = $stream->getVarInt();
|
||||
$this->itemInHand = ItemStackWrapper::read($stream);
|
||||
$this->headPos = $stream->getVector3();
|
||||
}
|
||||
|
||||
protected function encodeData(PacketSerializer $stream) : void{
|
||||
$stream->putUnsignedVarInt($this->actionType);
|
||||
$stream->putVarInt($this->hotbarSlot);
|
||||
$this->itemInHand->write($stream);
|
||||
$stream->putVector3($this->headPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NetworkInventoryAction[] $actions
|
||||
*/
|
||||
public static function new(array $actions, int $actionType, int $hotbarSlot, ItemStackWrapper $itemInHand, Vector3 $headPos) : self{
|
||||
$result = new self;
|
||||
$result->actions = $actions;
|
||||
$result->actionType = $actionType;
|
||||
$result->hotbarSlot = $hotbarSlot;
|
||||
$result->itemInHand = $itemInHand;
|
||||
$result->headPos = $headPos;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
use pocketmine\utils\BinaryDataException;
|
||||
use UnexpectedValueException as PacketDecodeException;
|
||||
use function count;
|
||||
|
||||
abstract class TransactionData{
|
||||
/** @var NetworkInventoryAction[] */
|
||||
protected $actions = [];
|
||||
|
||||
/**
|
||||
* @return NetworkInventoryAction[]
|
||||
*/
|
||||
final public function getActions() : array{
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
abstract public function getTypeId() : int;
|
||||
|
||||
/**
|
||||
* @throws BinaryDataException
|
||||
* @throws PacketDecodeException
|
||||
*/
|
||||
final public function decode(PacketSerializer $stream) : void{
|
||||
$actionCount = $stream->getUnsignedVarInt();
|
||||
for($i = 0; $i < $actionCount; ++$i){
|
||||
$this->actions[] = (new NetworkInventoryAction())->read($stream);
|
||||
}
|
||||
$this->decodeData($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BinaryDataException
|
||||
* @throws PacketDecodeException
|
||||
*/
|
||||
abstract protected function decodeData(PacketSerializer $stream) : void;
|
||||
|
||||
final public function encode(PacketSerializer $stream) : void{
|
||||
$stream->putUnsignedVarInt(count($this->actions));
|
||||
foreach($this->actions as $action){
|
||||
$action->write($stream);
|
||||
}
|
||||
$this->encodeData($stream);
|
||||
}
|
||||
|
||||
abstract protected function encodeData(PacketSerializer $stream) : void;
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
|
||||
class UseItemOnEntityTransactionData extends TransactionData{
|
||||
public const ACTION_INTERACT = 0;
|
||||
public const ACTION_ATTACK = 1;
|
||||
public const ACTION_ITEM_INTERACT = 2;
|
||||
|
||||
/** @var int */
|
||||
private $entityRuntimeId;
|
||||
/** @var int */
|
||||
private $actionType;
|
||||
/** @var int */
|
||||
private $hotbarSlot;
|
||||
/** @var ItemStackWrapper */
|
||||
private $itemInHand;
|
||||
/** @var Vector3 */
|
||||
private $playerPos;
|
||||
/** @var Vector3 */
|
||||
private $clickPos;
|
||||
|
||||
public function getEntityRuntimeId() : int{
|
||||
return $this->entityRuntimeId;
|
||||
}
|
||||
|
||||
public function getActionType() : int{
|
||||
return $this->actionType;
|
||||
}
|
||||
|
||||
public function getHotbarSlot() : int{
|
||||
return $this->hotbarSlot;
|
||||
}
|
||||
|
||||
public function getItemInHand() : ItemStackWrapper{
|
||||
return $this->itemInHand;
|
||||
}
|
||||
|
||||
public function getPlayerPos() : Vector3{
|
||||
return $this->playerPos;
|
||||
}
|
||||
|
||||
public function getClickPos() : Vector3{
|
||||
return $this->clickPos;
|
||||
}
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_USE_ITEM_ON_ENTITY;
|
||||
}
|
||||
|
||||
protected function decodeData(PacketSerializer $stream) : void{
|
||||
$this->entityRuntimeId = $stream->getEntityRuntimeId();
|
||||
$this->actionType = $stream->getUnsignedVarInt();
|
||||
$this->hotbarSlot = $stream->getVarInt();
|
||||
$this->itemInHand = ItemStackWrapper::read($stream);
|
||||
$this->playerPos = $stream->getVector3();
|
||||
$this->clickPos = $stream->getVector3();
|
||||
}
|
||||
|
||||
protected function encodeData(PacketSerializer $stream) : void{
|
||||
$stream->putEntityRuntimeId($this->entityRuntimeId);
|
||||
$stream->putUnsignedVarInt($this->actionType);
|
||||
$stream->putVarInt($this->hotbarSlot);
|
||||
$this->itemInHand->write($stream);
|
||||
$stream->putVector3($this->playerPos);
|
||||
$stream->putVector3($this->clickPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NetworkInventoryAction[] $actions
|
||||
*/
|
||||
public static function new(array $actions, int $entityRuntimeId, int $actionType, int $hotbarSlot, ItemStackWrapper $itemInHand, Vector3 $playerPos, Vector3 $clickPos) : self{
|
||||
$result = new self;
|
||||
$result->actions = $actions;
|
||||
$result->entityRuntimeId = $entityRuntimeId;
|
||||
$result->actionType = $actionType;
|
||||
$result->hotbarSlot = $hotbarSlot;
|
||||
$result->itemInHand = $itemInHand;
|
||||
$result->playerPos = $playerPos;
|
||||
$result->clickPos = $clickPos;
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
|
||||
class UseItemTransactionData extends TransactionData{
|
||||
public const ACTION_CLICK_BLOCK = 0;
|
||||
public const ACTION_CLICK_AIR = 1;
|
||||
public const ACTION_BREAK_BLOCK = 2;
|
||||
|
||||
/** @var int */
|
||||
private $actionType;
|
||||
/** @var Vector3 */
|
||||
private $blockPos;
|
||||
/** @var int */
|
||||
private $face;
|
||||
/** @var int */
|
||||
private $hotbarSlot;
|
||||
/** @var ItemStackWrapper */
|
||||
private $itemInHand;
|
||||
/** @var Vector3 */
|
||||
private $playerPos;
|
||||
/** @var Vector3 */
|
||||
private $clickPos;
|
||||
/** @var int */
|
||||
private $blockRuntimeId;
|
||||
|
||||
public function getActionType() : int{
|
||||
return $this->actionType;
|
||||
}
|
||||
|
||||
public function getBlockPos() : Vector3{
|
||||
return $this->blockPos;
|
||||
}
|
||||
|
||||
public function getFace() : int{
|
||||
return $this->face;
|
||||
}
|
||||
|
||||
public function getHotbarSlot() : int{
|
||||
return $this->hotbarSlot;
|
||||
}
|
||||
|
||||
public function getItemInHand() : ItemStackWrapper{
|
||||
return $this->itemInHand;
|
||||
}
|
||||
|
||||
public function getPlayerPos() : Vector3{
|
||||
return $this->playerPos;
|
||||
}
|
||||
|
||||
public function getClickPos() : Vector3{
|
||||
return $this->clickPos;
|
||||
}
|
||||
|
||||
public function getBlockRuntimeId() : int{
|
||||
return $this->blockRuntimeId;
|
||||
}
|
||||
|
||||
public function getTypeId() : int{
|
||||
return InventoryTransactionPacket::TYPE_USE_ITEM;
|
||||
}
|
||||
|
||||
protected function decodeData(PacketSerializer $stream) : void{
|
||||
$this->actionType = $stream->getUnsignedVarInt();
|
||||
$x = $y = $z = 0;
|
||||
$stream->getBlockPosition($x, $y, $z);
|
||||
$this->blockPos = new Vector3($x, $y, $z);
|
||||
$this->face = $stream->getVarInt();
|
||||
$this->hotbarSlot = $stream->getVarInt();
|
||||
$this->itemInHand = ItemStackWrapper::read($stream);
|
||||
$this->playerPos = $stream->getVector3();
|
||||
$this->clickPos = $stream->getVector3();
|
||||
$this->blockRuntimeId = $stream->getUnsignedVarInt();
|
||||
}
|
||||
|
||||
protected function encodeData(PacketSerializer $stream) : void{
|
||||
$stream->putUnsignedVarInt($this->actionType);
|
||||
$stream->putBlockPosition($this->blockPos->x, $this->blockPos->y, $this->blockPos->z);
|
||||
$stream->putVarInt($this->face);
|
||||
$stream->putVarInt($this->hotbarSlot);
|
||||
$this->itemInHand->write($stream);
|
||||
$stream->putVector3($this->playerPos);
|
||||
$stream->putVector3($this->clickPos);
|
||||
$stream->putUnsignedVarInt($this->blockRuntimeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NetworkInventoryAction[] $actions
|
||||
*/
|
||||
public static function new(array $actions, int $actionType, Vector3 $blockPos, int $face, int $hotbarSlot, ItemStackWrapper $itemInHand, Vector3 $playerPos, Vector3 $clickPos, int $blockRuntimeId) : self{
|
||||
$result = new self;
|
||||
$result->actions = $actions;
|
||||
$result->actionType = $actionType;
|
||||
$result->blockPos = $blockPos;
|
||||
$result->face = $face;
|
||||
$result->hotbarSlot = $hotbarSlot;
|
||||
$result->itemInHand = $itemInHand;
|
||||
$result->playerPos = $playerPos;
|
||||
$result->clickPos = $clickPos;
|
||||
$result->blockRuntimeId = $blockRuntimeId;
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ final class DeprecatedCraftingResultsStackRequestAction extends ItemStackRequest
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$results = [];
|
||||
for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$results[] = $in->getSlot();
|
||||
$results[] = $in->getItemStackWithoutStackId();
|
||||
}
|
||||
$iterations = $in->getByte();
|
||||
return new self($results, $iterations);
|
||||
@ -67,7 +67,7 @@ final class DeprecatedCraftingResultsStackRequestAction extends ItemStackRequest
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->putUnsignedVarInt(count($this->results));
|
||||
foreach($this->results as $result){
|
||||
$out->putSlot($result);
|
||||
$out->putItemStackWithoutStackId($result);
|
||||
}
|
||||
$out->putByte($this->iterations);
|
||||
}
|
||||
|
@ -57,15 +57,24 @@ use const SOL_TCP;
|
||||
class RCON{
|
||||
/** @var Server */
|
||||
private $server;
|
||||
/** @var resource */
|
||||
/**
|
||||
* @var \Socket|resource
|
||||
* @phpstan-var PhpSocket
|
||||
*/
|
||||
private $socket;
|
||||
|
||||
/** @var RCONInstance */
|
||||
private $instance;
|
||||
|
||||
/** @var resource */
|
||||
/**
|
||||
* @var \Socket|resource
|
||||
* @phpstan-var PhpSocket
|
||||
*/
|
||||
private $ipcMainSocket;
|
||||
/** @var resource */
|
||||
/**
|
||||
* @var resource
|
||||
* @phpstan-var PhpSocket
|
||||
*/
|
||||
private $ipcThreadSocket;
|
||||
|
||||
public function __construct(Server $server, string $password, int $port = 19132, string $interface = "0.0.0.0", int $maxClients = 50){
|
||||
|
@ -60,7 +60,10 @@ class RCONInstance extends Thread{
|
||||
|
||||
/** @var bool */
|
||||
private $stop;
|
||||
/** @var resource */
|
||||
/**
|
||||
* @var \Socket|resource
|
||||
* @phpstan-var PhpSocket
|
||||
*/
|
||||
private $socket;
|
||||
/** @var string */
|
||||
private $password;
|
||||
@ -68,14 +71,19 @@ class RCONInstance extends Thread{
|
||||
private $maxClients;
|
||||
/** @var \ThreadedLogger */
|
||||
private $logger;
|
||||
/** @var resource */
|
||||
/**
|
||||
* @var \Socket|resource
|
||||
* @phpstan-var PhpSocket
|
||||
*/
|
||||
private $ipcSocket;
|
||||
/** @var SleeperNotifier|null */
|
||||
private $notifier;
|
||||
|
||||
/**
|
||||
* @param resource $socket
|
||||
* @param resource $ipcSocket
|
||||
* @param \Socket|resource $socket
|
||||
* @param \Socket|resource $ipcSocket
|
||||
* @phpstan-param PhpSocket $socket
|
||||
* @phpstan-param PhpSocket $ipcSocket
|
||||
*/
|
||||
public function __construct($socket, string $password, int $maxClients, \ThreadedLogger $logger, $ipcSocket, ?SleeperNotifier $notifier){
|
||||
$this->stop = false;
|
||||
@ -92,7 +100,8 @@ class RCONInstance extends Thread{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource $client
|
||||
* @param \Socket|resource $client
|
||||
* @phpstan-param PhpSocket $client
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
@ -105,10 +114,11 @@ class RCONInstance extends Thread{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource $client
|
||||
* @param \Socket|resource $client
|
||||
* @param int $requestID reference parameter
|
||||
* @param int $packetType reference parameter
|
||||
* @param string $payload reference parameter
|
||||
* @phpstan-param PhpSocket $client
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@ -165,7 +175,10 @@ class RCONInstance extends Thread{
|
||||
public function run(){
|
||||
$this->registerClassLoader();
|
||||
|
||||
/** @var resource[] $clients */
|
||||
/**
|
||||
* @var \Socket[]|resource[] $clients
|
||||
* @phpstan-var array<int, PhpSocket> $clients
|
||||
*/
|
||||
$clients = [];
|
||||
/** @var bool[] $authenticated */
|
||||
$authenticated = [];
|
||||
@ -265,7 +278,8 @@ class RCONInstance extends Thread{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource $client
|
||||
* @param \Socket|resource $client
|
||||
* @phpstan-param PhpSocket $client
|
||||
*/
|
||||
private function disconnectClient($client) : void{
|
||||
socket_getpeername($client, $ip, $port);
|
||||
|
Submodule src/pocketmine/resources/vanilla updated: 989e02a631...21ec07f14e
@ -177,7 +177,7 @@ class TaskScheduler{
|
||||
continue;
|
||||
}
|
||||
$task->run($this->currentTick);
|
||||
if($task->isRepeating()){
|
||||
if(!$task->isCancelled() && $task->isRepeating()){
|
||||
$task->setNextRun($this->currentTick + $task->getPeriod());
|
||||
$this->queue->insert($task, $this->currentTick + $task->getPeriod());
|
||||
}else{
|
||||
|
@ -52,6 +52,9 @@ class Sign extends Spawnable{
|
||||
/** @var string[] */
|
||||
protected $text = ["", "", "", ""];
|
||||
|
||||
/** @var int|null */
|
||||
protected $editorEntityRuntimeId = null;
|
||||
|
||||
protected function readSaveData(CompoundTag $nbt) : void{
|
||||
if($nbt->hasTag(self::TAG_TEXT_BLOB, StringTag::class)){ //MCPE 1.2 save format
|
||||
$this->text = self::fixTextBlob($nbt->getString(self::TAG_TEXT_BLOB));
|
||||
@ -132,6 +135,22 @@ class Sign extends Spawnable{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity runtime ID of the player who placed this sign. Only the player whose entity ID matches this
|
||||
* one may edit the sign text.
|
||||
* This is needed because as of 1.16.220, there is still no reliable way to detect when the MCPE client closed the
|
||||
* sign edit GUI, so we have no way to know when the text is finalized. This limits editing of the text to only the
|
||||
* player who placed it, and only while that player is online.
|
||||
* We can say for sure that the sign is finalized if either of the following occurs:
|
||||
* - The player quits (after rejoin, the player's entity runtimeID will be different).
|
||||
* - The chunk is unloaded (on next load, the entity runtimeID will be null, because it's not saved).
|
||||
*/
|
||||
public function getEditorEntityRuntimeId() : ?int{ return $this->editorEntityRuntimeId; }
|
||||
|
||||
public function setEditorEntityRuntimeId(?int $editorEntityRuntimeId) : void{
|
||||
$this->editorEntityRuntimeId = $editorEntityRuntimeId;
|
||||
}
|
||||
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));
|
||||
}
|
||||
@ -158,6 +177,9 @@ class Sign extends Spawnable{
|
||||
$removeFormat = $player->getRemoveFormat();
|
||||
|
||||
$ev = new SignChangeEvent($this->getBlock(), $player, array_map(function(string $line) use ($removeFormat) : string{ return TextFormat::clean($line, $removeFormat); }, $lines));
|
||||
if($this->editorEntityRuntimeId === null || $this->editorEntityRuntimeId !== $player->getId()){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
$ev->call();
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
|
@ -258,7 +258,7 @@ class Config{
|
||||
/**
|
||||
* Sets the options for the JSON encoding when saving
|
||||
*
|
||||
* @return Config $this
|
||||
* @return $this
|
||||
* @throws \RuntimeException if the Config is not in JSON
|
||||
* @see json_encode
|
||||
*/
|
||||
@ -275,7 +275,7 @@ class Config{
|
||||
/**
|
||||
* Enables the given option in addition to the currently set JSON options
|
||||
*
|
||||
* @return Config $this
|
||||
* @return $this
|
||||
* @throws \RuntimeException if the Config is not in JSON
|
||||
* @see json_encode
|
||||
*/
|
||||
@ -292,7 +292,7 @@ class Config{
|
||||
/**
|
||||
* Disables the given option for the JSON encoding when saving
|
||||
*
|
||||
* @return Config $this
|
||||
* @return $this
|
||||
* @throws \RuntimeException if the Config is not in JSON
|
||||
* @see json_encode
|
||||
*/
|
||||
|
@ -196,7 +196,7 @@ class Internet{
|
||||
* @param callable|null $onSuccess function to be called if there is no error. Accepts a resource argument as the cURL handle.
|
||||
* @phpstan-param array<int, mixed> $extraOpts
|
||||
* @phpstan-param list<string> $extraHeaders
|
||||
* @phpstan-param (callable(resource) : void)|null $onSuccess
|
||||
* @phpstan-param (callable(PhpCurlHandle) : void)|null $onSuccess
|
||||
*
|
||||
* @return array a plain array of three [result body : string, headers : string[][], HTTP response code : int]. Headers are grouped by requests with strtolower(header name) as keys and header value as values
|
||||
* @phpstan-return array{string, list<array<string, string>>, int}
|
||||
|
@ -454,7 +454,7 @@ class Utils{
|
||||
* @param callable|null $onSuccess function to be called if there is no error. Accepts a resource argument as the cURL handle.
|
||||
* @phpstan-param array<int, mixed> $extraOpts
|
||||
* @phpstan-param list<string> $extraHeaders
|
||||
* @phpstan-param (callable(resource) : void)|null $onSuccess
|
||||
* @phpstan-param (callable(PhpCurlHandle) : void)|null $onSuccess
|
||||
*
|
||||
* @return array a plain array of three [result body : string, headers : string[][], HTTP response code : int]. Headers are grouped by requests with strtolower(header name) as keys and header value as values
|
||||
* @phpstan-return array{string, list<array<string, string>>, int}
|
||||
|
@ -1,5 +1,5 @@
|
||||
@echo off
|
||||
TITLE PocketMine-MP server software for Minecraft: Pocket Edition
|
||||
TITLE PocketMine-MP server software for Minecraft: Bedrock Edition
|
||||
cd /d %~dp0
|
||||
|
||||
if exist bin\php\php.exe (
|
||||
@ -22,5 +22,5 @@ if exist bin\mintty.exe (
|
||||
start "" bin\mintty.exe -o Columns=88 -o Rows=32 -o AllowBlinking=0 -o FontQuality=3 -o Font="Consolas" -o FontHeight=10 -o CursorType=0 -o CursorBlinks=1 -h error -t "PocketMine-MP" -i bin/pocketmine.ico -w max %PHP_BINARY% %POCKETMINE_FILE% --enable-ansi %*
|
||||
) else (
|
||||
REM pause on exitcode != 0 so the user can see what went wrong
|
||||
%PHP_BINARY% -c bin\php %POCKETMINE_FILE% %* || pause
|
||||
%PHP_BINARY% %POCKETMINE_FILE% %* || pause
|
||||
)
|
||||
|
@ -21,6 +21,5 @@ git clone https://github.com/php-build/php-build.git
|
||||
cd php-build
|
||||
./install-dependencies.sh
|
||||
echo '"pthreads",,"https://github.com/pmmp/pthreads.git",,,"extension",' >> share/php-build/extension/definition
|
||||
PHP_BUILD_INSTALL_EXTENSION='pthreads=@acc6e52b2144c61c434b62a3cb680d537e06828e yaml=2.2.1' PHP_BUILD_ZTS_ENABLE=on ./bin/php-build "$VERSION" "$INSTALL_DIR" || exit 1
|
||||
PHP_BUILD_INSTALL_EXTENSION='pthreads=@a6afc0434f91c1e9541444aef6ac7a1f16c595be yaml=2.2.1' PHP_BUILD_ZTS_ENABLE=on ./bin/php-build "$VERSION" "$INSTALL_DIR" || exit 1
|
||||
rm "$INSTALL_DIR/etc/conf.d/xdebug.ini" || true
|
||||
cp install-dependencies.sh "$INSTALL_DIR"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user