mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-23 11:54:04 +00:00
Merge branch 'minor-next' into major-next
This commit is contained in:
commit
e781c64540
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -34,7 +34,10 @@ Requires translations:
|
||||
|
||||
## Tests
|
||||
<!--
|
||||
Details should be provided of tests done. Simply saying "tested" or equivalent is not acceptable.
|
||||
|
||||
Attach scripts or actions to test this pull request, as well as the result
|
||||
PRs which have not been tested MUST be marked as draft.
|
||||
-->
|
||||
I tested this PR by doing the following (tick all that apply):
|
||||
- [ ] Writing PHPUnit tests (commit these in the `tests/phpunit` folder)
|
||||
- [ ] Playtesting using a Minecraft client (provide screenshots or a video)
|
||||
- [ ] Writing a test plugin (provide the code and sample output)
|
||||
- [ ] Other (provide details)
|
||||
|
8
.github/workflows/build-docker-image.yml
vendored
8
.github/workflows/build-docker-image.yml
vendored
@ -53,7 +53,7 @@ jobs:
|
||||
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v5.2.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v5.2.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v5.2.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v5.2.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.29.0
|
||||
uses: shivammathur/setup-php@2.30.0
|
||||
with:
|
||||
php-version: 8.2
|
||||
|
||||
|
4
.github/workflows/draft-release.yml
vendored
4
.github/workflows/draft-release.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.29.0
|
||||
uses: shivammathur/setup-php@2.30.0
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
|
||||
@ -86,7 +86,7 @@ jobs:
|
||||
${{ github.workspace }}/build_info.json
|
||||
|
||||
- name: Create draft release
|
||||
uses: ncipollo/release-action@v1.13.0
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||
commit: ${{ github.sha }}
|
||||
|
8
.github/workflows/main-php-matrix.yml
vendored
8
.github/workflows/main-php-matrix.yml
vendored
@ -30,7 +30,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
@ -62,7 +62,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
@ -96,7 +96,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
@ -128,7 +128,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
|
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.29.0
|
||||
uses: shivammathur/setup-php@2.30.0
|
||||
with:
|
||||
php-version: 8.2
|
||||
tools: php-cs-fixer:3.49
|
||||
|
133
build/generate-biome-ids.php
Normal file
133
build/generate-biome-ids.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?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\build\generate_biome_ids;
|
||||
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use function asort;
|
||||
use function dirname;
|
||||
use function fclose;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function is_array;
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function str_replace;
|
||||
use function strtoupper;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
const HEADER = <<<'HEADER'
|
||||
<?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);
|
||||
|
||||
|
||||
HEADER;
|
||||
|
||||
/** @return resource */
|
||||
function safe_fopen(string $file, string $flags){
|
||||
$result = fopen($file, $flags);
|
||||
if($result === false){
|
||||
throw new \RuntimeException("Failed to open file");
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function make_const_name(string $name) : string{
|
||||
return strtoupper(str_replace(['.', 'minecraft:'], ['_', ''], $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $map
|
||||
* @phpstan-param array<string, int> $map
|
||||
*/
|
||||
function generate(array $map, string $outputFile) : void{
|
||||
$file = safe_fopen($outputFile, 'wb');
|
||||
fwrite($file, HEADER);
|
||||
fwrite($file, <<<'CLASSHEADER'
|
||||
namespace pocketmine\data\bedrock;
|
||||
|
||||
final class BiomeIds{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
|
||||
CLASSHEADER
|
||||
);
|
||||
$list = $map;
|
||||
asort($list, SORT_NUMERIC);
|
||||
$lastId = -1;
|
||||
foreach(Utils::stringifyKeys($list) as $name => $id){
|
||||
if($name === ""){
|
||||
continue;
|
||||
}
|
||||
if($id !== $lastId + 1){
|
||||
fwrite($file, "\n");
|
||||
}
|
||||
$lastId = $id;
|
||||
fwrite($file, "\tpublic const " . make_const_name($name) . ' = ' . $id . ';' . "\n");
|
||||
}
|
||||
fwrite($file, "}\n");
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
$ids = json_decode(Filesystem::fileGetContents(BedrockDataFiles::BIOME_ID_MAP_JSON), true);
|
||||
if(!is_array($ids)){
|
||||
throw new \RuntimeException("Invalid biome ID map, expected array for root JSON object");
|
||||
}
|
||||
$cleanedIds = [];
|
||||
foreach($ids as $name => $id){
|
||||
if(!is_string($name) || !is_int($id)){
|
||||
throw new \RuntimeException("Invalid biome ID map, expected string => int map");
|
||||
}
|
||||
$cleanedIds[$name] = $id;
|
||||
}
|
||||
generate($cleanedIds, dirname(__DIR__) . '/src/data/bedrock/BiomeIds.php');
|
||||
|
||||
echo "Done. Don't forget to run CS fixup after generating code.\n";
|
@ -24,3 +24,22 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
|
||||
- Restructured GitHub Actions CI workflows to make them easier to maintain (no need to update PHP versions in multiple places anymore).
|
||||
- GitHub Actions CodeStyle workflow now uses php-cs-fixer 3.49.x.
|
||||
- Dependabot updates are now processed weekly instead of daily.
|
||||
|
||||
# 5.11.1
|
||||
Released 23rd February 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed subchunk count calculation in `ChunkSerializer` for non-overworld dimension (useful for dimension plugins).
|
||||
- Harden options used for processing JSON data, particularly on the network, to close security issues.
|
||||
|
||||
## Documentation
|
||||
- Fixed PHPStan signature for `Utils::cloneObjectArray()`.
|
||||
|
||||
## Internals
|
||||
- Updated GitHub Actions versions to get rid of deprecation warnings.
|
||||
|
||||
# 5.11.2
|
||||
Released 26th February 2024.
|
||||
|
||||
## Fixes
|
||||
- Added extra checks for `BookEditPacket` handling.
|
||||
|
63
changelogs/5.12.md
Normal file
63
changelogs/5.12.md
Normal file
@ -0,0 +1,63 @@
|
||||
# 5.12.0
|
||||
Released 28th February 2024
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.60**
|
||||
|
||||
This is a minor feature release, with a few new features and improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added a `--version` command-line option to display the server version and exit.
|
||||
|
||||
## Tools
|
||||
- Added `tools/generate-biome-ids.php` to generate `pocketmine\data\bedrock\BiomeIds`.
|
||||
- Fixed ordering of property values generated by `tools/generate-block-palette-spec.php`.
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new classes have been added:
|
||||
- `utils\LightableTrait` - used by blocks with `getLit()` and `setLit()` methods
|
||||
- The following methods have been deprecated:
|
||||
- `Block->isSolid()` - this method returns confusing results which don't match expectations and no one really knows what it actually means
|
||||
- `CocoaBlock` now extends `Flowable` to match vanilla Minecraft behaviour.
|
||||
|
||||
### `pocketmine\plugin`
|
||||
- `PluginManager->registerEvent()` now throws an exception when given a generator function for the event handler.
|
||||
- `PluginManager->registerEvents()` now throws an exception if any of the detected event handlers are generator functions. Use `@notHandler` to have the function ignored if intended.
|
||||
|
||||
### `pocketmine\promise`
|
||||
- The following methods have been added:
|
||||
- `public static Promise::all(list<Promise> $promises) : Promise` - returns a promise that is resolved once all given promises are resolved, or is rejected if any of the promises are rejected.
|
||||
|
||||
### `pocketmine\scheduler`
|
||||
- The following methods have been deprecated:
|
||||
- `AsyncWorker->getFromThreadStore()` - use class static properties for thread-local storage
|
||||
- `AsyncWorker->removeFromThreadStore()`
|
||||
- `AsyncWorker->saveToThreadStore()`
|
||||
|
||||
## Documentation
|
||||
- Improved documentation of various methods in `Block`.
|
||||
|
||||
## Gameplay
|
||||
- The following new items have been added:
|
||||
- Name Tag
|
||||
|
||||
## Internals
|
||||
- Removed specialization of shutdown logic for `Thread` vs `Worker` (no specialization is required).
|
||||
- Authentication system no longer accepts logins signed with the old Mojang root public key.
|
||||
- ID to enum mappings in `pocketmine\data` now use a new `match` convention to allow static analysis to ensure that all enum cases are handled.
|
||||
- Updated version of `pocketmine/bedrock-protocol` allows avoiding decoding of some itemstack data from the client in most cases, improving performance.
|
||||
|
||||
# 5.12.1
|
||||
Released 13th March 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed `Player Network Receive - Decompression` timings not being stopped correctly when receiving an uncompressed packet.
|
||||
|
||||
## Internals
|
||||
- Removed hardcoded batch packet size limit. This was already covered by other limits anyway.
|
16
changelogs/5.13.md
Normal file
16
changelogs/5.13.md
Normal file
@ -0,0 +1,16 @@
|
||||
# 5.13.0
|
||||
Released 13th March 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.70**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.70.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.70.
|
||||
- Removed support for earlier versions.
|
@ -32,11 +32,11 @@
|
||||
"ext-zlib": ">=1.2.11",
|
||||
"composer-runtime-api": "^2.0",
|
||||
"adhocore/json-comment": "~1.2.0",
|
||||
"pocketmine/netresearch-jsonmapper": "~v4.2.1000",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~3.5.0+bedrock-1.20.60",
|
||||
"pocketmine/bedrock-data": "~2.8.0+bedrock-1.20.60",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.7.0+bedrock-1.20.60",
|
||||
"pocketmine/bedrock-protocol": "~27.0.0+bedrock-1.20.60",
|
||||
"pocketmine/netresearch-jsonmapper": "~v4.4.999",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~3.6.0+bedrock-1.20.70",
|
||||
"pocketmine/bedrock-data": "~2.9.0+bedrock-1.20.70",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.8.0+bedrock-1.20.70",
|
||||
"pocketmine/bedrock-protocol": "~29.0.0+bedrock-1.20.70",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
@ -45,14 +45,14 @@
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/math": "~1.0.0",
|
||||
"pocketmine/nbt": "~1.0.0",
|
||||
"pocketmine/raklib": "^0.15.0",
|
||||
"pocketmine/raklib-ipc": "^0.2.0",
|
||||
"pocketmine/raklib": "~1.1.0",
|
||||
"pocketmine/raklib-ipc": "~1.0.0",
|
||||
"pocketmine/snooze": "^0.5.0",
|
||||
"ramsey/uuid": "~4.7.0",
|
||||
"symfony/filesystem": "~6.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.10.57",
|
||||
"phpstan/phpstan": "1.10.60",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "~10.3.0 || ~10.2.0 || ~10.1.0"
|
||||
|
287
composer.lock
generated
287
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "d923f5fd75f0d33eb5198268a74a58b4",
|
||||
"content-hash": "f3dd41a25226b5ff1030d822b2c46d02",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -122,16 +122,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-block-upgrade-schema",
|
||||
"version": "3.5.0",
|
||||
"version": "3.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
|
||||
"reference": "1ed4ba738333c4b4afe4fef8e9326a45c89f12e3"
|
||||
"reference": "1496e275db5148cb96bdaa998115e5e31a5c1e4d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/1ed4ba738333c4b4afe4fef8e9326a45c89f12e3",
|
||||
"reference": "1ed4ba738333c4b4afe4fef8e9326a45c89f12e3",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/1496e275db5148cb96bdaa998115e5e31a5c1e4d",
|
||||
"reference": "1496e275db5148cb96bdaa998115e5e31a5c1e4d",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -142,22 +142,22 @@
|
||||
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
|
||||
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/3.5.0"
|
||||
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/3.6.0"
|
||||
},
|
||||
"time": "2024-02-07T11:46:50+00:00"
|
||||
"time": "2024-02-28T19:25:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-data",
|
||||
"version": "2.8.0+bedrock-1.20.60",
|
||||
"version": "2.9.0+bedrock-1.20.70",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "d8ea0355b7c835564af9fe6e273e650ac62c84a2"
|
||||
"reference": "10b6696b662fd80a282eff7dca6c99d321c5b9e3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/d8ea0355b7c835564af9fe6e273e650ac62c84a2",
|
||||
"reference": "d8ea0355b7c835564af9fe6e273e650ac62c84a2",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/10b6696b662fd80a282eff7dca6c99d321c5b9e3",
|
||||
"reference": "10b6696b662fd80a282eff7dca6c99d321c5b9e3",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -168,22 +168,22 @@
|
||||
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockData/issues",
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.60"
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.70"
|
||||
},
|
||||
"time": "2024-02-07T11:23:46+00:00"
|
||||
"time": "2024-03-13T13:55:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-item-upgrade-schema",
|
||||
"version": "1.7.0",
|
||||
"version": "1.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
|
||||
"reference": "69772dd58e2b2c7b7513fa2bcdc46e782228641c"
|
||||
"reference": "4c4dc3bbceb944c5de429b6e752ab7a15652078c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/69772dd58e2b2c7b7513fa2bcdc46e782228641c",
|
||||
"reference": "69772dd58e2b2c7b7513fa2bcdc46e782228641c",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/4c4dc3bbceb944c5de429b6e752ab7a15652078c",
|
||||
"reference": "4c4dc3bbceb944c5de429b6e752ab7a15652078c",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -194,27 +194,26 @@
|
||||
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
|
||||
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.7.0"
|
||||
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.8.0"
|
||||
},
|
||||
"time": "2024-02-07T11:58:05+00:00"
|
||||
"time": "2024-02-28T19:25:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "27.0.1+bedrock-1.20.60",
|
||||
"version": "29.0.0+bedrock-1.20.70",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "0cebb55f6e904f722b14d420f6b2c84c7fa69f10"
|
||||
"reference": "8d63f39bb2cded3d3e578fd3cf7bc769b9674857"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/0cebb55f6e904f722b14d420f6b2c84c7fa69f10",
|
||||
"reference": "0cebb55f6e904f722b14d420f6b2c84c7fa69f10",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/8d63f39bb2cded3d3e578fd3cf7bc769b9674857",
|
||||
"reference": "8d63f39bb2cded3d3e578fd3cf7bc769b9674857",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"netresearch/jsonmapper": "^4.0",
|
||||
"php": "^8.1",
|
||||
"pocketmine/binaryutils": "^0.2.0",
|
||||
"pocketmine/color": "^0.2.0 || ^0.3.0",
|
||||
@ -223,7 +222,7 @@
|
||||
"ramsey/uuid": "^4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.10.39",
|
||||
"phpstan/phpstan": "1.10.59",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||
"phpunit/phpunit": "^9.5 || ^10.0"
|
||||
@ -241,22 +240,22 @@
|
||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/27.0.1+bedrock-1.20.60"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/29.0.0+bedrock-1.20.70"
|
||||
},
|
||||
"time": "2024-02-07T11:53:50+00:00"
|
||||
"time": "2024-03-13T14:35:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
"version": "0.2.4",
|
||||
"version": "0.2.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BinaryUtils.git",
|
||||
"reference": "5ac7eea91afbad8dc498f5ce34ce6297d5e6ea9a"
|
||||
"reference": "ccfc1899b859d45814ea3592e20ebec4cb731c84"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/5ac7eea91afbad8dc498f5ce34ce6297d5e6ea9a",
|
||||
"reference": "5ac7eea91afbad8dc498f5ce34ce6297d5e6ea9a",
|
||||
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/ccfc1899b859d45814ea3592e20ebec4cb731c84",
|
||||
"reference": "ccfc1899b859d45814ea3592e20ebec4cb731c84",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -265,10 +264,10 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "1.3.0",
|
||||
"phpstan/phpstan": "~1.10.3",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
"phpunit/phpunit": "^9.5 || ^10.0 || ^11.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -283,9 +282,9 @@
|
||||
"description": "Classes and methods for conveniently handling binary data",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BinaryUtils/issues",
|
||||
"source": "https://github.com/pmmp/BinaryUtils/tree/0.2.4"
|
||||
"source": "https://github.com/pmmp/BinaryUtils/tree/0.2.6"
|
||||
},
|
||||
"time": "2022-01-12T18:06:33+00:00"
|
||||
"time": "2024-03-04T15:04:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/callback-validator",
|
||||
@ -563,16 +562,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/netresearch-jsonmapper",
|
||||
"version": "v4.2.1000",
|
||||
"version": "v4.4.999",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/netresearch-jsonmapper.git",
|
||||
"reference": "078764e869e9b732f97206ec9363480a77c35532"
|
||||
"reference": "9a6610033d56e358e86a3e4fd5f87063c7318833"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/netresearch-jsonmapper/zipball/078764e869e9b732f97206ec9363480a77c35532",
|
||||
"reference": "078764e869e9b732f97206ec9363480a77c35532",
|
||||
"url": "https://api.github.com/repos/pmmp/netresearch-jsonmapper/zipball/9a6610033d56e358e86a3e4fd5f87063c7318833",
|
||||
"reference": "9a6610033d56e358e86a3e4fd5f87063c7318833",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -586,7 +585,7 @@
|
||||
"netresearch/jsonmapper": "~4.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~7.5 || ~8.0 || ~9.0",
|
||||
"phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
|
||||
"squizlabs/php_codesniffer": "~3.5"
|
||||
},
|
||||
"type": "library",
|
||||
@ -611,34 +610,34 @@
|
||||
"support": {
|
||||
"email": "cweiske@cweiske.de",
|
||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||
"source": "https://github.com/pmmp/netresearch-jsonmapper/tree/v4.2.1000"
|
||||
"source": "https://github.com/pmmp/netresearch-jsonmapper/tree/v4.4.999"
|
||||
},
|
||||
"time": "2023-07-14T10:44:14+00:00"
|
||||
"time": "2024-02-23T13:17:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib",
|
||||
"version": "0.15.1",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/RakLib.git",
|
||||
"reference": "79b7b4d1d7516dc6e322514453645ad9452b20ca"
|
||||
"reference": "be2783be516bf6e2872ff5c81fb9048596617b97"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/79b7b4d1d7516dc6e322514453645ad9452b20ca",
|
||||
"reference": "79b7b4d1d7516dc6e322514453645ad9452b20ca",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/be2783be516bf6e2872ff5c81fb9048596617b97",
|
||||
"reference": "be2783be516bf6e2872ff5c81fb9048596617b97",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-sockets": "*",
|
||||
"php": "^8.0",
|
||||
"php": "^8.1",
|
||||
"php-64bit": "*",
|
||||
"php-ipv6": "*",
|
||||
"pocketmine/binaryutils": "^0.2.0",
|
||||
"pocketmine/log": "^0.3.0 || ^0.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.9.17",
|
||||
"phpstan/phpstan": "1.10.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
@ -654,32 +653,32 @@
|
||||
"description": "A RakNet server implementation written in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/RakLib/issues",
|
||||
"source": "https://github.com/pmmp/RakLib/tree/0.15.1"
|
||||
"source": "https://github.com/pmmp/RakLib/tree/1.1.1"
|
||||
},
|
||||
"time": "2023-03-07T15:10:34+00:00"
|
||||
"time": "2024-03-04T14:02:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib-ipc",
|
||||
"version": "0.2.0",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/RakLibIpc.git",
|
||||
"reference": "26ed56fa9db06e4ca6e8920c0ede2e01e219bb9c"
|
||||
"reference": "ce632ef2c6743e71eddb5dc329c49af6555f90bc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLibIpc/zipball/26ed56fa9db06e4ca6e8920c0ede2e01e219bb9c",
|
||||
"reference": "26ed56fa9db06e4ca6e8920c0ede2e01e219bb9c",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLibIpc/zipball/ce632ef2c6743e71eddb5dc329c49af6555f90bc",
|
||||
"reference": "ce632ef2c6743e71eddb5dc329c49af6555f90bc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"php-64bit": "*",
|
||||
"pocketmine/binaryutils": "^0.2.0",
|
||||
"pocketmine/raklib": "^0.15.0"
|
||||
"pocketmine/raklib": "^0.15.0 || ^1.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.9.17",
|
||||
"phpstan/phpstan": "1.10.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
@ -695,9 +694,9 @@
|
||||
"description": "Channel-based protocols for inter-thread/inter-process communication with RakLib",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/RakLibIpc/issues",
|
||||
"source": "https://github.com/pmmp/RakLibIpc/tree/0.2.0"
|
||||
"source": "https://github.com/pmmp/RakLibIpc/tree/1.0.1"
|
||||
},
|
||||
"time": "2023-02-13T13:40:40+00:00"
|
||||
"time": "2024-03-01T15:55:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/snooze",
|
||||
@ -922,16 +921,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v6.4.0",
|
||||
"version": "v6.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59"
|
||||
"reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/952a8cb588c3bc6ce76f6023000fb932f16a6e59",
|
||||
"reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb",
|
||||
"reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -965,7 +964,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v6.4.0"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v6.4.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -981,20 +980,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-26T17:27:13+00:00"
|
||||
"time": "2024-01-23T14:51:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.28.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1008,9 +1007,6 @@
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
@ -1047,7 +1043,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1063,20 +1059,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.28.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229"
|
||||
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
|
||||
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1090,9 +1086,6 @@
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
@ -1130,7 +1123,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1146,7 +1139,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-28T09:04:16+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@ -1211,16 +1204,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.0.0",
|
||||
"version": "v5.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc"
|
||||
"reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4a21235f7e56e713259a6f76bf4b5ea08502b9dc",
|
||||
"reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13",
|
||||
"reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1263,26 +1256,27 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.0.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2"
|
||||
},
|
||||
"time": "2024-01-07T17:17:35+00:00"
|
||||
"time": "2024-03-05T20:51:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phar-io/manifest.git",
|
||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53"
|
||||
"reference": "54750ef60c58e43759730615a392c31c80e23176"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
|
||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53",
|
||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
|
||||
"reference": "54750ef60c58e43759730615a392c31c80e23176",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"phar-io/version": "^3.0.1",
|
||||
@ -1323,9 +1317,15 @@
|
||||
"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/2.0.3"
|
||||
"source": "https://github.com/phar-io/manifest/tree/2.0.4"
|
||||
},
|
||||
"time": "2021-07-20T11:28:43+00:00"
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/theseer",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-03T12:33:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/version",
|
||||
@ -1380,16 +1380,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.57",
|
||||
"version": "1.10.60",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "1627b1d03446904aaa77593f370c5201d2ecc34e"
|
||||
"reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/1627b1d03446904aaa77593f370c5201d2ecc34e",
|
||||
"reference": "1627b1d03446904aaa77593f370c5201d2ecc34e",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/95dcea7d6c628a3f2f56d091d8a0219485a86bbe",
|
||||
"reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1438,20 +1438,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-24T11:51:34+00:00"
|
||||
"time": "2024-03-07T13:30:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "1.3.15",
|
||||
"version": "1.3.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a"
|
||||
"reference": "d5242a59d035e46774f2e634b374bc39ff62cb95"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/70ecacc64fe8090d8d2a33db5a51fe8e88acd93a",
|
||||
"reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d5242a59d035e46774f2e634b374bc39ff62cb95",
|
||||
"reference": "d5242a59d035e46774f2e634b374bc39ff62cb95",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1488,9 +1488,9 @@
|
||||
"description": "PHPUnit extensions and rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.15"
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.16"
|
||||
},
|
||||
"time": "2023-10-09T18:58:39+00:00"
|
||||
"time": "2024-02-23T09:51:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
@ -1543,16 +1543,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "10.1.11",
|
||||
"version": "10.1.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "78c3b7625965c2513ee96569a4dbb62601784145"
|
||||
"reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/78c3b7625965c2513ee96569a4dbb62601784145",
|
||||
"reference": "78c3b7625965c2513ee96569a4dbb62601784145",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
|
||||
"reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1609,7 +1609,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.11"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1617,7 +1617,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-21T15:38:30+00:00"
|
||||
"time": "2024-03-12T15:33:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -1965,16 +1965,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/cli-parser.git",
|
||||
"reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae"
|
||||
"reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/efdc130dbbbb8ef0b545a994fd811725c5282cae",
|
||||
"reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084",
|
||||
"reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2009,7 +2009,8 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/cli-parser",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
|
||||
"source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.0"
|
||||
"security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2017,7 +2018,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-03T06:58:15+00:00"
|
||||
"time": "2024-03-02T07:12:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit",
|
||||
@ -2267,16 +2268,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "5.1.0",
|
||||
"version": "5.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f"
|
||||
"reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/fbf413a49e54f6b9b17e12d900ac7f6101591b7f",
|
||||
"reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
|
||||
"reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2284,7 +2285,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"symfony/process": "^4.2 || ^5"
|
||||
"symfony/process": "^6.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -2322,7 +2323,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||
"security": "https://github.com/sebastianbergmann/diff/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/5.1.0"
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/5.1.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2330,7 +2331,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-22T10:55:06+00:00"
|
||||
"time": "2024-03-02T07:15:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
@ -2398,16 +2399,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
"version": "5.1.1",
|
||||
"version": "5.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||
"reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc"
|
||||
"reference": "955288482d97c19a372d3f31006ab3f37da47adf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/64f51654862e0f5e318db7e9dcc2292c63cdbddc",
|
||||
"reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf",
|
||||
"reference": "955288482d97c19a372d3f31006ab3f37da47adf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2464,7 +2465,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
||||
"security": "https://github.com/sebastianbergmann/exporter/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/5.1.1"
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2472,20 +2473,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-24T13:22:09+00:00"
|
||||
"time": "2024-03-02T07:17:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
"version": "6.0.1",
|
||||
"version": "6.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||
"reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4"
|
||||
"reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/7ea9ead78f6d380d2a667864c132c2f7b83055e4",
|
||||
"reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
|
||||
"reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2519,14 +2520,14 @@
|
||||
}
|
||||
],
|
||||
"description": "Snapshotting of global state",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/global-state",
|
||||
"homepage": "https://www.github.com/sebastianbergmann/global-state",
|
||||
"keywords": [
|
||||
"global state"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||
"security": "https://github.com/sebastianbergmann/global-state/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/6.0.1"
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2534,7 +2535,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-19T07:19:23+00:00"
|
||||
"time": "2024-03-02T07:19:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/lines-of-code",
|
||||
@ -2880,16 +2881,16 @@
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2918,7 +2919,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/1.2.2"
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2926,7 +2927,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-20T00:12:19+00:00"
|
||||
"time": "2024-03-03T12:36:25+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
@ -59,7 +59,6 @@ use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\PacketBroadcaster;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm;
|
||||
use pocketmine\network\mcpe\raklib\RakLibInterface;
|
||||
use pocketmine\network\mcpe\StandardEntityEventBroadcaster;
|
||||
@ -1189,12 +1188,11 @@ class Server{
|
||||
bool $useQuery,
|
||||
PacketBroadcaster $packetBroadcaster,
|
||||
EntityEventBroadcaster $entityEventBroadcaster,
|
||||
PacketSerializerContext $packetSerializerContext,
|
||||
TypeConverter $typeConverter
|
||||
) : bool{
|
||||
$prettyIp = $ipV6 ? "[$ip]" : $ip;
|
||||
try{
|
||||
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter));
|
||||
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6, $packetBroadcaster, $entityEventBroadcaster, $typeConverter));
|
||||
}catch(NetworkInterfaceStartException $e){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
|
||||
$ip,
|
||||
@ -1221,15 +1219,14 @@ class Server{
|
||||
$useQuery = $this->configGroup->getConfigBool(ServerProperties::ENABLE_QUERY, true);
|
||||
|
||||
$typeConverter = TypeConverter::getInstance();
|
||||
$packetSerializerContext = new PacketSerializerContext($typeConverter->getItemTypeDictionary());
|
||||
$packetBroadcaster = new StandardPacketBroadcaster($this, $packetSerializerContext);
|
||||
$packetBroadcaster = new StandardPacketBroadcaster($this);
|
||||
$entityEventBroadcaster = new StandardEntityEventBroadcaster($packetBroadcaster, $typeConverter);
|
||||
|
||||
if(
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter) ||
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $typeConverter) ||
|
||||
(
|
||||
$this->configGroup->getConfigBool(ServerProperties::ENABLE_IPV6, true) &&
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter)
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $typeConverter)
|
||||
)
|
||||
){
|
||||
return false;
|
||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.11.1";
|
||||
public const BASE_VERSION = "5.13.1";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
@ -111,4 +111,15 @@ final class BiomeIds{
|
||||
public const CRIMSON_FOREST = 179;
|
||||
public const WARPED_FOREST = 180;
|
||||
public const BASALT_DELTAS = 181;
|
||||
public const JAGGED_PEAKS = 182;
|
||||
public const FROZEN_PEAKS = 183;
|
||||
public const SNOWY_SLOPES = 184;
|
||||
public const GROVE = 185;
|
||||
public const MEADOW = 186;
|
||||
public const LUSH_CAVES = 187;
|
||||
public const DRIPSTONE_CAVES = 188;
|
||||
public const STONY_PEAKS = 189;
|
||||
public const DEEP_DARK = 190;
|
||||
public const MANGROVE_SWAMP = 191;
|
||||
public const CHERRY_GROVE = 192;
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ final class BlockStateData{
|
||||
public const CURRENT_VERSION =
|
||||
(1 << 24) | //major
|
||||
(20 << 16) | //minor
|
||||
(60 << 8) | //patch
|
||||
(1); //revision
|
||||
(70 << 8) | //patch
|
||||
(4); //revision
|
||||
|
||||
public const TAG_NAME = "name";
|
||||
public const TAG_STATES = "states";
|
||||
|
@ -105,9 +105,7 @@ final class BlockStateNames{
|
||||
public const MOISTURIZED_AMOUNT = "moisturized_amount";
|
||||
public const MONSTER_EGG_STONE_TYPE = "monster_egg_stone_type";
|
||||
public const MULTI_FACE_DIRECTION_BITS = "multi_face_direction_bits";
|
||||
public const NEW_LEAF_TYPE = "new_leaf_type";
|
||||
public const OCCUPIED_BIT = "occupied_bit";
|
||||
public const OLD_LEAF_TYPE = "old_leaf_type";
|
||||
public const OPEN_BIT = "open_bit";
|
||||
public const ORIENTATION = "orientation";
|
||||
public const OUTPUT_LIT_BIT = "output_lit_bit";
|
||||
@ -151,6 +149,7 @@ final class BlockStateNames{
|
||||
public const UPDATE_BIT = "update_bit";
|
||||
public const UPPER_BLOCK_BIT = "upper_block_bit";
|
||||
public const UPSIDE_DOWN_BIT = "upside_down_bit";
|
||||
public const VAULT_STATE = "vault_state";
|
||||
public const VINE_DIRECTION_BITS = "vine_direction_bits";
|
||||
public const WALL_BLOCK_TYPE = "wall_block_type";
|
||||
public const WALL_CONNECTION_TYPE_EAST = "wall_connection_type_east";
|
||||
@ -160,5 +159,4 @@ final class BlockStateNames{
|
||||
public const WALL_POST_BIT = "wall_post_bit";
|
||||
public const WEEPING_VINES_AGE = "weeping_vines_age";
|
||||
public const WEIRDO_DIRECTION = "weirdo_direction";
|
||||
public const WOOD_TYPE = "wood_type";
|
||||
}
|
||||
|
@ -143,14 +143,6 @@ final class BlockStateStringValues{
|
||||
public const MONSTER_EGG_STONE_TYPE_STONE = "stone";
|
||||
public const MONSTER_EGG_STONE_TYPE_STONE_BRICK = "stone_brick";
|
||||
|
||||
public const NEW_LEAF_TYPE_ACACIA = "acacia";
|
||||
public const NEW_LEAF_TYPE_DARK_OAK = "dark_oak";
|
||||
|
||||
public const OLD_LEAF_TYPE_BIRCH = "birch";
|
||||
public const OLD_LEAF_TYPE_JUNGLE = "jungle";
|
||||
public const OLD_LEAF_TYPE_OAK = "oak";
|
||||
public const OLD_LEAF_TYPE_SPRUCE = "spruce";
|
||||
|
||||
public const ORIENTATION_DOWN_EAST = "down_east";
|
||||
public const ORIENTATION_DOWN_NORTH = "down_north";
|
||||
public const ORIENTATION_DOWN_SOUTH = "down_south";
|
||||
@ -264,6 +256,11 @@ final class BlockStateStringValues{
|
||||
public const TURTLE_EGG_COUNT_THREE_EGG = "three_egg";
|
||||
public const TURTLE_EGG_COUNT_TWO_EGG = "two_egg";
|
||||
|
||||
public const VAULT_STATE_ACTIVE = "active";
|
||||
public const VAULT_STATE_EJECTING = "ejecting";
|
||||
public const VAULT_STATE_INACTIVE = "inactive";
|
||||
public const VAULT_STATE_UNLOCKING = "unlocking";
|
||||
|
||||
public const WALL_BLOCK_TYPE_ANDESITE = "andesite";
|
||||
public const WALL_BLOCK_TYPE_BRICK = "brick";
|
||||
public const WALL_BLOCK_TYPE_COBBLESTONE = "cobblestone";
|
||||
@ -295,11 +292,4 @@ final class BlockStateStringValues{
|
||||
public const WALL_CONNECTION_TYPE_WEST_SHORT = "short";
|
||||
public const WALL_CONNECTION_TYPE_WEST_TALL = "tall";
|
||||
|
||||
public const WOOD_TYPE_ACACIA = "acacia";
|
||||
public const WOOD_TYPE_BIRCH = "birch";
|
||||
public const WOOD_TYPE_DARK_OAK = "dark_oak";
|
||||
public const WOOD_TYPE_JUNGLE = "jungle";
|
||||
public const WOOD_TYPE_OAK = "oak";
|
||||
public const WOOD_TYPE_SPRUCE = "spruce";
|
||||
|
||||
}
|
||||
|
@ -33,16 +33,20 @@ final class BlockTypeNames{
|
||||
|
||||
public const ACACIA_BUTTON = "minecraft:acacia_button";
|
||||
public const ACACIA_DOOR = "minecraft:acacia_door";
|
||||
public const ACACIA_DOUBLE_SLAB = "minecraft:acacia_double_slab";
|
||||
public const ACACIA_FENCE = "minecraft:acacia_fence";
|
||||
public const ACACIA_FENCE_GATE = "minecraft:acacia_fence_gate";
|
||||
public const ACACIA_HANGING_SIGN = "minecraft:acacia_hanging_sign";
|
||||
public const ACACIA_LEAVES = "minecraft:acacia_leaves";
|
||||
public const ACACIA_LOG = "minecraft:acacia_log";
|
||||
public const ACACIA_PLANKS = "minecraft:acacia_planks";
|
||||
public const ACACIA_PRESSURE_PLATE = "minecraft:acacia_pressure_plate";
|
||||
public const ACACIA_SLAB = "minecraft:acacia_slab";
|
||||
public const ACACIA_STAIRS = "minecraft:acacia_stairs";
|
||||
public const ACACIA_STANDING_SIGN = "minecraft:acacia_standing_sign";
|
||||
public const ACACIA_TRAPDOOR = "minecraft:acacia_trapdoor";
|
||||
public const ACACIA_WALL_SIGN = "minecraft:acacia_wall_sign";
|
||||
public const ACACIA_WOOD = "minecraft:acacia_wood";
|
||||
public const ACTIVATOR_RAIL = "minecraft:activator_rail";
|
||||
public const AIR = "minecraft:air";
|
||||
public const ALLOW = "minecraft:allow";
|
||||
@ -88,16 +92,20 @@ final class BlockTypeNames{
|
||||
public const BIG_DRIPLEAF = "minecraft:big_dripleaf";
|
||||
public const BIRCH_BUTTON = "minecraft:birch_button";
|
||||
public const BIRCH_DOOR = "minecraft:birch_door";
|
||||
public const BIRCH_DOUBLE_SLAB = "minecraft:birch_double_slab";
|
||||
public const BIRCH_FENCE = "minecraft:birch_fence";
|
||||
public const BIRCH_FENCE_GATE = "minecraft:birch_fence_gate";
|
||||
public const BIRCH_HANGING_SIGN = "minecraft:birch_hanging_sign";
|
||||
public const BIRCH_LEAVES = "minecraft:birch_leaves";
|
||||
public const BIRCH_LOG = "minecraft:birch_log";
|
||||
public const BIRCH_PLANKS = "minecraft:birch_planks";
|
||||
public const BIRCH_PRESSURE_PLATE = "minecraft:birch_pressure_plate";
|
||||
public const BIRCH_SLAB = "minecraft:birch_slab";
|
||||
public const BIRCH_STAIRS = "minecraft:birch_stairs";
|
||||
public const BIRCH_STANDING_SIGN = "minecraft:birch_standing_sign";
|
||||
public const BIRCH_TRAPDOOR = "minecraft:birch_trapdoor";
|
||||
public const BIRCH_WALL_SIGN = "minecraft:birch_wall_sign";
|
||||
public const BIRCH_WOOD = "minecraft:birch_wood";
|
||||
public const BLACK_CANDLE = "minecraft:black_candle";
|
||||
public const BLACK_CANDLE_CAKE = "minecraft:black_candle_cake";
|
||||
public const BLACK_CARPET = "minecraft:black_carpet";
|
||||
@ -266,14 +274,18 @@ final class BlockTypeNames{
|
||||
public const CYAN_WOOL = "minecraft:cyan_wool";
|
||||
public const DARK_OAK_BUTTON = "minecraft:dark_oak_button";
|
||||
public const DARK_OAK_DOOR = "minecraft:dark_oak_door";
|
||||
public const DARK_OAK_DOUBLE_SLAB = "minecraft:dark_oak_double_slab";
|
||||
public const DARK_OAK_FENCE = "minecraft:dark_oak_fence";
|
||||
public const DARK_OAK_FENCE_GATE = "minecraft:dark_oak_fence_gate";
|
||||
public const DARK_OAK_HANGING_SIGN = "minecraft:dark_oak_hanging_sign";
|
||||
public const DARK_OAK_LEAVES = "minecraft:dark_oak_leaves";
|
||||
public const DARK_OAK_LOG = "minecraft:dark_oak_log";
|
||||
public const DARK_OAK_PLANKS = "minecraft:dark_oak_planks";
|
||||
public const DARK_OAK_PRESSURE_PLATE = "minecraft:dark_oak_pressure_plate";
|
||||
public const DARK_OAK_SLAB = "minecraft:dark_oak_slab";
|
||||
public const DARK_OAK_STAIRS = "minecraft:dark_oak_stairs";
|
||||
public const DARK_OAK_TRAPDOOR = "minecraft:dark_oak_trapdoor";
|
||||
public const DARK_OAK_WOOD = "minecraft:dark_oak_wood";
|
||||
public const DARK_PRISMARINE_STAIRS = "minecraft:dark_prismarine_stairs";
|
||||
public const DARKOAK_STANDING_SIGN = "minecraft:darkoak_standing_sign";
|
||||
public const DARKOAK_WALL_SIGN = "minecraft:darkoak_wall_sign";
|
||||
@ -320,7 +332,6 @@ final class BlockTypeNames{
|
||||
public const DOUBLE_STONE_BLOCK_SLAB2 = "minecraft:double_stone_block_slab2";
|
||||
public const DOUBLE_STONE_BLOCK_SLAB3 = "minecraft:double_stone_block_slab3";
|
||||
public const DOUBLE_STONE_BLOCK_SLAB4 = "minecraft:double_stone_block_slab4";
|
||||
public const DOUBLE_WOODEN_SLAB = "minecraft:double_wooden_slab";
|
||||
public const DRAGON_EGG = "minecraft:dragon_egg";
|
||||
public const DRIED_KELP_BLOCK = "minecraft:dried_kelp_block";
|
||||
public const DRIPSTONE_BLOCK = "minecraft:dripstone_block";
|
||||
@ -490,7 +501,7 @@ final class BlockTypeNames{
|
||||
public const GOLDEN_RAIL = "minecraft:golden_rail";
|
||||
public const GRANITE = "minecraft:granite";
|
||||
public const GRANITE_STAIRS = "minecraft:granite_stairs";
|
||||
public const GRASS = "minecraft:grass";
|
||||
public const GRASS_BLOCK = "minecraft:grass_block";
|
||||
public const GRASS_PATH = "minecraft:grass_path";
|
||||
public const GRAVEL = "minecraft:gravel";
|
||||
public const GRAY_CANDLE = "minecraft:gray_candle";
|
||||
@ -572,16 +583,20 @@ final class BlockTypeNames{
|
||||
public const JUKEBOX = "minecraft:jukebox";
|
||||
public const JUNGLE_BUTTON = "minecraft:jungle_button";
|
||||
public const JUNGLE_DOOR = "minecraft:jungle_door";
|
||||
public const JUNGLE_DOUBLE_SLAB = "minecraft:jungle_double_slab";
|
||||
public const JUNGLE_FENCE = "minecraft:jungle_fence";
|
||||
public const JUNGLE_FENCE_GATE = "minecraft:jungle_fence_gate";
|
||||
public const JUNGLE_HANGING_SIGN = "minecraft:jungle_hanging_sign";
|
||||
public const JUNGLE_LEAVES = "minecraft:jungle_leaves";
|
||||
public const JUNGLE_LOG = "minecraft:jungle_log";
|
||||
public const JUNGLE_PLANKS = "minecraft:jungle_planks";
|
||||
public const JUNGLE_PRESSURE_PLATE = "minecraft:jungle_pressure_plate";
|
||||
public const JUNGLE_SLAB = "minecraft:jungle_slab";
|
||||
public const JUNGLE_STAIRS = "minecraft:jungle_stairs";
|
||||
public const JUNGLE_STANDING_SIGN = "minecraft:jungle_standing_sign";
|
||||
public const JUNGLE_TRAPDOOR = "minecraft:jungle_trapdoor";
|
||||
public const JUNGLE_WALL_SIGN = "minecraft:jungle_wall_sign";
|
||||
public const JUNGLE_WOOD = "minecraft:jungle_wood";
|
||||
public const KELP = "minecraft:kelp";
|
||||
public const LADDER = "minecraft:ladder";
|
||||
public const LANTERN = "minecraft:lantern";
|
||||
@ -589,8 +604,6 @@ final class BlockTypeNames{
|
||||
public const LAPIS_ORE = "minecraft:lapis_ore";
|
||||
public const LARGE_AMETHYST_BUD = "minecraft:large_amethyst_bud";
|
||||
public const LAVA = "minecraft:lava";
|
||||
public const LEAVES = "minecraft:leaves";
|
||||
public const LEAVES2 = "minecraft:leaves2";
|
||||
public const LECTERN = "minecraft:lectern";
|
||||
public const LEVER = "minecraft:lever";
|
||||
public const LIGHT_BLOCK = "minecraft:light_block";
|
||||
@ -698,11 +711,15 @@ final class BlockTypeNames{
|
||||
public const NETHERREACTOR = "minecraft:netherreactor";
|
||||
public const NORMAL_STONE_STAIRS = "minecraft:normal_stone_stairs";
|
||||
public const NOTEBLOCK = "minecraft:noteblock";
|
||||
public const OAK_DOUBLE_SLAB = "minecraft:oak_double_slab";
|
||||
public const OAK_FENCE = "minecraft:oak_fence";
|
||||
public const OAK_HANGING_SIGN = "minecraft:oak_hanging_sign";
|
||||
public const OAK_LEAVES = "minecraft:oak_leaves";
|
||||
public const OAK_LOG = "minecraft:oak_log";
|
||||
public const OAK_PLANKS = "minecraft:oak_planks";
|
||||
public const OAK_SLAB = "minecraft:oak_slab";
|
||||
public const OAK_STAIRS = "minecraft:oak_stairs";
|
||||
public const OAK_WOOD = "minecraft:oak_wood";
|
||||
public const OBSERVER = "minecraft:observer";
|
||||
public const OBSIDIAN = "minecraft:obsidian";
|
||||
public const OCHRE_FROGLIGHT = "minecraft:ochre_froglight";
|
||||
@ -875,16 +892,20 @@ final class BlockTypeNames{
|
||||
public const SPORE_BLOSSOM = "minecraft:spore_blossom";
|
||||
public const SPRUCE_BUTTON = "minecraft:spruce_button";
|
||||
public const SPRUCE_DOOR = "minecraft:spruce_door";
|
||||
public const SPRUCE_DOUBLE_SLAB = "minecraft:spruce_double_slab";
|
||||
public const SPRUCE_FENCE = "minecraft:spruce_fence";
|
||||
public const SPRUCE_FENCE_GATE = "minecraft:spruce_fence_gate";
|
||||
public const SPRUCE_HANGING_SIGN = "minecraft:spruce_hanging_sign";
|
||||
public const SPRUCE_LEAVES = "minecraft:spruce_leaves";
|
||||
public const SPRUCE_LOG = "minecraft:spruce_log";
|
||||
public const SPRUCE_PLANKS = "minecraft:spruce_planks";
|
||||
public const SPRUCE_PRESSURE_PLATE = "minecraft:spruce_pressure_plate";
|
||||
public const SPRUCE_SLAB = "minecraft:spruce_slab";
|
||||
public const SPRUCE_STAIRS = "minecraft:spruce_stairs";
|
||||
public const SPRUCE_STANDING_SIGN = "minecraft:spruce_standing_sign";
|
||||
public const SPRUCE_TRAPDOOR = "minecraft:spruce_trapdoor";
|
||||
public const SPRUCE_WALL_SIGN = "minecraft:spruce_wall_sign";
|
||||
public const SPRUCE_WOOD = "minecraft:spruce_wood";
|
||||
public const STANDING_BANNER = "minecraft:standing_banner";
|
||||
public const STANDING_SIGN = "minecraft:standing_sign";
|
||||
public const STICKY_PISTON = "minecraft:sticky_piston";
|
||||
@ -902,18 +923,24 @@ final class BlockTypeNames{
|
||||
public const STONECUTTER = "minecraft:stonecutter";
|
||||
public const STONECUTTER_BLOCK = "minecraft:stonecutter_block";
|
||||
public const STRIPPED_ACACIA_LOG = "minecraft:stripped_acacia_log";
|
||||
public const STRIPPED_ACACIA_WOOD = "minecraft:stripped_acacia_wood";
|
||||
public const STRIPPED_BAMBOO_BLOCK = "minecraft:stripped_bamboo_block";
|
||||
public const STRIPPED_BIRCH_LOG = "minecraft:stripped_birch_log";
|
||||
public const STRIPPED_BIRCH_WOOD = "minecraft:stripped_birch_wood";
|
||||
public const STRIPPED_CHERRY_LOG = "minecraft:stripped_cherry_log";
|
||||
public const STRIPPED_CHERRY_WOOD = "minecraft:stripped_cherry_wood";
|
||||
public const STRIPPED_CRIMSON_HYPHAE = "minecraft:stripped_crimson_hyphae";
|
||||
public const STRIPPED_CRIMSON_STEM = "minecraft:stripped_crimson_stem";
|
||||
public const STRIPPED_DARK_OAK_LOG = "minecraft:stripped_dark_oak_log";
|
||||
public const STRIPPED_DARK_OAK_WOOD = "minecraft:stripped_dark_oak_wood";
|
||||
public const STRIPPED_JUNGLE_LOG = "minecraft:stripped_jungle_log";
|
||||
public const STRIPPED_JUNGLE_WOOD = "minecraft:stripped_jungle_wood";
|
||||
public const STRIPPED_MANGROVE_LOG = "minecraft:stripped_mangrove_log";
|
||||
public const STRIPPED_MANGROVE_WOOD = "minecraft:stripped_mangrove_wood";
|
||||
public const STRIPPED_OAK_LOG = "minecraft:stripped_oak_log";
|
||||
public const STRIPPED_OAK_WOOD = "minecraft:stripped_oak_wood";
|
||||
public const STRIPPED_SPRUCE_LOG = "minecraft:stripped_spruce_log";
|
||||
public const STRIPPED_SPRUCE_WOOD = "minecraft:stripped_spruce_wood";
|
||||
public const STRIPPED_WARPED_HYPHAE = "minecraft:stripped_warped_hyphae";
|
||||
public const STRIPPED_WARPED_STEM = "minecraft:stripped_warped_stem";
|
||||
public const STRUCTURE_BLOCK = "minecraft:structure_block";
|
||||
@ -952,6 +979,7 @@ final class BlockTypeNames{
|
||||
public const UNLIT_REDSTONE_TORCH = "minecraft:unlit_redstone_torch";
|
||||
public const UNPOWERED_COMPARATOR = "minecraft:unpowered_comparator";
|
||||
public const UNPOWERED_REPEATER = "minecraft:unpowered_repeater";
|
||||
public const VAULT = "minecraft:vault";
|
||||
public const VERDANT_FROGLIGHT = "minecraft:verdant_froglight";
|
||||
public const VINE = "minecraft:vine";
|
||||
public const WALL_BANNER = "minecraft:wall_banner";
|
||||
@ -1042,11 +1070,9 @@ final class BlockTypeNames{
|
||||
public const WHITE_TERRACOTTA = "minecraft:white_terracotta";
|
||||
public const WHITE_WOOL = "minecraft:white_wool";
|
||||
public const WITHER_ROSE = "minecraft:wither_rose";
|
||||
public const WOOD = "minecraft:wood";
|
||||
public const WOODEN_BUTTON = "minecraft:wooden_button";
|
||||
public const WOODEN_DOOR = "minecraft:wooden_door";
|
||||
public const WOODEN_PRESSURE_PLATE = "minecraft:wooden_pressure_plate";
|
||||
public const WOODEN_SLAB = "minecraft:wooden_slab";
|
||||
public const YELLOW_CANDLE = "minecraft:yellow_candle";
|
||||
public const YELLOW_CANDLE_CAKE = "minecraft:yellow_candle_cake";
|
||||
public const YELLOW_CARPET = "minecraft:yellow_carpet";
|
||||
|
@ -202,7 +202,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->registerFlatCoralSerializers();
|
||||
$this->registerCauldronSerializers();
|
||||
$this->registerFlatWoodBlockSerializers();
|
||||
$this->registerLegacyWoodBlockSerializers();
|
||||
$this->registerLeavesSerializers();
|
||||
$this->registerSimpleSerializers();
|
||||
$this->registerSerializers();
|
||||
@ -557,9 +556,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::ACACIA_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::ACACIA_TRAPDOOR)));
|
||||
$this->map(Blocks::ACACIA_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::ACACIA_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::ACACIA_LOG(), Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG);
|
||||
$this->mapLog(Blocks::ACACIA_WOOD(), Ids::ACACIA_WOOD, Ids::STRIPPED_ACACIA_WOOD);
|
||||
$this->mapSimple(Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE);
|
||||
$this->mapSimple(Blocks::ACACIA_PLANKS(), Ids::ACACIA_PLANKS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
$this->mapSlab(Blocks::ACACIA_SLAB(), Ids::ACACIA_SLAB, Ids::ACACIA_DOUBLE_SLAB);
|
||||
|
||||
$this->map(Blocks::BIRCH_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::BIRCH_BUTTON)));
|
||||
$this->map(Blocks::BIRCH_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::BIRCH_DOOR)));
|
||||
@ -569,10 +569,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::BIRCH_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::BIRCH_TRAPDOOR)));
|
||||
$this->map(Blocks::BIRCH_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::BIRCH_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::BIRCH_LOG(), Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG);
|
||||
$this->mapLog(Blocks::BIRCH_WOOD(), Ids::BIRCH_WOOD, Ids::STRIPPED_BIRCH_WOOD);
|
||||
$this->mapSimple(Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE);
|
||||
$this->mapSimple(Blocks::BIRCH_PLANKS(), Ids::BIRCH_PLANKS);
|
||||
$this->mapSlab(Blocks::BIRCH_SLAB(), Ids::BIRCH_SLAB, Ids::BIRCH_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Blocks::CHERRY_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::CHERRY_BUTTON)));
|
||||
$this->map(Blocks::CHERRY_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::CHERRY_DOOR)));
|
||||
@ -620,10 +621,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::DARK_OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::DARK_OAK_TRAPDOOR)));
|
||||
$this->map(Blocks::DARK_OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::DARKOAK_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::DARK_OAK_LOG(), Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG);
|
||||
$this->mapLog(Blocks::DARK_OAK_WOOD(), Ids::DARK_OAK_WOOD, Ids::STRIPPED_DARK_OAK_WOOD);
|
||||
$this->mapSimple(Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE);
|
||||
$this->mapSimple(Blocks::DARK_OAK_PLANKS(), Ids::DARK_OAK_PLANKS);
|
||||
$this->mapSlab(Blocks::DARK_OAK_SLAB(), Ids::DARK_OAK_SLAB, Ids::DARK_OAK_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Blocks::JUNGLE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::JUNGLE_BUTTON)));
|
||||
$this->map(Blocks::JUNGLE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::JUNGLE_DOOR)));
|
||||
@ -633,10 +635,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::JUNGLE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::JUNGLE_TRAPDOOR)));
|
||||
$this->map(Blocks::JUNGLE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::JUNGLE_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::JUNGLE_LOG(), Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG);
|
||||
$this->mapLog(Blocks::JUNGLE_WOOD(), Ids::JUNGLE_WOOD, Ids::STRIPPED_JUNGLE_WOOD);
|
||||
$this->mapSimple(Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE);
|
||||
$this->mapSimple(Blocks::JUNGLE_PLANKS(), Ids::JUNGLE_PLANKS);
|
||||
$this->mapSlab(Blocks::JUNGLE_SLAB(), Ids::JUNGLE_SLAB, Ids::JUNGLE_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Blocks::MANGROVE_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::MANGROVE_BUTTON)));
|
||||
$this->map(Blocks::MANGROVE_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::MANGROVE_DOOR)));
|
||||
@ -670,10 +673,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::TRAPDOOR)));
|
||||
$this->map(Blocks::OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::WALL_SIGN)));
|
||||
$this->mapLog(Blocks::OAK_LOG(), Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG);
|
||||
$this->mapLog(Blocks::OAK_WOOD(), Ids::OAK_WOOD, Ids::STRIPPED_OAK_WOOD);
|
||||
$this->mapSimple(Blocks::OAK_FENCE(), Ids::OAK_FENCE);
|
||||
$this->mapSimple(Blocks::OAK_PLANKS(), Ids::OAK_PLANKS);
|
||||
$this->mapSlab(Blocks::OAK_SLAB(), Ids::OAK_SLAB, Ids::OAK_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::OAK_STAIRS(), Ids::OAK_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Blocks::SPRUCE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::SPRUCE_BUTTON)));
|
||||
$this->map(Blocks::SPRUCE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::SPRUCE_DOOR)));
|
||||
@ -683,8 +687,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::SPRUCE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::SPRUCE_TRAPDOOR)));
|
||||
$this->map(Blocks::SPRUCE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::SPRUCE_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::SPRUCE_LOG(), Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG);
|
||||
$this->mapLog(Blocks::SPRUCE_WOOD(), Ids::SPRUCE_WOOD, Ids::STRIPPED_SPRUCE_WOOD);
|
||||
$this->mapSimple(Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE);
|
||||
$this->mapSimple(Blocks::SPRUCE_PLANKS(), Ids::SPRUCE_PLANKS);
|
||||
$this->mapSlab(Blocks::SPRUCE_SLAB(), Ids::SPRUCE_SLAB, Ids::SPRUCE_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
@ -703,30 +709,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapStairs(Blocks::WARPED_STAIRS(), Ids::WARPED_STAIRS);
|
||||
}
|
||||
|
||||
private function registerLegacyWoodBlockSerializers() : void{
|
||||
foreach([
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_SLAB(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_SLAB(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_SLAB(),
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_SLAB(),
|
||||
] as $woodType => $block){
|
||||
$this->map($block, fn(Slab $block) => Helper::encodeWoodenSlab($block, $woodType));
|
||||
}
|
||||
|
||||
foreach([
|
||||
Blocks::ACACIA_WOOD(),
|
||||
Blocks::BIRCH_WOOD(),
|
||||
Blocks::DARK_OAK_WOOD(),
|
||||
Blocks::JUNGLE_WOOD(),
|
||||
Blocks::OAK_WOOD(),
|
||||
Blocks::SPRUCE_WOOD(),
|
||||
] as $block){
|
||||
$this->map($block, fn(Wood $block) => Helper::encodeAllSidedLog($block));
|
||||
}
|
||||
}
|
||||
|
||||
private function registerLeavesSerializers() : void{
|
||||
//flattened IDs
|
||||
$this->map(Blocks::AZALEA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::AZALEA_LEAVES)));
|
||||
@ -735,12 +717,12 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::MANGROVE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::MANGROVE_LEAVES)));
|
||||
|
||||
//legacy mess
|
||||
$this->map(Blocks::ACACIA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves2($block, StringValues::NEW_LEAF_TYPE_ACACIA));
|
||||
$this->map(Blocks::BIRCH_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_BIRCH));
|
||||
$this->map(Blocks::DARK_OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves2($block, StringValues::NEW_LEAF_TYPE_DARK_OAK));
|
||||
$this->map(Blocks::JUNGLE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_JUNGLE));
|
||||
$this->map(Blocks::OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_OAK));
|
||||
$this->map(Blocks::SPRUCE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_SPRUCE));
|
||||
$this->map(Blocks::ACACIA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::ACACIA_LEAVES)));
|
||||
$this->map(Blocks::BIRCH_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::BIRCH_LEAVES)));
|
||||
$this->map(Blocks::DARK_OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::DARK_OAK_LEAVES)));
|
||||
$this->map(Blocks::JUNGLE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::JUNGLE_LEAVES)));
|
||||
$this->map(Blocks::OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::OAK_LEAVES)));
|
||||
$this->map(Blocks::SPRUCE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::SPRUCE_LEAVES)));
|
||||
}
|
||||
|
||||
private function registerSimpleSerializers() : void{
|
||||
@ -926,7 +908,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapSimple(Blocks::GOLD(), Ids::GOLD_BLOCK);
|
||||
$this->mapSimple(Blocks::GOLD_ORE(), Ids::GOLD_ORE);
|
||||
$this->mapSimple(Blocks::GRANITE(), Ids::GRANITE);
|
||||
$this->mapSimple(Blocks::GRASS(), Ids::GRASS);
|
||||
$this->mapSimple(Blocks::GRASS(), Ids::GRASS_BLOCK);
|
||||
$this->mapSimple(Blocks::GRASS_PATH(), Ids::GRASS_PATH);
|
||||
$this->mapSimple(Blocks::GRAVEL(), Ids::GRAVEL);
|
||||
$this->mapSimple(Blocks::HANGING_ROOTS(), Ids::HANGING_ROOTS);
|
||||
|
@ -362,18 +362,4 @@ final class BlockStateDeserializerHelper{
|
||||
default => throw $in->badValueException(BlockStateNames::STONE_SLAB_TYPE_4, $type),
|
||||
};
|
||||
}
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public static function mapWoodenSlabType(BlockStateReader $in) : Slab{
|
||||
// * wood_type (StringTag) = acacia, birch, dark_oak, jungle, oak, spruce
|
||||
return match($type = $in->readString(BlockStateNames::WOOD_TYPE)){
|
||||
StringValues::WOOD_TYPE_ACACIA => VanillaBlocks::ACACIA_SLAB(),
|
||||
StringValues::WOOD_TYPE_BIRCH => VanillaBlocks::BIRCH_SLAB(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => VanillaBlocks::DARK_OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => VanillaBlocks::JUNGLE_SLAB(),
|
||||
StringValues::WOOD_TYPE_OAK => VanillaBlocks::OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => VanillaBlocks::SPRUCE_SLAB(),
|
||||
default => throw $in->badValueException(BlockStateNames::WOOD_TYPE, $type),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -56,14 +56,6 @@ use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
|
||||
use pocketmine\math\Facing;
|
||||
|
||||
final class BlockStateSerializerHelper{
|
||||
|
||||
public static function encodeAllSidedLog(Wood $block) : Writer{
|
||||
return Writer::create(Ids::WOOD)
|
||||
->writeBool(BlockStateNames::STRIPPED_BIT, $block->isStripped())
|
||||
->writePillarAxis($block->getAxis())
|
||||
->writeLegacyWoodType($block->getWoodType());
|
||||
}
|
||||
|
||||
public static function encodeButton(Button $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeFacingDirection($block->getFacing())
|
||||
@ -151,16 +143,6 @@ final class BlockStateSerializerHelper{
|
||||
->writeBool(BlockStateNames::UPDATE_BIT, $block->isCheckDecay());
|
||||
}
|
||||
|
||||
public static function encodeLeaves1(Leaves $block, string $type) : Writer{
|
||||
return self::encodeLeaves($block, Writer::create(Ids::LEAVES)
|
||||
->writeString(BlockStateNames::OLD_LEAF_TYPE, $type));
|
||||
}
|
||||
|
||||
public static function encodeLeaves2(Leaves $block, string $type) : Writer{
|
||||
return self::encodeLeaves($block, Writer::create(Ids::LEAVES2)
|
||||
->writeString(BlockStateNames::NEW_LEAF_TYPE, $type));
|
||||
}
|
||||
|
||||
public static function encodeLiquid(Liquid $block, string $stillId, string $flowingId) : Writer{
|
||||
return Writer::create($block->isStill() ? $stillId : $flowingId)
|
||||
->writeInt(BlockStateNames::LIQUID_DEPTH, $block->getDecay() | ($block->isFalling() ? 0x8 : 0));
|
||||
@ -279,9 +261,4 @@ final class BlockStateSerializerHelper{
|
||||
return $out
|
||||
->writeHorizontalFacing($block->getFacing());
|
||||
}
|
||||
|
||||
public static function encodeWoodenSlab(Slab $block, string $typeValue) : Writer{
|
||||
return self::encodeSlab($block, Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB)
|
||||
->writeString(BlockStateNames::WOOD_TYPE, $typeValue);
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->registerFlatCoralDeserializers();
|
||||
$this->registerCauldronDeserializers();
|
||||
$this->registerFlatWoodBlockDeserializers();
|
||||
$this->registerLegacyWoodBlockDeserializers();
|
||||
$this->registerLeavesDeserializers();
|
||||
$this->registerSimpleDeserializers();
|
||||
$this->registerDeserializers();
|
||||
@ -468,10 +467,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::ACACIA_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::ACACIA_TRAPDOOR(), $in));
|
||||
$this->map(Ids::ACACIA_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::ACACIA_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG, fn() => Blocks::ACACIA_LOG());
|
||||
$this->mapLog(Ids::ACACIA_WOOD, Ids::STRIPPED_ACACIA_WOOD, fn() => Blocks::ACACIA_WOOD());
|
||||
$this->mapSimple(Ids::ACACIA_FENCE, fn() => Blocks::ACACIA_FENCE());
|
||||
$this->mapSimple(Ids::ACACIA_PLANKS, fn() => Blocks::ACACIA_PLANKS());
|
||||
$this->mapSlab(Ids::ACACIA_SLAB, Ids::ACACIA_DOUBLE_SLAB, fn() => Blocks::ACACIA_SLAB());
|
||||
$this->mapStairs(Ids::ACACIA_STAIRS, fn() => Blocks::ACACIA_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::BIRCH_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::BIRCH_BUTTON(), $in));
|
||||
$this->map(Ids::BIRCH_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::BIRCH_DOOR(), $in));
|
||||
@ -481,10 +481,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::BIRCH_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::BIRCH_TRAPDOOR(), $in));
|
||||
$this->map(Ids::BIRCH_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::BIRCH_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG, fn() => Blocks::BIRCH_LOG());
|
||||
$this->mapLog(Ids::BIRCH_WOOD, Ids::STRIPPED_BIRCH_WOOD, fn() => Blocks::BIRCH_WOOD());
|
||||
$this->mapSimple(Ids::BIRCH_FENCE, fn() => Blocks::BIRCH_FENCE());
|
||||
$this->mapSimple(Ids::BIRCH_PLANKS, fn() => Blocks::BIRCH_PLANKS());
|
||||
$this->mapSlab(Ids::BIRCH_SLAB, Ids::BIRCH_DOUBLE_SLAB, fn() => Blocks::BIRCH_SLAB());
|
||||
$this->mapStairs(Ids::BIRCH_STAIRS, fn() => Blocks::BIRCH_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::CHERRY_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::CHERRY_BUTTON(), $in));
|
||||
$this->map(Ids::CHERRY_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::CHERRY_DOOR(), $in));
|
||||
@ -526,10 +527,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::DARK_OAK_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::DARK_OAK_PRESSURE_PLATE(), $in));
|
||||
$this->map(Ids::DARK_OAK_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::DARK_OAK_TRAPDOOR(), $in));
|
||||
$this->mapLog(Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG, fn() => Blocks::DARK_OAK_LOG());
|
||||
$this->mapLog(Ids::DARK_OAK_WOOD, Ids::STRIPPED_DARK_OAK_WOOD, fn() => Blocks::DARK_OAK_WOOD());
|
||||
$this->mapSimple(Ids::DARK_OAK_FENCE, fn() => Blocks::DARK_OAK_FENCE());
|
||||
$this->mapSimple(Ids::DARK_OAK_PLANKS, fn() => Blocks::DARK_OAK_PLANKS());
|
||||
$this->mapSlab(Ids::DARK_OAK_SLAB, Ids::DARK_OAK_DOUBLE_SLAB, fn() => Blocks::DARK_OAK_SLAB());
|
||||
$this->mapStairs(Ids::DARK_OAK_STAIRS, fn() => Blocks::DARK_OAK_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::JUNGLE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::JUNGLE_BUTTON(), $in));
|
||||
$this->map(Ids::JUNGLE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::JUNGLE_DOOR(), $in));
|
||||
@ -539,10 +541,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::JUNGLE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::JUNGLE_TRAPDOOR(), $in));
|
||||
$this->map(Ids::JUNGLE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::JUNGLE_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG, fn() => Blocks::JUNGLE_LOG());
|
||||
$this->mapLog(Ids::JUNGLE_WOOD, Ids::STRIPPED_JUNGLE_WOOD, fn() => Blocks::JUNGLE_WOOD());
|
||||
$this->mapSimple(Ids::JUNGLE_FENCE, fn() => Blocks::JUNGLE_FENCE());
|
||||
$this->mapSimple(Ids::JUNGLE_PLANKS, fn() => Blocks::JUNGLE_PLANKS());
|
||||
$this->mapSlab(Ids::JUNGLE_SLAB, Ids::JUNGLE_DOUBLE_SLAB, fn() => Blocks::JUNGLE_SLAB());
|
||||
$this->mapStairs(Ids::JUNGLE_STAIRS, fn() => Blocks::JUNGLE_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::MANGROVE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::MANGROVE_BUTTON(), $in));
|
||||
$this->map(Ids::MANGROVE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::MANGROVE_DOOR(), $in));
|
||||
@ -571,10 +574,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::OAK_TRAPDOOR(), $in));
|
||||
$this->map(Ids::WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::OAK_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG, fn() => Blocks::OAK_LOG());
|
||||
$this->mapLog(Ids::OAK_WOOD, Ids::STRIPPED_OAK_WOOD, fn() => Blocks::OAK_WOOD());
|
||||
$this->mapSimple(Ids::OAK_FENCE, fn() => Blocks::OAK_FENCE());
|
||||
$this->mapSimple(Ids::OAK_PLANKS, fn() => Blocks::OAK_PLANKS());
|
||||
$this->mapSlab(Ids::OAK_SLAB, Ids::OAK_DOUBLE_SLAB, fn() => Blocks::OAK_SLAB());
|
||||
$this->mapStairs(Ids::OAK_STAIRS, fn() => Blocks::OAK_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::SPRUCE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::SPRUCE_BUTTON(), $in));
|
||||
$this->map(Ids::SPRUCE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::SPRUCE_DOOR(), $in));
|
||||
@ -584,10 +588,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::SPRUCE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::SPRUCE_TRAPDOOR(), $in));
|
||||
$this->map(Ids::SPRUCE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::SPRUCE_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG, fn() => Blocks::SPRUCE_LOG());
|
||||
$this->mapLog(Ids::SPRUCE_WOOD, Ids::STRIPPED_SPRUCE_WOOD, fn() => Blocks::SPRUCE_WOOD());
|
||||
$this->mapSimple(Ids::SPRUCE_FENCE, fn() => Blocks::SPRUCE_FENCE());
|
||||
$this->mapSimple(Ids::SPRUCE_PLANKS, fn() => Blocks::SPRUCE_PLANKS());
|
||||
$this->mapSlab(Ids::SPRUCE_SLAB, Ids::SPRUCE_DOUBLE_SLAB, fn() => Blocks::SPRUCE_SLAB());
|
||||
$this->mapStairs(Ids::SPRUCE_STAIRS, fn() => Blocks::SPRUCE_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::WARPED_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::WARPED_BUTTON(), $in));
|
||||
$this->map(Ids::WARPED_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::WARPED_DOOR(), $in));
|
||||
@ -604,40 +609,17 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapStairs(Ids::WARPED_STAIRS, fn() => Blocks::WARPED_STAIRS());
|
||||
}
|
||||
|
||||
private function registerLegacyWoodBlockDeserializers() : void{
|
||||
$this->mapSlab(Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB, fn(Reader $in) => Helper::mapWoodenSlabType($in));
|
||||
|
||||
$this->map(Ids::WOOD, fn(Reader $in) : Block => Helper::decodeLog(match($woodType = $in->readString(StateNames::WOOD_TYPE)){
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_WOOD(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_WOOD(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_WOOD(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_WOOD(),
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_WOOD(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_WOOD(),
|
||||
default => throw $in->badValueException(StateNames::WOOD_TYPE, $woodType),
|
||||
}, $in->readBool(StateNames::STRIPPED_BIT), $in));
|
||||
}
|
||||
|
||||
private function registerLeavesDeserializers() : void{
|
||||
//flattened IDs
|
||||
$this->map(Ids::ACACIA_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::ACACIA_LEAVES(), $in));
|
||||
$this->map(Ids::AZALEA_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::AZALEA_LEAVES(), $in));
|
||||
$this->map(Ids::AZALEA_LEAVES_FLOWERED, fn(Reader $in) => Helper::decodeLeaves(Blocks::FLOWERING_AZALEA_LEAVES(), $in));
|
||||
$this->map(Ids::BIRCH_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::BIRCH_LEAVES(), $in));
|
||||
$this->map(Ids::CHERRY_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::CHERRY_LEAVES(), $in));
|
||||
$this->map(Ids::DARK_OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::DARK_OAK_LEAVES(), $in));
|
||||
$this->map(Ids::JUNGLE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::JUNGLE_LEAVES(), $in));
|
||||
$this->map(Ids::MANGROVE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::MANGROVE_LEAVES(), $in));
|
||||
|
||||
//legacy mess
|
||||
$this->map(Ids::LEAVES, fn(Reader $in) => Helper::decodeLeaves(match($type = $in->readString(StateNames::OLD_LEAF_TYPE)){
|
||||
StringValues::OLD_LEAF_TYPE_BIRCH => Blocks::BIRCH_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_JUNGLE => Blocks::JUNGLE_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_OAK => Blocks::OAK_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_SPRUCE => Blocks::SPRUCE_LEAVES(),
|
||||
default => throw $in->badValueException(StateNames::OLD_LEAF_TYPE, $type),
|
||||
}, $in));
|
||||
$this->map(Ids::LEAVES2, fn(Reader $in) => Helper::decodeLeaves(match($type = $in->readString(StateNames::NEW_LEAF_TYPE)){
|
||||
StringValues::NEW_LEAF_TYPE_ACACIA => Blocks::ACACIA_LEAVES(),
|
||||
StringValues::NEW_LEAF_TYPE_DARK_OAK => Blocks::DARK_OAK_LEAVES(),
|
||||
default => throw $in->badValueException(StateNames::NEW_LEAF_TYPE, $type),
|
||||
}, $in));
|
||||
$this->map(Ids::OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::OAK_LEAVES(), $in));
|
||||
$this->map(Ids::SPRUCE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::SPRUCE_LEAVES(), $in));
|
||||
}
|
||||
|
||||
private function registerSimpleDeserializers() : void{
|
||||
@ -821,7 +803,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapSimple(Ids::GOLD_BLOCK, fn() => Blocks::GOLD());
|
||||
$this->mapSimple(Ids::GOLD_ORE, fn() => Blocks::GOLD_ORE());
|
||||
$this->mapSimple(Ids::GRANITE, fn() => Blocks::GRANITE());
|
||||
$this->mapSimple(Ids::GRASS, fn() => Blocks::GRASS());
|
||||
$this->mapSimple(Ids::GRASS_BLOCK, fn() => Blocks::GRASS());
|
||||
$this->mapSimple(Ids::GRASS_PATH, fn() => Blocks::GRASS_PATH());
|
||||
$this->mapSimple(Ids::GRAVEL, fn() => Blocks::GRAVEL());
|
||||
$this->mapSimple(Ids::HANGING_ROOTS, fn() => Blocks::HANGING_ROOTS());
|
||||
|
@ -27,7 +27,6 @@ use pocketmine\block\utils\BellAttachmentType;
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\SlabType;
|
||||
use pocketmine\block\utils\WallConnectionType;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
|
||||
use pocketmine\data\bedrock\block\BlockStateData;
|
||||
use pocketmine\data\bedrock\block\BlockStateNames;
|
||||
@ -257,20 +256,6 @@ final class BlockStateWriter{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function writeLegacyWoodType(WoodType $treeType) : self{
|
||||
$this->writeString(BlockStateNames::WOOD_TYPE, match($treeType){
|
||||
WoodType::OAK => StringValues::WOOD_TYPE_OAK,
|
||||
WoodType::SPRUCE => StringValues::WOOD_TYPE_SPRUCE,
|
||||
WoodType::BIRCH => StringValues::WOOD_TYPE_BIRCH,
|
||||
WoodType::JUNGLE => StringValues::WOOD_TYPE_JUNGLE,
|
||||
WoodType::ACACIA => StringValues::WOOD_TYPE_ACACIA,
|
||||
WoodType::DARK_OAK => StringValues::WOOD_TYPE_DARK_OAK,
|
||||
default => throw new BlockStateSerializeException("Invalid legacy wood type " . $treeType->name)
|
||||
});
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function writeCoralType(CoralType $coralType) : self{
|
||||
$this->writeString(BlockStateNames::CORAL_COLOR, match($coralType){
|
||||
|
@ -64,20 +64,24 @@ final class BlockStateUpgradeSchema{
|
||||
*/
|
||||
public array $remappedStates = [];
|
||||
|
||||
public readonly int $versionId;
|
||||
|
||||
public function __construct(
|
||||
public int $maxVersionMajor,
|
||||
public int $maxVersionMinor,
|
||||
public int $maxVersionPatch,
|
||||
public int $maxVersionRevision,
|
||||
public readonly int $maxVersionMajor,
|
||||
public readonly int $maxVersionMinor,
|
||||
public readonly int $maxVersionPatch,
|
||||
public readonly int $maxVersionRevision,
|
||||
private int $schemaId
|
||||
){}
|
||||
){
|
||||
$this->versionId = ($this->maxVersionMajor << 24) | ($this->maxVersionMinor << 16) | ($this->maxVersionPatch << 8) | $this->maxVersionRevision;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This is defined by Mojang, and therefore cannot be relied on. Use getSchemaId() instead for
|
||||
* internal version management.
|
||||
*/
|
||||
public function getVersionId() : int{
|
||||
return ($this->maxVersionMajor << 24) | ($this->maxVersionMinor << 16) | ($this->maxVersionPatch << 8) | $this->maxVersionRevision;
|
||||
return $this->versionId;
|
||||
}
|
||||
|
||||
public function getSchemaId() : int{ return $this->schemaId; }
|
||||
|
@ -389,6 +389,9 @@ final class BlockStateUpgradeSchemaUtils{
|
||||
}
|
||||
|
||||
$jsonMapper = new \JsonMapper();
|
||||
$jsonMapper->bExceptionOnMissingData = true;
|
||||
$jsonMapper->bExceptionOnUndefinedProperty = true;
|
||||
$jsonMapper->bStrictObjectTypeChecking = true;
|
||||
try{
|
||||
$model = $jsonMapper->map($json, new BlockStateUpgradeSchemaModel());
|
||||
}catch(\JsonMapper_Exception $e){
|
||||
|
@ -35,9 +35,14 @@ use function sprintf;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
final class BlockStateUpgrader{
|
||||
/** @var BlockStateUpgradeSchema[] */
|
||||
/**
|
||||
* @var BlockStateUpgradeSchema[][] versionId => [schemaId => schema]
|
||||
* @phpstan-var array<int, array<int, BlockStateUpgradeSchema>>
|
||||
*/
|
||||
private array $upgradeSchemas = [];
|
||||
|
||||
private int $outputVersion = 0;
|
||||
|
||||
/**
|
||||
* @param BlockStateUpgradeSchema[] $upgradeSchemas
|
||||
* @phpstan-param array<int, BlockStateUpgradeSchema> $upgradeSchemas
|
||||
@ -50,27 +55,76 @@ final class BlockStateUpgrader{
|
||||
|
||||
public function addSchema(BlockStateUpgradeSchema $schema) : void{
|
||||
$schemaId = $schema->getSchemaId();
|
||||
if(isset($this->upgradeSchemas[$schemaId])){
|
||||
throw new \InvalidArgumentException("Cannot add two schemas with the same schema ID");
|
||||
$versionId = $schema->getVersionId();
|
||||
if(isset($this->upgradeSchemas[$versionId][$schemaId])){
|
||||
throw new \InvalidArgumentException("Cannot add two schemas with the same schema ID and version ID");
|
||||
}
|
||||
$this->upgradeSchemas[$schemaId] = $schema;
|
||||
|
||||
//schema ID tells us the order when multiple schemas use the same version ID
|
||||
$this->upgradeSchemas[$versionId][$schemaId] = $schema;
|
||||
|
||||
ksort($this->upgradeSchemas, SORT_NUMERIC);
|
||||
ksort($this->upgradeSchemas[$versionId], SORT_NUMERIC);
|
||||
|
||||
$this->outputVersion = max($this->outputVersion, $schema->getVersionId());
|
||||
}
|
||||
|
||||
public function upgrade(BlockStateData $blockStateData) : BlockStateData{
|
||||
$version = $blockStateData->getVersion();
|
||||
$highestVersion = $version;
|
||||
foreach($this->upgradeSchemas as $schema){
|
||||
$resultVersion = $schema->getVersionId();
|
||||
$highestVersion = max($highestVersion, $resultVersion);
|
||||
if($version > $resultVersion){
|
||||
//even if this is actually the same version, we have to apply it anyway because mojang are dumb and
|
||||
//didn't always bump the blockstate version when changing it :(
|
||||
foreach($this->upgradeSchemas as $resultVersion => $schemaList){
|
||||
/*
|
||||
* Sometimes Mojang made changes without bumping the version ID.
|
||||
* A notable example is 0131_1.18.20.27_beta_to_1.18.30.json, which renamed a bunch of blockIDs.
|
||||
* When this happens, all the schemas must be applied even if the version is the same, because the input
|
||||
* version doesn't tell us which of the schemas have already been applied.
|
||||
* If there's only one schema for a version (the norm), we can safely assume it's already been applied if
|
||||
* the version is the same, and skip over it.
|
||||
*/
|
||||
if($version > $resultVersion || (count($schemaList) === 1 && $version === $resultVersion)){
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($schemaList as $schema){
|
||||
$blockStateData = $this->applySchema($schema, $blockStateData);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->outputVersion > $version){
|
||||
//always update the version number of the blockstate, even if it didn't change - this is needed for
|
||||
//external tools
|
||||
$blockStateData = new BlockStateData($blockStateData->getName(), $blockStateData->getStates(), $this->outputVersion);
|
||||
}
|
||||
return $blockStateData;
|
||||
}
|
||||
|
||||
private function applySchema(BlockStateUpgradeSchema $schema, BlockStateData $blockStateData) : BlockStateData{
|
||||
$newStateData = $this->applyStateRemapped($schema, $blockStateData);
|
||||
if($newStateData !== null){
|
||||
return $newStateData;
|
||||
}
|
||||
|
||||
$oldName = $blockStateData->getName();
|
||||
$newName = $schema->renamedIds[$oldName] ?? null;
|
||||
|
||||
$stateChanges = 0;
|
||||
$states = $blockStateData->getStates();
|
||||
|
||||
$states = $this->applyPropertyAdded($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyRemoved($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyRenamedOrValueChanged($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyValueChanged($schema, $oldName, $states, $stateChanges);
|
||||
|
||||
if($newName !== null || $stateChanges > 0){
|
||||
return new BlockStateData($newName ?? $oldName, $states, $schema->getVersionId());
|
||||
}
|
||||
|
||||
return $blockStateData;
|
||||
}
|
||||
|
||||
private function applyStateRemapped(BlockStateUpgradeSchema $schema, BlockStateData $blockStateData) : ?BlockStateData{
|
||||
$oldName = $blockStateData->getName();
|
||||
$oldState = $blockStateData->getStates();
|
||||
|
||||
if(isset($schema->remappedStates[$oldName])){
|
||||
foreach($schema->remappedStates[$oldName] as $remap){
|
||||
if(count($remap->oldState) > count($oldState)){
|
||||
@ -103,32 +157,11 @@ final class BlockStateUpgrader{
|
||||
}
|
||||
}
|
||||
|
||||
$blockStateData = new BlockStateData($newName, $newState, $resultVersion);
|
||||
continue 2; //try next schema
|
||||
}
|
||||
}
|
||||
$newName = $schema->renamedIds[$oldName] ?? null;
|
||||
|
||||
$stateChanges = 0;
|
||||
$states = $blockStateData->getStates();
|
||||
|
||||
$states = $this->applyPropertyAdded($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyRemoved($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyRenamedOrValueChanged($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyValueChanged($schema, $oldName, $states, $stateChanges);
|
||||
|
||||
if($newName !== null || $stateChanges > 0){
|
||||
$blockStateData = new BlockStateData($newName ?? $oldName, $states, $resultVersion);
|
||||
//don't break out; we may need to further upgrade the state
|
||||
return new BlockStateData($newName, $newState, $schema->getVersionId());
|
||||
}
|
||||
}
|
||||
|
||||
if($highestVersion > $version){
|
||||
//always update the version number of the blockstate, even if it didn't change - this is needed for
|
||||
//external tools
|
||||
$blockStateData = new BlockStateData($blockStateData->getName(), $blockStateData->getStates(), $highestVersion);
|
||||
}
|
||||
return $blockStateData;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,6 +305,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::MUSIC_DISC_WAIT, Items::RECORD_WAIT());
|
||||
$this->map1to1Item(Ids::MUSIC_DISC_WARD, Items::RECORD_WARD());
|
||||
$this->map1to1Item(Ids::MUTTON, Items::RAW_MUTTON());
|
||||
$this->map1to1Item(Ids::NAME_TAG, Items::NAME_TAG());
|
||||
$this->map1to1Item(Ids::NAUTILUS_SHELL, Items::NAUTILUS_SHELL());
|
||||
$this->map1to1Item(Ids::NETHER_STAR, Items::NETHER_STAR());
|
||||
$this->map1to1Item(Ids::NETHERBRICK, Items::NETHER_BRICK());
|
||||
|
@ -74,6 +74,7 @@ final class ItemTypeNames{
|
||||
public const BLEACH = "minecraft:bleach";
|
||||
public const BLUE_DYE = "minecraft:blue_dye";
|
||||
public const BOAT = "minecraft:boat";
|
||||
public const BOGGED_SPAWN_EGG = "minecraft:bogged_spawn_egg";
|
||||
public const BONE = "minecraft:bone";
|
||||
public const BONE_MEAL = "minecraft:bone_meal";
|
||||
public const BOOK = "minecraft:book";
|
||||
@ -286,6 +287,8 @@ final class ItemTypeNames{
|
||||
public const LEATHER_HELMET = "minecraft:leather_helmet";
|
||||
public const LEATHER_HORSE_ARMOR = "minecraft:leather_horse_armor";
|
||||
public const LEATHER_LEGGINGS = "minecraft:leather_leggings";
|
||||
public const LEAVES = "minecraft:leaves";
|
||||
public const LEAVES2 = "minecraft:leaves2";
|
||||
public const LIGHT_BLUE_DYE = "minecraft:light_blue_dye";
|
||||
public const LIGHT_GRAY_DYE = "minecraft:light_gray_dye";
|
||||
public const LIME_DYE = "minecraft:lime_dye";
|
||||
@ -500,16 +503,19 @@ final class ItemTypeNames{
|
||||
public const WHEAT_SEEDS = "minecraft:wheat_seeds";
|
||||
public const WHITE_DYE = "minecraft:white_dye";
|
||||
public const WILD_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:wild_armor_trim_smithing_template";
|
||||
public const WIND_CHARGE = "minecraft:wind_charge";
|
||||
public const WITCH_SPAWN_EGG = "minecraft:witch_spawn_egg";
|
||||
public const WITHER_SKELETON_SPAWN_EGG = "minecraft:wither_skeleton_spawn_egg";
|
||||
public const WITHER_SPAWN_EGG = "minecraft:wither_spawn_egg";
|
||||
public const WOLF_ARMOR = "minecraft:wolf_armor";
|
||||
public const WOLF_SPAWN_EGG = "minecraft:wolf_spawn_egg";
|
||||
public const WOOD = "minecraft:wood";
|
||||
public const WOODEN_AXE = "minecraft:wooden_axe";
|
||||
public const WOODEN_DOOR = "minecraft:wooden_door";
|
||||
public const WOODEN_HOE = "minecraft:wooden_hoe";
|
||||
public const WOODEN_PICKAXE = "minecraft:wooden_pickaxe";
|
||||
public const WOODEN_SHOVEL = "minecraft:wooden_shovel";
|
||||
public const WOODEN_SLAB = "minecraft:wooden_slab";
|
||||
public const WOODEN_SWORD = "minecraft:wooden_sword";
|
||||
public const WOOL = "minecraft:wool";
|
||||
public const WRITABLE_BOOK = "minecraft:writable_book";
|
||||
|
@ -88,6 +88,9 @@ final class ItemIdMetaUpgradeSchemaUtils{
|
||||
}
|
||||
|
||||
$jsonMapper = new \JsonMapper();
|
||||
$jsonMapper->bExceptionOnMissingData = true;
|
||||
$jsonMapper->bExceptionOnUndefinedProperty = true;
|
||||
$jsonMapper->bStrictObjectTypeChecking = true;
|
||||
try{
|
||||
$model = $jsonMapper->map($json, new ItemIdMetaUpgradeSchemaModel());
|
||||
}catch(\JsonMapper_Exception $e){
|
||||
|
@ -252,6 +252,14 @@ abstract class Entity{
|
||||
return $this->alwaysShowNameTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether players can rename this entity using a name tag.
|
||||
* Note that plugins can still name entities using setNameTag().
|
||||
*/
|
||||
public function canBeRenamed() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setNameTag(string $name) : void{
|
||||
$this->nameTag = $name;
|
||||
$this->networkPropertiesDirty = true;
|
||||
@ -792,7 +800,7 @@ abstract class Entity{
|
||||
}
|
||||
|
||||
protected function broadcastMotion() : void{
|
||||
NetworkBroadcastUtils::broadcastPackets($this->hasSpawned, [SetActorMotionPacket::create($this->id, $this->getMotion())]);
|
||||
NetworkBroadcastUtils::broadcastPackets($this->hasSpawned, [SetActorMotionPacket::create($this->id, $this->getMotion(), tick: 0)]);
|
||||
}
|
||||
|
||||
public function getGravity() : float{
|
||||
|
@ -132,6 +132,10 @@ abstract class Living extends Entity{
|
||||
|
||||
abstract public function getName() : string;
|
||||
|
||||
public function canBeRenamed() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function initEntity(CompoundTag $nbt) : void{
|
||||
parent::initEntity($nbt);
|
||||
|
||||
|
106
src/event/player/PlayerResourcePackOfferEvent.php
Normal file
106
src/event/player/PlayerResourcePackOfferEvent.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?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\event\player;
|
||||
|
||||
use pocketmine\event\Event;
|
||||
use pocketmine\player\PlayerInfo;
|
||||
use pocketmine\resourcepacks\ResourcePack;
|
||||
use function array_unshift;
|
||||
|
||||
/**
|
||||
* Called after a player authenticates and is being offered resource packs to download.
|
||||
*
|
||||
* This event should be used to decide which resource packs to offer the player and whether to require the player to
|
||||
* download the packs before they can join the server.
|
||||
*/
|
||||
class PlayerResourcePackOfferEvent extends Event{
|
||||
/**
|
||||
* @param ResourcePack[] $resourcePacks
|
||||
* @param string[] $encryptionKeys pack UUID => key, leave unset for any packs that are not encrypted
|
||||
*
|
||||
* @phpstan-param list<ResourcePack> $resourcePacks
|
||||
* @phpstan-param array<string, string> $encryptionKeys
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly PlayerInfo $playerInfo,
|
||||
private array $resourcePacks,
|
||||
private array $encryptionKeys,
|
||||
private bool $mustAccept
|
||||
){}
|
||||
|
||||
public function getPlayerInfo() : PlayerInfo{
|
||||
return $this->playerInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a resource pack to the top of the stack.
|
||||
* The resources in this pack will be applied over the top of any existing packs.
|
||||
*/
|
||||
public function addResourcePack(ResourcePack $entry, ?string $encryptionKey = null) : void{
|
||||
array_unshift($this->resourcePacks, $entry);
|
||||
if($encryptionKey !== null){
|
||||
$this->encryptionKeys[$entry->getPackId()] = $encryptionKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resource packs to offer. Packs are applied from the highest key to the lowest, with each pack
|
||||
* overwriting any resources from the previous pack. This means that the pack at index 0 gets the final say on which
|
||||
* resources are used.
|
||||
*
|
||||
* @param ResourcePack[] $resourcePacks
|
||||
* @param string[] $encryptionKeys pack UUID => key, leave unset for any packs that are not encrypted
|
||||
*
|
||||
* @phpstan-param list<ResourcePack> $resourcePacks
|
||||
* @phpstan-param array<string, string> $encryptionKeys
|
||||
*/
|
||||
public function setResourcePacks(array $resourcePacks, array $encryptionKeys) : void{
|
||||
$this->resourcePacks = $resourcePacks;
|
||||
$this->encryptionKeys = $encryptionKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResourcePack[]
|
||||
* @phpstan-return list<ResourcePack>
|
||||
*/
|
||||
public function getResourcePacks() : array{
|
||||
return $this->resourcePacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @phpstan-return array<string, string>
|
||||
*/
|
||||
public function getEncryptionKeys() : array{
|
||||
return $this->encryptionKeys;
|
||||
}
|
||||
|
||||
public function setMustAccept(bool $mustAccept) : void{
|
||||
$this->mustAccept = $mustAccept;
|
||||
}
|
||||
|
||||
public function mustAccept() : bool{
|
||||
return $this->mustAccept;
|
||||
}
|
||||
}
|
@ -323,8 +323,9 @@ final class ItemTypeIds{
|
||||
public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = 20284;
|
||||
public const SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = 20285;
|
||||
public const PITCHER_POD = 20286;
|
||||
public const NAME_TAG = 20287;
|
||||
|
||||
public const FIRST_UNUSED_ITEM_ID = 20287;
|
||||
public const FIRST_UNUSED_ITEM_ID = 20288;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;
|
||||
|
||||
|
40
src/item/NameTag.php
Normal file
40
src/item/NameTag.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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\item;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class NameTag extends Item{
|
||||
|
||||
public function onInteractEntity(Player $player, Entity $entity, Vector3 $clickVector) : bool{
|
||||
if($entity->canBeRenamed() && $this->hasCustomName()){
|
||||
$entity->setNameTag($this->getCustomName());
|
||||
$this->pop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1384,6 +1384,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("mutton_raw", fn() => Items::RAW_MUTTON());
|
||||
$result->register("muttoncooked", fn() => Items::COOKED_MUTTON());
|
||||
$result->register("muttonraw", fn() => Items::RAW_MUTTON());
|
||||
$result->register("name_tag", fn() => Items::NAME_TAG());
|
||||
$result->register("nautilus_shell", fn() => Items::NAUTILUS_SHELL());
|
||||
$result->register("nether_brick", fn() => Items::NETHER_BRICK());
|
||||
$result->register("nether_quartz", fn() => Items::NETHER_QUARTZ());
|
||||
|
@ -219,6 +219,7 @@ use function strtolower;
|
||||
* @method static MilkBucket MILK_BUCKET()
|
||||
* @method static Minecart MINECART()
|
||||
* @method static MushroomStew MUSHROOM_STEW()
|
||||
* @method static NameTag NAME_TAG()
|
||||
* @method static Item NAUTILUS_SHELL()
|
||||
* @method static Axe NETHERITE_AXE()
|
||||
* @method static Armor NETHERITE_BOOTS()
|
||||
@ -490,6 +491,7 @@ final class VanillaItems{
|
||||
self::register("milk_bucket", new MilkBucket(new IID(Ids::MILK_BUCKET), "Milk Bucket"));
|
||||
self::register("minecart", new Minecart(new IID(Ids::MINECART), "Minecart"));
|
||||
self::register("mushroom_stew", new MushroomStew(new IID(Ids::MUSHROOM_STEW), "Mushroom Stew"));
|
||||
self::register("name_tag", new NameTag(new IID(Ids::NAME_TAG), "Name Tag"));
|
||||
self::register("nautilus_shell", new Item(new IID(Ids::NAUTILUS_SHELL), "Nautilus Shell"));
|
||||
self::register("nether_brick", new Item(new IID(Ids::NETHER_BRICK), "Nether Brick"));
|
||||
self::register("nether_quartz", new Item(new IID(Ids::NETHER_QUARTZ), "Nether Quartz"));
|
||||
|
@ -28,7 +28,6 @@ use pocketmine\network\mcpe\compression\Compressor;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\types\ChunkPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||
use pocketmine\network\mcpe\serializer\ChunkSerializer;
|
||||
@ -72,11 +71,10 @@ class ChunkRequestTask extends AsyncTask{
|
||||
|
||||
$subCount = ChunkSerializer::getSubChunkCount($chunk, $dimensionId);
|
||||
$converter = TypeConverter::getInstance();
|
||||
$encoderContext = new PacketSerializerContext($converter->getItemTypeDictionary());
|
||||
$payload = ChunkSerializer::serializeFullChunk($chunk, $dimensionId, $converter->getBlockTranslator(), $encoderContext, $this->tiles);
|
||||
$payload = ChunkSerializer::serializeFullChunk($chunk, $dimensionId, $converter->getBlockTranslator(), $this->tiles);
|
||||
|
||||
$stream = new BinaryStream();
|
||||
PacketBatch::encodePackets($stream, $encoderContext, [LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $dimensionId, $subCount, false, null, $payload)]);
|
||||
PacketBatch::encodePackets($stream, [LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $dimensionId, $subCount, false, null, $payload)]);
|
||||
|
||||
$compressor = $this->compressor->deserialize();
|
||||
$this->setResult(chr($compressor->getNetworkId()) . $compressor->compress($stream->getBuffer()));
|
||||
|
@ -423,6 +423,41 @@ class InventoryManager{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares itemstack extra data for equality. This is used to verify legacy InventoryTransaction slot predictions.
|
||||
*
|
||||
* TODO: It would be preferable if we didn't have to deserialize this, to improve performance and reduce attack
|
||||
* surface. However, the raw data may not match due to differences in ordering. Investigate whether the
|
||||
* client-provided NBT is consistently sorted.
|
||||
*/
|
||||
private function itemStackExtraDataEqual(ItemStack $left, ItemStack $right) : bool{
|
||||
if($left->getRawExtraData() === $right->getRawExtraData()){
|
||||
return true;
|
||||
}
|
||||
|
||||
$typeConverter = $this->session->getTypeConverter();
|
||||
$leftExtraData = $typeConverter->deserializeItemStackExtraData($left->getRawExtraData(), $left->getId());
|
||||
$rightExtraData = $typeConverter->deserializeItemStackExtraData($right->getRawExtraData(), $right->getId());
|
||||
|
||||
$leftNbt = $leftExtraData->getNbt();
|
||||
$rightNbt = $rightExtraData->getNbt();
|
||||
return
|
||||
$leftExtraData->getCanPlaceOn() === $rightExtraData->getCanPlaceOn() &&
|
||||
$leftExtraData->getCanDestroy() === $rightExtraData->getCanDestroy() && (
|
||||
$leftNbt === $rightNbt || //this covers null === null and fast object identity
|
||||
($leftNbt !== null && $rightNbt !== null && $leftNbt->equals($rightNbt))
|
||||
);
|
||||
}
|
||||
|
||||
private function itemStacksEqual(ItemStack $left, ItemStack $right) : bool{
|
||||
return
|
||||
$left->getId() === $right->getId() &&
|
||||
$left->getMeta() === $right->getMeta() &&
|
||||
$left->getBlockRuntimeId() === $right->getBlockRuntimeId() &&
|
||||
$left->getCount() === $right->getCount() &&
|
||||
$this->itemStackExtraDataEqual($left, $right);
|
||||
}
|
||||
|
||||
public function onSlotChange(Inventory $inventory, int $slot) : void{
|
||||
$inventoryEntry = $this->inventories[spl_object_id($inventory)] ?? null;
|
||||
if($inventoryEntry === null){
|
||||
@ -432,7 +467,7 @@ class InventoryManager{
|
||||
}
|
||||
$currentItem = $this->session->getTypeConverter()->coreItemStackToNet($inventory->getItem($slot));
|
||||
$clientSideItem = $inventoryEntry->predictions[$slot] ?? null;
|
||||
if($clientSideItem === null || !$clientSideItem->equals($currentItem)){
|
||||
if($clientSideItem === null || !$this->itemStacksEqual($currentItem, $clientSideItem)){
|
||||
//no prediction or incorrect - do not associate this with the currently active itemstack request
|
||||
$this->trackItemStack($inventoryEntry, $slot, $currentItem, null);
|
||||
$inventoryEntry->pendingSyncs[$slot] = $currentItem;
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe;
|
||||
|
||||
use pocketmine\entity\effect\EffectInstance;
|
||||
use pocketmine\event\player\PlayerDuplicateLoginEvent;
|
||||
use pocketmine\event\player\PlayerResourcePackOfferEvent;
|
||||
use pocketmine\event\server\DataPacketDecodeEvent;
|
||||
use pocketmine\event\server\DataPacketReceiveEvent;
|
||||
use pocketmine\event\server\DataPacketSendEvent;
|
||||
@ -67,7 +68,6 @@ use pocketmine\network\mcpe\protocol\PlayStatusPacket;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\ServerboundPacket;
|
||||
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
|
||||
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
|
||||
@ -101,6 +101,8 @@ use pocketmine\player\Player;
|
||||
use pocketmine\player\PlayerInfo;
|
||||
use pocketmine\player\UsedChunkStatus;
|
||||
use pocketmine\player\XboxLivePlayerInfo;
|
||||
use pocketmine\promise\Promise;
|
||||
use pocketmine\promise\PromiseResolver;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
@ -159,15 +161,24 @@ class NetworkSession{
|
||||
|
||||
/** @var string[] */
|
||||
private array $sendBuffer = [];
|
||||
|
||||
/**
|
||||
* @var \SplQueue|CompressBatchPromise[]|string[]
|
||||
* @phpstan-var \SplQueue<CompressBatchPromise|string>
|
||||
* @var PromiseResolver[]
|
||||
* @phpstan-var list<PromiseResolver<true>>
|
||||
*/
|
||||
private array $sendBufferAckPromises = [];
|
||||
|
||||
/** @phpstan-var \SplQueue<array{CompressBatchPromise|string, list<PromiseResolver<true>>}> */
|
||||
private \SplQueue $compressedQueue;
|
||||
private bool $forceAsyncCompression = true;
|
||||
private bool $enableCompression = false; //disabled until handshake completed
|
||||
|
||||
private int $nextAckReceiptId = 0;
|
||||
/**
|
||||
* @var PromiseResolver[][]
|
||||
* @phpstan-var array<int, list<PromiseResolver<true>>>
|
||||
*/
|
||||
private array $ackPromisesByReceiptId = [];
|
||||
|
||||
private ?InventoryManager $invManager = null;
|
||||
|
||||
/**
|
||||
@ -180,7 +191,6 @@ class NetworkSession{
|
||||
private Server $server,
|
||||
private NetworkSessionManager $manager,
|
||||
private PacketPool $packetPool,
|
||||
private PacketSerializerContext $packetSerializerContext,
|
||||
private PacketSender $sender,
|
||||
private PacketBroadcaster $broadcaster,
|
||||
private EntityEventBroadcaster $entityEventBroadcaster,
|
||||
@ -362,12 +372,12 @@ class NetworkSession{
|
||||
}
|
||||
|
||||
if($this->enableCompression){
|
||||
Timings::$playerNetworkReceiveDecompress->startTiming();
|
||||
$compressionType = ord($payload[0]);
|
||||
$compressed = substr($payload, 1);
|
||||
if($compressionType === CompressionAlgorithm::NONE){
|
||||
$decompressed = $compressed;
|
||||
}elseif($compressionType === $this->compressor->getNetworkId()){
|
||||
Timings::$playerNetworkReceiveDecompress->startTiming();
|
||||
try{
|
||||
$decompressed = $this->compressor->decompress($compressed);
|
||||
}catch(DecompressionException $e){
|
||||
@ -385,12 +395,8 @@ class NetworkSession{
|
||||
|
||||
try{
|
||||
$stream = new BinaryStream($decompressed);
|
||||
$count = 0;
|
||||
foreach(PacketBatch::decodeRaw($stream) as $buffer){
|
||||
$this->gamePacketLimiter->decrement();
|
||||
if(++$count > 100){
|
||||
throw new PacketHandlingException("Too many packets in batch");
|
||||
}
|
||||
$packet = $this->packetPool->getPacket($buffer);
|
||||
if($packet === null){
|
||||
$this->logger->debug("Unknown packet: " . base64_encode($buffer));
|
||||
@ -435,7 +441,7 @@ class NetworkSession{
|
||||
$decodeTimings = Timings::getDecodeDataPacketTimings($packet);
|
||||
$decodeTimings->startTiming();
|
||||
try{
|
||||
$stream = PacketSerializer::decoder($buffer, 0, $this->packetSerializerContext);
|
||||
$stream = PacketSerializer::decoder($buffer, 0);
|
||||
try{
|
||||
$packet->decode($stream);
|
||||
}catch(PacketDecodeException $e){
|
||||
@ -470,7 +476,23 @@ class NetworkSession{
|
||||
}
|
||||
}
|
||||
|
||||
public function sendDataPacket(ClientboundPacket $packet, bool $immediate = false) : bool{
|
||||
public function handleAckReceipt(int $receiptId) : void{
|
||||
if(!$this->connected){
|
||||
return;
|
||||
}
|
||||
if(isset($this->ackPromisesByReceiptId[$receiptId])){
|
||||
$promises = $this->ackPromisesByReceiptId[$receiptId];
|
||||
unset($this->ackPromisesByReceiptId[$receiptId]);
|
||||
foreach($promises as $promise){
|
||||
$promise->resolve(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param PromiseResolver<true>|null $ackReceiptResolver
|
||||
*/
|
||||
private function sendDataPacketInternal(ClientboundPacket $packet, bool $immediate, ?PromiseResolver $ackReceiptResolver) : bool{
|
||||
if(!$this->connected){
|
||||
return false;
|
||||
}
|
||||
@ -493,8 +515,11 @@ class NetworkSession{
|
||||
$packets = [$packet];
|
||||
}
|
||||
|
||||
if($ackReceiptResolver !== null){
|
||||
$this->sendBufferAckPromises[] = $ackReceiptResolver;
|
||||
}
|
||||
foreach($packets as $evPacket){
|
||||
$this->addToSendBuffer(self::encodePacketTimed(PacketSerializer::encoder($this->packetSerializerContext), $evPacket));
|
||||
$this->addToSendBuffer(self::encodePacketTimed(PacketSerializer::encoder(), $evPacket));
|
||||
}
|
||||
if($immediate){
|
||||
$this->flushSendBuffer(true);
|
||||
@ -506,6 +531,23 @@ class NetworkSession{
|
||||
}
|
||||
}
|
||||
|
||||
public function sendDataPacket(ClientboundPacket $packet, bool $immediate = false) : bool{
|
||||
return $this->sendDataPacketInternal($packet, $immediate, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-return Promise<true>
|
||||
*/
|
||||
public function sendDataPacketWithReceipt(ClientboundPacket $packet, bool $immediate = false) : Promise{
|
||||
$resolver = new PromiseResolver();
|
||||
|
||||
if(!$this->sendDataPacketInternal($packet, $immediate, $resolver)){
|
||||
$resolver->reject();
|
||||
}
|
||||
|
||||
return $resolver->getPromise();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@ -547,15 +589,15 @@ class NetworkSession{
|
||||
$batch = $stream->getBuffer();
|
||||
}
|
||||
$this->sendBuffer = [];
|
||||
$this->queueCompressedNoBufferFlush($batch, $immediate);
|
||||
$ackPromises = $this->sendBufferAckPromises;
|
||||
$this->sendBufferAckPromises = [];
|
||||
$this->queueCompressedNoBufferFlush($batch, $immediate, $ackPromises);
|
||||
}finally{
|
||||
Timings::$playerNetworkSend->stopTiming();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getPacketSerializerContext() : PacketSerializerContext{ return $this->packetSerializerContext; }
|
||||
|
||||
public function getBroadcaster() : PacketBroadcaster{ return $this->broadcaster; }
|
||||
|
||||
public function getEntityEventBroadcaster() : EntityEventBroadcaster{ return $this->entityEventBroadcaster; }
|
||||
@ -576,22 +618,27 @@ class NetworkSession{
|
||||
}
|
||||
}
|
||||
|
||||
private function queueCompressedNoBufferFlush(CompressBatchPromise|string $batch, bool $immediate = false) : void{
|
||||
/**
|
||||
* @param PromiseResolver[] $ackPromises
|
||||
*
|
||||
* @phpstan-param list<PromiseResolver<true>> $ackPromises
|
||||
*/
|
||||
private function queueCompressedNoBufferFlush(CompressBatchPromise|string $batch, bool $immediate = false, array $ackPromises = []) : void{
|
||||
Timings::$playerNetworkSend->startTiming();
|
||||
try{
|
||||
if(is_string($batch)){
|
||||
if($immediate){
|
||||
//Skips all queues
|
||||
$this->sendEncoded($batch, true);
|
||||
$this->sendEncoded($batch, true, $ackPromises);
|
||||
}else{
|
||||
$this->compressedQueue->enqueue($batch);
|
||||
$this->compressedQueue->enqueue([$batch, $ackPromises]);
|
||||
$this->flushCompressedQueue();
|
||||
}
|
||||
}elseif($immediate){
|
||||
//Skips all queues
|
||||
$this->sendEncoded($batch->getResult(), true);
|
||||
$this->sendEncoded($batch->getResult(), true, $ackPromises);
|
||||
}else{
|
||||
$this->compressedQueue->enqueue($batch);
|
||||
$this->compressedQueue->enqueue([$batch, $ackPromises]);
|
||||
$batch->onResolve(function() : void{
|
||||
if($this->connected){
|
||||
$this->flushCompressedQueue();
|
||||
@ -608,14 +655,14 @@ class NetworkSession{
|
||||
try{
|
||||
while(!$this->compressedQueue->isEmpty()){
|
||||
/** @var CompressBatchPromise|string $current */
|
||||
$current = $this->compressedQueue->bottom();
|
||||
[$current, $ackPromises] = $this->compressedQueue->bottom();
|
||||
if(is_string($current)){
|
||||
$this->compressedQueue->dequeue();
|
||||
$this->sendEncoded($current);
|
||||
$this->sendEncoded($current, false, $ackPromises);
|
||||
|
||||
}elseif($current->hasResult()){
|
||||
$this->compressedQueue->dequeue();
|
||||
$this->sendEncoded($current->getResult());
|
||||
$this->sendEncoded($current->getResult(), false, $ackPromises);
|
||||
|
||||
}else{
|
||||
//can't send any more queued until this one is ready
|
||||
@ -627,13 +674,24 @@ class NetworkSession{
|
||||
}
|
||||
}
|
||||
|
||||
private function sendEncoded(string $payload, bool $immediate = false) : void{
|
||||
/**
|
||||
* @param PromiseResolver[] $ackPromises
|
||||
* @phpstan-param list<PromiseResolver<true>> $ackPromises
|
||||
*/
|
||||
private function sendEncoded(string $payload, bool $immediate, array $ackPromises) : void{
|
||||
if($this->cipher !== null){
|
||||
Timings::$playerNetworkSendEncrypt->startTiming();
|
||||
$payload = $this->cipher->encrypt($payload);
|
||||
Timings::$playerNetworkSendEncrypt->stopTiming();
|
||||
}
|
||||
$this->sender->send($payload, $immediate);
|
||||
|
||||
if(count($ackPromises) > 0){
|
||||
$ackReceiptId = $this->nextAckReceiptId++;
|
||||
$this->ackPromisesByReceiptId[$ackReceiptId] = $ackPromises;
|
||||
}else{
|
||||
$ackReceiptId = null;
|
||||
}
|
||||
$this->sender->send($payload, $immediate, $ackReceiptId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -653,6 +711,19 @@ class NetworkSession{
|
||||
$this->setHandler(null);
|
||||
$this->connected = false;
|
||||
|
||||
$ackPromisesByReceiptId = $this->ackPromisesByReceiptId;
|
||||
$this->ackPromisesByReceiptId = [];
|
||||
foreach($ackPromisesByReceiptId as $resolvers){
|
||||
foreach($resolvers as $resolver){
|
||||
$resolver->reject();
|
||||
}
|
||||
}
|
||||
$sendBufferAckPromises = $this->sendBufferAckPromises;
|
||||
$this->sendBufferAckPromises = [];
|
||||
foreach($sendBufferAckPromises as $resolver){
|
||||
$resolver->reject();
|
||||
}
|
||||
|
||||
$this->logger->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_network_session_close($reason)));
|
||||
}
|
||||
}
|
||||
@ -848,7 +919,19 @@ class NetworkSession{
|
||||
$this->sendDataPacket(PlayStatusPacket::create(PlayStatusPacket::LOGIN_SUCCESS));
|
||||
|
||||
$this->logger->debug("Initiating resource packs phase");
|
||||
$this->setHandler(new ResourcePacksPacketHandler($this, $this->server->getResourcePackManager(), function() : void{
|
||||
|
||||
$packManager = $this->server->getResourcePackManager();
|
||||
$resourcePacks = $packManager->getResourceStack();
|
||||
$keys = [];
|
||||
foreach($resourcePacks as $resourcePack){
|
||||
$key = $packManager->getPackEncryptionKey($resourcePack->getPackId());
|
||||
if($key !== null){
|
||||
$keys[$resourcePack->getPackId()] = $key;
|
||||
}
|
||||
}
|
||||
$event = new PlayerResourcePackOfferEvent($this->info, $resourcePacks, $keys, $packManager->resourcePacksRequired());
|
||||
$event->call();
|
||||
$this->setHandler(new ResourcePacksPacketHandler($this, $event->getResourcePacks(), $event->getEncryptionKeys(), $event->mustAccept(), function() : void{
|
||||
$this->createPlayer();
|
||||
}));
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ interface PacketSender{
|
||||
/**
|
||||
* Pushes a packet into the channel to be processed.
|
||||
*/
|
||||
public function send(string $payload, bool $immediate) : void;
|
||||
public function send(string $payload, bool $immediate, ?int $receiptId) : void;
|
||||
|
||||
/**
|
||||
* Closes the channel, terminating the connection.
|
||||
|
@ -87,12 +87,13 @@ final class StandardEntityEventBroadcaster implements EntityEventBroadcaster{
|
||||
EffectIdMap::getInstance()->toId($effect->getType()),
|
||||
$effect->getAmplifier(),
|
||||
$effect->isVisible(),
|
||||
$effect->getDuration()
|
||||
$effect->getDuration(),
|
||||
tick: 0
|
||||
));
|
||||
}
|
||||
|
||||
public function onEntityEffectRemoved(array $recipients, Living $entity, EffectInstance $effect) : void{
|
||||
$this->sendDataPacket($recipients, MobEffectPacket::remove($entity->getId(), EffectIdMap::getInstance()->toId($effect->getType())));
|
||||
$this->sendDataPacket($recipients, MobEffectPacket::remove($entity->getId(), EffectIdMap::getInstance()->toId($effect->getType()), tick: 0));
|
||||
}
|
||||
|
||||
public function onEntityRemoved(array $recipients, Entity $entity) : void{
|
||||
|
@ -26,7 +26,6 @@ namespace pocketmine\network\mcpe;
|
||||
use pocketmine\event\server\DataPacketSendEvent;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
@ -37,8 +36,7 @@ use function strlen;
|
||||
|
||||
final class StandardPacketBroadcaster implements PacketBroadcaster{
|
||||
public function __construct(
|
||||
private Server $server,
|
||||
private PacketSerializerContext $protocolContext
|
||||
private Server $server
|
||||
){}
|
||||
|
||||
public function broadcastPackets(array $recipients, array $packets) : void{
|
||||
@ -58,10 +56,6 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
|
||||
/** @var NetworkSession[][] $targetsByCompressor */
|
||||
$targetsByCompressor = [];
|
||||
foreach($recipients as $recipient){
|
||||
if($recipient->getPacketSerializerContext() !== $this->protocolContext){
|
||||
throw new \InvalidArgumentException("Only recipients with the same protocol context as the broadcaster can be broadcast to by this broadcaster");
|
||||
}
|
||||
|
||||
//TODO: different compressors might be compatible, it might not be necessary to split them up by object
|
||||
$compressor = $recipient->getCompressor();
|
||||
$compressors[spl_object_id($compressor)] = $compressor;
|
||||
@ -72,7 +66,7 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
|
||||
$totalLength = 0;
|
||||
$packetBuffers = [];
|
||||
foreach($packets as $packet){
|
||||
$buffer = NetworkSession::encodePacketTimed(PacketSerializer::encoder($this->protocolContext), $packet);
|
||||
$buffer = NetworkSession::encodePacketTimed(PacketSerializer::encoder(), $packet);
|
||||
//varint length prefix + packet buffer
|
||||
$totalLength += (((int) log(strlen($buffer), 128)) + 1) + strlen($buffer);
|
||||
$packetBuffers[] = $buffer;
|
||||
|
@ -124,6 +124,7 @@ class ProcessLoginTask extends AsyncTask{
|
||||
$mapper = new \JsonMapper();
|
||||
$mapper->bExceptionOnMissingData = true;
|
||||
$mapper->bExceptionOnUndefinedProperty = true;
|
||||
$mapper->bStrictObjectTypeChecking = true;
|
||||
$mapper->bEnforceMapType = false;
|
||||
|
||||
try{
|
||||
@ -167,6 +168,7 @@ class ProcessLoginTask extends AsyncTask{
|
||||
$mapper = new \JsonMapper();
|
||||
$mapper->bExceptionOnUndefinedProperty = false; //we only care about the properties we're using in this case
|
||||
$mapper->bExceptionOnMissingData = true;
|
||||
$mapper->bStrictObjectTypeChecking = true;
|
||||
$mapper->bEnforceMapType = false;
|
||||
$mapper->bRemoveUndefinedAttributes = true;
|
||||
try{
|
||||
|
@ -38,7 +38,7 @@ final class ZlibCompressor implements Compressor{
|
||||
|
||||
public const DEFAULT_LEVEL = 7;
|
||||
public const DEFAULT_THRESHOLD = 256;
|
||||
public const DEFAULT_MAX_DECOMPRESSION_SIZE = 2 * 1024 * 1024;
|
||||
public const DEFAULT_MAX_DECOMPRESSION_SIZE = 8 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* @see SingletonTrait::make()
|
||||
|
@ -30,13 +30,17 @@ use pocketmine\crafting\RecipeIngredient;
|
||||
use pocketmine\crafting\TagWildcardRecipeIngredient;
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
||||
use pocketmine\data\bedrock\item\ItemTypeNames;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\nbt\NbtException;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\types\GameMode as ProtocolGameMode;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackExtraData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackExtraDataShield;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\IntIdMetaItemDescriptor;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient as ProtocolRecipeIngredient;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\StringIdMetaItemDescriptor;
|
||||
@ -76,7 +80,7 @@ class TypeConverter{
|
||||
);
|
||||
|
||||
$this->itemTypeDictionary = ItemTypeDictionaryFromDataHelper::loadFromString(Filesystem::fileGetContents(BedrockDataFiles::REQUIRED_ITEM_LIST_JSON));
|
||||
$this->shieldRuntimeId = $this->itemTypeDictionary->fromStringId("minecraft:shield");
|
||||
$this->shieldRuntimeId = $this->itemTypeDictionary->fromStringId(ItemTypeNames::SHIELD);
|
||||
|
||||
$this->itemTranslator = new ItemTranslator(
|
||||
$this->itemTypeDictionary,
|
||||
@ -217,26 +221,36 @@ class TypeConverter{
|
||||
[$id, $meta, $blockRuntimeId] = $idMeta;
|
||||
}
|
||||
|
||||
$extraData = $id === $this->shieldRuntimeId ?
|
||||
new ItemStackExtraDataShield($nbt, canPlaceOn: [], canDestroy: [], blockingTick: 0) :
|
||||
new ItemStackExtraData($nbt, canPlaceOn: [], canDestroy: []);
|
||||
$extraDataSerializer = PacketSerializer::encoder();
|
||||
$extraData->write($extraDataSerializer);
|
||||
|
||||
return new ItemStack(
|
||||
$id,
|
||||
$meta,
|
||||
$itemStack->getCount(),
|
||||
$blockRuntimeId ?? ItemTranslator::NO_BLOCK_RUNTIME_ID,
|
||||
$nbt,
|
||||
[],
|
||||
[],
|
||||
$id === $this->shieldRuntimeId ? 0 : null
|
||||
$extraDataSerializer->getBuffer(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Avoid this in server-side code. If you need to compare ItemStacks provided by the client to the
|
||||
* server, prefer encoding the server's itemstack and comparing the serialized ItemStack, instead of converting
|
||||
* the client's ItemStack to a core Item.
|
||||
* This method will fully decode the item's extra data, which can be very costly if the item has a lot of NBT data.
|
||||
*
|
||||
* @throws TypeConversionException
|
||||
*/
|
||||
public function netItemStackToCore(ItemStack $itemStack) : Item{
|
||||
if($itemStack->getId() === 0){
|
||||
return VanillaItems::AIR();
|
||||
}
|
||||
$compound = $itemStack->getNbt();
|
||||
$extraData = $this->deserializeItemStackExtraData($itemStack->getRawExtraData(), $itemStack->getId());
|
||||
|
||||
$compound = $extraData->getNbt();
|
||||
|
||||
$itemResult = $this->itemTranslator->fromNetworkId($itemStack->getId(), $itemStack->getMeta(), $itemStack->getBlockRuntimeId());
|
||||
|
||||
@ -255,4 +269,11 @@ class TypeConverter{
|
||||
|
||||
return $itemResult;
|
||||
}
|
||||
|
||||
public function deserializeItemStackExtraData(string $extraData, int $id) : ItemStackExtraData{
|
||||
$extraDataDeserializer = PacketSerializer::decoder($extraData, 0);
|
||||
return $id === $this->shieldRuntimeId ?
|
||||
ItemStackExtraDataShield::read($extraDataDeserializer) :
|
||||
ItemStackExtraData::read($extraDataDeserializer);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace pocketmine\network\mcpe\handler;
|
||||
|
||||
use pocketmine\block\BaseSign;
|
||||
use pocketmine\block\ItemFrame;
|
||||
use pocketmine\block\Lectern;
|
||||
use pocketmine\block\tile\Sign;
|
||||
use pocketmine\block\utils\SignText;
|
||||
@ -60,7 +59,6 @@ use pocketmine\network\mcpe\protocol\ContainerClosePacket;
|
||||
use pocketmine\network\mcpe\protocol\EmotePacket;
|
||||
use pocketmine\network\mcpe\protocol\InteractPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket;
|
||||
use pocketmine\network\mcpe\protocol\ItemStackRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\ItemStackResponsePacket;
|
||||
use pocketmine\network\mcpe\protocol\LabTablePacket;
|
||||
@ -444,9 +442,18 @@ class InGamePacketHandler extends PacketHandler{
|
||||
return false;
|
||||
}
|
||||
$serverItemStack = $this->session->getTypeConverter()->coreItemStackToNet($sourceSlotItem);
|
||||
//because the client doesn't tell us the expected itemstack ID, we have to deep-compare our known
|
||||
//itemstack info with the one the client sent. This is costly, but we don't have any other option :(
|
||||
if(!$serverItemStack->equals($clientItemStack)){
|
||||
//Sadly we don't have itemstack IDs here, so we have to compare the basic item properties to ensure that we're
|
||||
//dropping the item the client expects (inventory might be out of sync with the client).
|
||||
if(
|
||||
$serverItemStack->getId() !== $clientItemStack->getId() ||
|
||||
$serverItemStack->getMeta() !== $clientItemStack->getMeta() ||
|
||||
$serverItemStack->getCount() !== $clientItemStack->getCount() ||
|
||||
$serverItemStack->getBlockRuntimeId() !== $clientItemStack->getBlockRuntimeId()
|
||||
//Raw extraData may not match because of TAG_Compound key ordering differences, and decoding it to compare
|
||||
//is costly. Assume that we're in sync if id+meta+count+runtimeId match.
|
||||
//NB: Make sure $clientItemStack isn't used to create the dropped item, as that would allow the client
|
||||
//to change the item NBT since we're not validating it.
|
||||
){
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -799,15 +806,6 @@ class InGamePacketHandler extends PacketHandler{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleItemFrameDropItem(ItemFrameDropItemPacket $packet) : bool{
|
||||
$blockPosition = $packet->blockPosition;
|
||||
$block = $this->player->getWorld()->getBlockAt($blockPosition->getX(), $blockPosition->getY(), $blockPosition->getZ());
|
||||
if($block instanceof ItemFrame && $block->getFramedItem() !== null){
|
||||
return $this->player->attackBlock(new Vector3($blockPosition->getX(), $blockPosition->getY(), $blockPosition->getZ()), $block->getFacing());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleBossEvent(BossEventPacket $packet) : bool{
|
||||
return false; //TODO
|
||||
}
|
||||
@ -869,8 +867,12 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
public function handleBookEdit(BookEditPacket $packet) : bool{
|
||||
$inventory = $this->player->getInventory();
|
||||
if(!$inventory->slotExists($packet->inventorySlot)){
|
||||
return false;
|
||||
}
|
||||
//TODO: break this up into book API things
|
||||
$oldBook = $this->player->getInventory()->getItem($packet->inventorySlot);
|
||||
$oldBook = $inventory->getItem($packet->inventorySlot);
|
||||
if(!($oldBook instanceof WritableBook)){
|
||||
return false;
|
||||
}
|
||||
@ -985,11 +987,6 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
public function handleLecternUpdate(LecternUpdatePacket $packet) : bool{
|
||||
if($packet->dropBook){
|
||||
//Drop book is handled with an interact event on use item transaction
|
||||
return true;
|
||||
}
|
||||
|
||||
$pos = $packet->blockPosition;
|
||||
$chunkX = $pos->getX() >> Chunk::COORD_BIT_SIZE;
|
||||
$chunkZ = $pos->getZ() >> Chunk::COORD_BIT_SIZE;
|
||||
|
@ -169,6 +169,7 @@ class LoginPacketHandler extends PacketHandler{
|
||||
$mapper->bEnforceMapType = false; //TODO: we don't really need this as an array, but right now we don't have enough models
|
||||
$mapper->bExceptionOnMissingData = true;
|
||||
$mapper->bExceptionOnUndefinedProperty = true;
|
||||
$mapper->bStrictObjectTypeChecking = true;
|
||||
try{
|
||||
/** @var AuthenticationData $extraData */
|
||||
$extraData = $mapper->map($claims["extraData"], new AuthenticationData());
|
||||
@ -197,6 +198,7 @@ class LoginPacketHandler extends PacketHandler{
|
||||
$mapper->bEnforceMapType = false; //TODO: we don't really need this as an array, but right now we don't have enough models
|
||||
$mapper->bExceptionOnMissingData = true;
|
||||
$mapper->bExceptionOnUndefinedProperty = true;
|
||||
$mapper->bStrictObjectTypeChecking = true;
|
||||
try{
|
||||
$clientData = $mapper->map($clientDataClaims, new ClientData());
|
||||
}catch(\JsonMapper_Exception $e){
|
||||
|
@ -37,12 +37,13 @@ use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackInfoEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackStackEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackType;
|
||||
use pocketmine\resourcepacks\ResourcePack;
|
||||
use pocketmine\resourcepacks\ResourcePackManager;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function ceil;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
@ -50,37 +51,77 @@ use function substr;
|
||||
* packs to the client.
|
||||
*/
|
||||
class ResourcePacksPacketHandler extends PacketHandler{
|
||||
private const PACK_CHUNK_SIZE = 128 * 1024; //128KB
|
||||
private const PACK_CHUNK_SIZE = 256 * 1024; //256KB
|
||||
|
||||
/**
|
||||
* Larger values allow downloading more chunks at the same time, increasing download speed, but the client may choke
|
||||
* and cause the download speed to drop (due to ACKs taking too long to arrive).
|
||||
*/
|
||||
private const MAX_CONCURRENT_CHUNK_REQUESTS = 1;
|
||||
|
||||
/**
|
||||
* @var ResourcePack[]
|
||||
* @phpstan-var array<string, ResourcePack>
|
||||
*/
|
||||
private array $resourcePacksById = [];
|
||||
|
||||
/** @var bool[][] uuid => [chunk index => hasSent] */
|
||||
private array $downloadedChunks = [];
|
||||
|
||||
/** @phpstan-var \SplQueue<array{ResourcePack, int}> */
|
||||
private \SplQueue $requestQueue;
|
||||
|
||||
private int $activeRequests = 0;
|
||||
|
||||
/**
|
||||
* @param ResourcePack[] $resourcePackStack
|
||||
* @param string[] $encryptionKeys pack UUID => key, leave unset for any packs that are not encrypted
|
||||
*
|
||||
* @phpstan-param list<ResourcePack> $resourcePackStack
|
||||
* @phpstan-param array<string, string> $encryptionKeys
|
||||
* @phpstan-param \Closure() : void $completionCallback
|
||||
*/
|
||||
public function __construct(
|
||||
private NetworkSession $session,
|
||||
private ResourcePackManager $resourcePackManager,
|
||||
private array $resourcePackStack,
|
||||
private array $encryptionKeys,
|
||||
private bool $mustAccept,
|
||||
private \Closure $completionCallback
|
||||
){}
|
||||
){
|
||||
$this->requestQueue = new \SplQueue();
|
||||
foreach($resourcePackStack as $pack){
|
||||
$this->resourcePacksById[$pack->getPackId()] = $pack;
|
||||
}
|
||||
}
|
||||
|
||||
private function getPackById(string $id) : ?ResourcePack{
|
||||
return $this->resourcePacksById[strtolower($id)] ?? null;
|
||||
}
|
||||
|
||||
public function setUp() : void{
|
||||
$resourcePackEntries = array_map(function(ResourcePack $pack) : ResourcePackInfoEntry{
|
||||
//TODO: more stuff
|
||||
$encryptionKey = $this->resourcePackManager->getPackEncryptionKey($pack->getPackId());
|
||||
|
||||
return new ResourcePackInfoEntry(
|
||||
$pack->getPackId(),
|
||||
$pack->getPackVersion(),
|
||||
$pack->getPackSize(),
|
||||
$encryptionKey ?? "",
|
||||
$this->encryptionKeys[$pack->getPackId()] ?? "",
|
||||
"",
|
||||
$pack->getPackId(),
|
||||
false
|
||||
);
|
||||
}, $this->resourcePackManager->getResourceStack());
|
||||
}, $this->resourcePackStack);
|
||||
//TODO: support forcing server packs
|
||||
$this->session->sendDataPacket(ResourcePacksInfoPacket::create($resourcePackEntries, [], $this->resourcePackManager->resourcePacksRequired(), false, false, []));
|
||||
$this->session->sendDataPacket(ResourcePacksInfoPacket::create(
|
||||
resourcePackEntries: $resourcePackEntries,
|
||||
behaviorPackEntries: [],
|
||||
mustAccept: $this->mustAccept,
|
||||
hasAddons: false,
|
||||
hasScripts: false,
|
||||
forceServerPacks: false,
|
||||
cdnUrls: []
|
||||
));
|
||||
$this->session->getLogger()->debug("Waiting for client to accept resource packs");
|
||||
}
|
||||
|
||||
@ -104,11 +145,11 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
||||
if($splitPos !== false){
|
||||
$uuid = substr($uuid, 0, $splitPos);
|
||||
}
|
||||
$pack = $this->resourcePackManager->getPackById($uuid);
|
||||
$pack = $this->getPackById($uuid);
|
||||
|
||||
if(!($pack instanceof ResourcePack)){
|
||||
//Client requested a resource pack but we don't have it available on the server
|
||||
$this->disconnectWithError("Unknown pack $uuid requested, available packs: " . implode(", ", $this->resourcePackManager->getPackIdList()));
|
||||
$this->disconnectWithError("Unknown pack $uuid requested, available packs: " . implode(", ", array_keys($this->resourcePacksById)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -128,7 +169,7 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
||||
case ResourcePackClientResponsePacket::STATUS_HAVE_ALL_PACKS:
|
||||
$stack = array_map(static function(ResourcePack $pack) : ResourcePackStackEntry{
|
||||
return new ResourcePackStackEntry($pack->getPackId(), $pack->getPackVersion(), ""); //TODO: subpacks
|
||||
}, $this->resourcePackManager->getResourceStack());
|
||||
}, $this->resourcePackStack);
|
||||
|
||||
//we support chemistry blocks by default, the client should already have this installed
|
||||
$stack[] = new ResourcePackStackEntry("0fba4063-dba1-4281-9b89-ff9390653530", "1.0.0", "");
|
||||
@ -151,9 +192,9 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
public function handleResourcePackChunkRequest(ResourcePackChunkRequestPacket $packet) : bool{
|
||||
$pack = $this->resourcePackManager->getPackById($packet->packId);
|
||||
$pack = $this->getPackById($packet->packId);
|
||||
if(!($pack instanceof ResourcePack)){
|
||||
$this->disconnectWithError("Invalid request for chunk $packet->chunkIndex of unknown pack $packet->packId, available packs: " . implode(", ", $this->resourcePackManager->getPackIdList()));
|
||||
$this->disconnectWithError("Invalid request for chunk $packet->chunkIndex of unknown pack $packet->packId, available packs: " . implode(", ", array_keys($this->resourcePacksById)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -176,8 +217,37 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
||||
$this->downloadedChunks[$packId][$packet->chunkIndex] = true;
|
||||
}
|
||||
|
||||
$this->session->sendDataPacket(ResourcePackChunkDataPacket::create($packId, $packet->chunkIndex, $offset, $pack->getPackChunk($offset, self::PACK_CHUNK_SIZE)));
|
||||
$this->requestQueue->enqueue([$pack, $packet->chunkIndex]);
|
||||
$this->processChunkRequestQueue();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function processChunkRequestQueue() : void{
|
||||
if($this->activeRequests >= self::MAX_CONCURRENT_CHUNK_REQUESTS || $this->requestQueue->isEmpty()){
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* @var ResourcePack $pack
|
||||
* @var int $chunkIndex
|
||||
*/
|
||||
[$pack, $chunkIndex] = $this->requestQueue->dequeue();
|
||||
|
||||
$packId = $pack->getPackId();
|
||||
$offset = $chunkIndex * self::PACK_CHUNK_SIZE;
|
||||
$chunkData = $pack->getPackChunk($offset, self::PACK_CHUNK_SIZE);
|
||||
$this->activeRequests++;
|
||||
$this->session
|
||||
->sendDataPacketWithReceipt(ResourcePackChunkDataPacket::create($packId, $chunkIndex, $offset, $chunkData))
|
||||
->onCompletion(
|
||||
function() : void{
|
||||
$this->activeRequests--;
|
||||
$this->processChunkRequestQueue();
|
||||
},
|
||||
function() : void{
|
||||
//this may have been rejected because of a disconnection - this will do nothing in that case
|
||||
$this->disconnectWithError("Plugin interrupted sending of resource packs");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\PacketBroadcaster;
|
||||
use pocketmine\network\mcpe\protocol\PacketPool;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\Network;
|
||||
use pocketmine\network\NetworkInterfaceStartException;
|
||||
use pocketmine\network\PacketHandlingException;
|
||||
@ -84,7 +83,6 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
|
||||
private PacketBroadcaster $packetBroadcaster;
|
||||
private EntityEventBroadcaster $entityEventBroadcaster;
|
||||
private PacketSerializerContext $packetSerializerContext;
|
||||
private TypeConverter $typeConverter;
|
||||
|
||||
public function __construct(
|
||||
@ -94,12 +92,10 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
bool $ipV6,
|
||||
PacketBroadcaster $packetBroadcaster,
|
||||
EntityEventBroadcaster $entityEventBroadcaster,
|
||||
PacketSerializerContext $packetSerializerContext,
|
||||
TypeConverter $typeConverter
|
||||
){
|
||||
$this->server = $server;
|
||||
$this->packetBroadcaster = $packetBroadcaster;
|
||||
$this->packetSerializerContext = $packetSerializerContext;
|
||||
$this->entityEventBroadcaster = $entityEventBroadcaster;
|
||||
$this->typeConverter = $typeConverter;
|
||||
|
||||
@ -192,7 +188,6 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
$this->server,
|
||||
$this->network->getSessionManager(),
|
||||
PacketPool::getInstance(),
|
||||
$this->packetSerializerContext,
|
||||
new RakLibPacketSender($sessionId, $this),
|
||||
$this->packetBroadcaster,
|
||||
$this->entityEventBroadcaster,
|
||||
@ -257,7 +252,9 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
}
|
||||
|
||||
public function onPacketAck(int $sessionId, int $identifierACK) : void{
|
||||
|
||||
if(isset($this->sessions[$sessionId])){
|
||||
$this->sessions[$sessionId]->handleAckReceipt($identifierACK);
|
||||
}
|
||||
}
|
||||
|
||||
public function setName(string $name) : void{
|
||||
@ -294,12 +291,13 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
$this->network->getBandwidthTracker()->add($bytesSentDiff, $bytesReceivedDiff);
|
||||
}
|
||||
|
||||
public function putPacket(int $sessionId, string $payload, bool $immediate = true) : void{
|
||||
public function putPacket(int $sessionId, string $payload, bool $immediate = true, ?int $receiptId = null) : void{
|
||||
if(isset($this->sessions[$sessionId])){
|
||||
$pk = new EncapsulatedPacket();
|
||||
$pk->buffer = self::MCPE_RAKNET_PACKET_ID . $payload;
|
||||
$pk->reliability = PacketReliability::RELIABLE_ORDERED;
|
||||
$pk->orderChannel = 0;
|
||||
$pk->identifierACK = $receiptId;
|
||||
|
||||
$this->interface->sendEncapsulated($sessionId, $pk, $immediate);
|
||||
}
|
||||
|
@ -33,9 +33,9 @@ class RakLibPacketSender implements PacketSender{
|
||||
private RakLibInterface $handler
|
||||
){}
|
||||
|
||||
public function send(string $payload, bool $immediate) : void{
|
||||
public function send(string $payload, bool $immediate, ?int $receiptId) : void{
|
||||
if(!$this->closed){
|
||||
$this->handler->putPacket($this->sessionId, $payload, $immediate);
|
||||
$this->handler->putPacket($this->sessionId, $payload, $immediate, $receiptId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,8 @@ class RakLibServer extends Thread{
|
||||
new SimpleProtocolAcceptor($this->protocolVersion),
|
||||
new UserToRakLibThreadMessageReceiver(new PthreadsChannelReader($this->mainToThreadBuffer)),
|
||||
new RakLibToUserThreadMessageSender(new SnoozeAwarePthreadsChannelWriter($this->threadToMainBuffer, $this->sleeperEntry->createNotifier())),
|
||||
new ExceptionTraceCleaner($this->mainPath)
|
||||
new ExceptionTraceCleaner($this->mainPath),
|
||||
recvMaxSplitParts: 512
|
||||
);
|
||||
$this->synchronized(function() : void{
|
||||
$this->ready = true;
|
||||
|
@ -30,7 +30,6 @@ use pocketmine\nbt\TreeRoot;
|
||||
use pocketmine\network\mcpe\convert\BlockTranslator;
|
||||
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
@ -84,8 +83,8 @@ final class ChunkSerializer{
|
||||
/**
|
||||
* @phpstan-param DimensionIds::* $dimensionId
|
||||
*/
|
||||
public static function serializeFullChunk(Chunk $chunk, int $dimensionId, BlockTranslator $blockTranslator, PacketSerializerContext $encoderContext, ?string $tiles = null) : string{
|
||||
$stream = PacketSerializer::encoder($encoderContext);
|
||||
public static function serializeFullChunk(Chunk $chunk, int $dimensionId, BlockTranslator $blockTranslator, ?string $tiles = null) : string{
|
||||
$stream = PacketSerializer::encoder();
|
||||
|
||||
$subChunkCount = self::getSubChunkCount($chunk, $dimensionId);
|
||||
$writtenCount = 0;
|
||||
|
@ -635,6 +635,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$this->displayName = $ev->getNewName();
|
||||
}
|
||||
|
||||
public function canBeRenamed() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the player's locale, e.g. en_US.
|
||||
*/
|
||||
@ -1394,7 +1398,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
public function setMotion(Vector3 $motion) : bool{
|
||||
if(parent::setMotion($motion)){
|
||||
$this->broadcastMotion();
|
||||
$this->getNetworkSession()->sendDataPacket(SetActorMotionPacket::create($this->id, $motion));
|
||||
$this->getNetworkSession()->sendDataPacket(SetActorMotionPacket::create($this->id, $motion, tick: 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -637,6 +637,11 @@ class PluginManager{
|
||||
|
||||
$handlerName = Utils::getNiceClosureName($handler);
|
||||
|
||||
$reflect = new \ReflectionFunction($handler);
|
||||
if($reflect->isGenerator()){
|
||||
throw new PluginException("Generator function $handlerName cannot be used as an event handler");
|
||||
}
|
||||
|
||||
if(!$plugin->isEnabled()){
|
||||
throw new PluginException("Plugin attempted to register event handler " . $handlerName . "() to event " . $event . " while not enabled");
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ class ZippedResourcePack implements ResourcePack{
|
||||
|
||||
$mapper = new \JsonMapper();
|
||||
$mapper->bExceptionOnMissingData = true;
|
||||
$mapper->bStrictObjectTypeChecking = true;
|
||||
|
||||
try{
|
||||
/** @var Manifest $manifest */
|
||||
|
@ -55,6 +55,7 @@ class UpdateCheckTask extends AsyncTask{
|
||||
}else{
|
||||
$mapper = new \JsonMapper();
|
||||
$mapper->bExceptionOnMissingData = true;
|
||||
$mapper->bStrictObjectTypeChecking = true;
|
||||
$mapper->bEnforceMapType = false;
|
||||
try{
|
||||
/** @var UpdateInfo $responseObj */
|
||||
|
@ -111,6 +111,13 @@ trait RegistryTrait{
|
||||
if(count($arguments) > 0){
|
||||
throw new \ArgumentCountError("Expected exactly 0 arguments, " . count($arguments) . " passed");
|
||||
}
|
||||
|
||||
//fast path
|
||||
if(self::$members !== null && isset(self::$members[$name])){
|
||||
return self::preprocessMember(self::$members[$name]);
|
||||
}
|
||||
|
||||
//fallback
|
||||
try{
|
||||
return self::_registryFromString($name);
|
||||
}catch(\InvalidArgumentException $e){
|
||||
|
@ -173,16 +173,17 @@ final class Utils{
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-template T of object
|
||||
* @phpstan-template TKey of array-key
|
||||
* @phpstan-template TValue of object
|
||||
*
|
||||
* @param object[] $array
|
||||
* @phpstan-param T[] $array
|
||||
* @phpstan-param array<TKey, TValue> $array
|
||||
*
|
||||
* @return object[]
|
||||
* @phpstan-return T[]
|
||||
* @phpstan-return array<TKey, TValue>
|
||||
*/
|
||||
public static function cloneObjectArray(array $array) : array{
|
||||
/** @phpstan-var \Closure(T) : T $callback */
|
||||
/** @phpstan-var \Closure(TValue) : TValue $callback */
|
||||
$callback = self::cloneCallback();
|
||||
return array_map($callback, $array);
|
||||
}
|
||||
|
@ -31,7 +31,9 @@ use pocketmine\world\format\io\exception\CorruptedWorldException;
|
||||
use pocketmine\world\format\io\exception\UnsupportedWorldFormatException;
|
||||
use pocketmine\world\format\PalettedBlockArray;
|
||||
use pocketmine\world\WorldException;
|
||||
use function count;
|
||||
use function file_exists;
|
||||
use function implode;
|
||||
|
||||
abstract class BaseWorldProvider implements WorldProvider{
|
||||
protected WorldData $worldData;
|
||||
@ -62,27 +64,35 @@ abstract class BaseWorldProvider implements WorldProvider{
|
||||
*/
|
||||
abstract protected function loadLevelData() : WorldData;
|
||||
|
||||
private function translatePalette(PalettedBlockArray $blockArray) : PalettedBlockArray{
|
||||
private function translatePalette(PalettedBlockArray $blockArray, \Logger $logger) : PalettedBlockArray{
|
||||
$palette = $blockArray->getPalette();
|
||||
|
||||
$newPalette = [];
|
||||
$blockDecodeErrors = [];
|
||||
foreach($palette as $k => $legacyIdMeta){
|
||||
//TODO: remember data for unknown states so we can implement them later
|
||||
$id = $legacyIdMeta >> 4;
|
||||
$meta = $legacyIdMeta & 0xf;
|
||||
try{
|
||||
$newStateData = $this->blockDataUpgrader->upgradeIntIdMeta($legacyIdMeta >> 4, $legacyIdMeta & 0xf);
|
||||
$newStateData = $this->blockDataUpgrader->upgradeIntIdMeta($id, $meta);
|
||||
}catch(BlockStateDeserializeException $e){
|
||||
$blockDecodeErrors[] = "Palette offset $k / Failed to upgrade legacy ID/meta $id:$meta: " . $e->getMessage();
|
||||
$newStateData = GlobalBlockStateHandlers::getUnknownBlockStateData();
|
||||
}
|
||||
|
||||
try{
|
||||
$newPalette[$k] = $this->blockStateDeserializer->deserialize($newStateData);
|
||||
}catch(BlockStateDeserializeException){
|
||||
//TODO: this needs to be logged
|
||||
//TODO: maybe we can remember unknown states for later saving instead of discarding them and destroying maps...
|
||||
}catch(BlockStateDeserializeException $e){
|
||||
//this should never happen anyway - if the upgrader returned an invalid state, we have bigger problems
|
||||
$blockDecodeErrors[] = "Palette offset $k / Failed to deserialize upgraded state $id:$meta: " . $e->getMessage();
|
||||
$newPalette[$k] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
|
||||
}
|
||||
}
|
||||
|
||||
if(count($blockDecodeErrors) > 0){
|
||||
$logger->error("Errors decoding/upgrading blocks:\n - " . implode("\n - ", $blockDecodeErrors));
|
||||
}
|
||||
|
||||
//TODO: this is sub-optimal since it reallocates the offset table multiple times
|
||||
return PalettedBlockArray::fromData(
|
||||
$blockArray->getBitsPerBlock(),
|
||||
@ -91,16 +101,16 @@ abstract class BaseWorldProvider implements WorldProvider{
|
||||
);
|
||||
}
|
||||
|
||||
protected function palettizeLegacySubChunkXZY(string $idArray, string $metaArray) : PalettedBlockArray{
|
||||
return $this->translatePalette(SubChunkConverter::convertSubChunkXZY($idArray, $metaArray));
|
||||
protected function palettizeLegacySubChunkXZY(string $idArray, string $metaArray, \Logger $logger) : PalettedBlockArray{
|
||||
return $this->translatePalette(SubChunkConverter::convertSubChunkXZY($idArray, $metaArray), $logger);
|
||||
}
|
||||
|
||||
protected function palettizeLegacySubChunkYZX(string $idArray, string $metaArray) : PalettedBlockArray{
|
||||
return $this->translatePalette(SubChunkConverter::convertSubChunkYZX($idArray, $metaArray));
|
||||
protected function palettizeLegacySubChunkYZX(string $idArray, string $metaArray, \Logger $logger) : PalettedBlockArray{
|
||||
return $this->translatePalette(SubChunkConverter::convertSubChunkYZX($idArray, $metaArray), $logger);
|
||||
}
|
||||
|
||||
protected function palettizeLegacySubChunkFromColumn(string $idArray, string $metaArray, int $yOffset) : PalettedBlockArray{
|
||||
return $this->translatePalette(SubChunkConverter::convertSubChunkFromLegacyColumn($idArray, $metaArray, $yOffset));
|
||||
protected function palettizeLegacySubChunkFromColumn(string $idArray, string $metaArray, int $yOffset, \Logger $logger) : PalettedBlockArray{
|
||||
return $this->translatePalette(SubChunkConverter::convertSubChunkFromLegacyColumn($idArray, $metaArray, $yOffset), $logger);
|
||||
}
|
||||
|
||||
public function getPath() : string{
|
||||
|
@ -51,12 +51,12 @@ use function time;
|
||||
class BedrockWorldData extends BaseNbtWorldData{
|
||||
|
||||
public const CURRENT_STORAGE_VERSION = 10;
|
||||
public const CURRENT_STORAGE_NETWORK_VERSION = 649;
|
||||
public const CURRENT_STORAGE_NETWORK_VERSION = 662;
|
||||
public const CURRENT_CLIENT_VERSION_TARGET = [
|
||||
1, //major
|
||||
20, //minor
|
||||
60, //patch
|
||||
4, //revision
|
||||
71, //patch
|
||||
1, //revision
|
||||
0 //is beta
|
||||
];
|
||||
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\world\format\io\leveldb;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\data\bedrock\BiomeIds;
|
||||
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
|
||||
use pocketmine\data\bedrock\block\convert\UnsupportedBlockStateException;
|
||||
use pocketmine\nbt\LittleEndianNbtSerializer;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\NbtDataException;
|
||||
@ -58,6 +59,7 @@ use function count;
|
||||
use function defined;
|
||||
use function extension_loaded;
|
||||
use function file_exists;
|
||||
use function implode;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function ord;
|
||||
@ -184,6 +186,8 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
||||
$paletteSize = $stream->getLInt();
|
||||
}
|
||||
|
||||
$blockDecodeErrors = [];
|
||||
|
||||
for($i = 0; $i < $paletteSize; ++$i){
|
||||
try{
|
||||
$offset = $stream->getOffset();
|
||||
@ -199,18 +203,25 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
||||
$blockStateData = $this->blockDataUpgrader->upgradeBlockStateNbt($blockStateNbt);
|
||||
}catch(BlockStateDeserializeException $e){
|
||||
//while not ideal, this is not a fatal error
|
||||
$logger->error("Failed to upgrade blockstate: " . $e->getMessage() . " offset $i in palette, blockstate NBT: " . $blockStateNbt->toString());
|
||||
$blockDecodeErrors[] = "Palette offset $i / Upgrade error: " . $e->getMessage() . ", NBT: " . $blockStateNbt->toString();
|
||||
$palette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
|
||||
continue;
|
||||
}
|
||||
try{
|
||||
$palette[] = $this->blockStateDeserializer->deserialize($blockStateData);
|
||||
}catch(UnsupportedBlockStateException $e){
|
||||
$blockDecodeErrors[] = "Palette offset $i / " . $e->getMessage();
|
||||
$palette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
|
||||
}catch(BlockStateDeserializeException $e){
|
||||
$logger->error("Failed to deserialize blockstate: " . $e->getMessage() . " offset $i in palette, blockstate NBT: " . $blockStateNbt->toString());
|
||||
$blockDecodeErrors[] = "Palette offset $i / Deserialize error: " . $e->getMessage() . ", NBT: " . $blockStateNbt->toString();
|
||||
$palette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
|
||||
}
|
||||
}
|
||||
|
||||
if(count($blockDecodeErrors) > 0){
|
||||
$logger->error("Errors decoding blocks:\n - " . implode("\n - ", $blockDecodeErrors));
|
||||
}
|
||||
|
||||
//TODO: exceptions
|
||||
return PalettedBlockArray::fromData($bitsPerBlock, $words, $palette);
|
||||
}
|
||||
@ -443,7 +454,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
||||
|
||||
$subChunks = [];
|
||||
for($yy = 0; $yy < 8; ++$yy){
|
||||
$storages = [$this->palettizeLegacySubChunkFromColumn($fullIds, $fullData, $yy)];
|
||||
$storages = [$this->palettizeLegacySubChunkFromColumn($fullIds, $fullData, $yy, new \PrefixedLogger($logger, "Subchunk y=$yy"))];
|
||||
if(isset($convertedLegacyExtraData[$yy])){
|
||||
$storages[] = $convertedLegacyExtraData[$yy];
|
||||
}
|
||||
@ -482,7 +493,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
||||
}
|
||||
}
|
||||
|
||||
$storages = [$this->palettizeLegacySubChunkXZY($blocks, $blockData)];
|
||||
$storages = [$this->palettizeLegacySubChunkXZY($blocks, $blockData, $logger)];
|
||||
if($convertedLegacyExtraData !== null){
|
||||
$storages[] = $convertedLegacyExtraData;
|
||||
}
|
||||
|
@ -31,10 +31,11 @@ use pocketmine\world\format\SubChunk;
|
||||
class Anvil extends RegionWorldProvider{
|
||||
use LegacyAnvilChunkTrait;
|
||||
|
||||
protected function deserializeSubChunk(CompoundTag $subChunk, PalettedBlockArray $biomes3d) : SubChunk{
|
||||
protected function deserializeSubChunk(CompoundTag $subChunk, PalettedBlockArray $biomes3d, \Logger $logger) : SubChunk{
|
||||
return new SubChunk(Block::EMPTY_STATE_ID, [$this->palettizeLegacySubChunkYZX(
|
||||
self::readFixedSizeByteArray($subChunk, "Blocks", 4096),
|
||||
self::readFixedSizeByteArray($subChunk, "Data", 2048)
|
||||
self::readFixedSizeByteArray($subChunk, "Data", 2048),
|
||||
$logger
|
||||
)], $biomes3d);
|
||||
//ignore legacy light information
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ trait LegacyAnvilChunkTrait{
|
||||
/**
|
||||
* @throws CorruptedChunkException
|
||||
*/
|
||||
protected function deserializeChunk(string $data) : ?LoadedChunkData{
|
||||
protected function deserializeChunk(string $data, \Logger $logger) : ?LoadedChunkData{
|
||||
$decompressed = @zlib_decode($data);
|
||||
if($decompressed === false){
|
||||
throw new CorruptedChunkException("Failed to decompress chunk NBT");
|
||||
@ -90,7 +90,8 @@ trait LegacyAnvilChunkTrait{
|
||||
$subChunksTag = $chunk->getListTag("Sections") ?? [];
|
||||
foreach($subChunksTag as $subChunk){
|
||||
if($subChunk instanceof CompoundTag){
|
||||
$subChunks[$subChunk->getByte("Y")] = $this->deserializeSubChunk($subChunk, clone $biomes3d);
|
||||
$y = $subChunk->getByte("Y");
|
||||
$subChunks[$y] = $this->deserializeSubChunk($subChunk, clone $biomes3d, new \PrefixedLogger($logger, "Subchunk y=$y"));
|
||||
}
|
||||
}
|
||||
for($y = Chunk::MIN_SUBCHUNK_INDEX; $y <= Chunk::MAX_SUBCHUNK_INDEX; ++$y){
|
||||
@ -111,6 +112,6 @@ trait LegacyAnvilChunkTrait{
|
||||
);
|
||||
}
|
||||
|
||||
abstract protected function deserializeSubChunk(CompoundTag $subChunk, PalettedBlockArray $biomes3d) : SubChunk;
|
||||
abstract protected function deserializeSubChunk(CompoundTag $subChunk, PalettedBlockArray $biomes3d, \Logger $logger) : SubChunk;
|
||||
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class McRegion extends RegionWorldProvider{
|
||||
/**
|
||||
* @throws CorruptedChunkException
|
||||
*/
|
||||
protected function deserializeChunk(string $data) : ?LoadedChunkData{
|
||||
protected function deserializeChunk(string $data, \Logger $logger) : ?LoadedChunkData{
|
||||
$decompressed = @zlib_decode($data);
|
||||
if($decompressed === false){
|
||||
throw new CorruptedChunkException("Failed to decompress chunk NBT");
|
||||
@ -90,7 +90,12 @@ class McRegion extends RegionWorldProvider{
|
||||
$fullData = self::readFixedSizeByteArray($chunk, "Data", 16384);
|
||||
|
||||
for($y = 0; $y < 8; ++$y){
|
||||
$subChunks[$y] = new SubChunk(Block::EMPTY_STATE_ID, [$this->palettizeLegacySubChunkFromColumn($fullIds, $fullData, $y)], clone $biomes3d);
|
||||
$subChunks[$y] = new SubChunk(Block::EMPTY_STATE_ID, [$this->palettizeLegacySubChunkFromColumn(
|
||||
$fullIds,
|
||||
$fullData,
|
||||
$y,
|
||||
new \PrefixedLogger($logger, "Subchunk y=$y"),
|
||||
)], clone $biomes3d);
|
||||
}
|
||||
for($y = Chunk::MIN_SUBCHUNK_INDEX; $y <= Chunk::MAX_SUBCHUNK_INDEX; ++$y){
|
||||
if(!isset($subChunks[$y])){
|
||||
|
@ -35,10 +35,11 @@ use pocketmine\world\format\SubChunk;
|
||||
class PMAnvil extends RegionWorldProvider{
|
||||
use LegacyAnvilChunkTrait;
|
||||
|
||||
protected function deserializeSubChunk(CompoundTag $subChunk, PalettedBlockArray $biomes3d) : SubChunk{
|
||||
protected function deserializeSubChunk(CompoundTag $subChunk, PalettedBlockArray $biomes3d, \Logger $logger) : SubChunk{
|
||||
return new SubChunk(Block::EMPTY_STATE_ID, [$this->palettizeLegacySubChunkXZY(
|
||||
self::readFixedSizeByteArray($subChunk, "Blocks", 4096),
|
||||
self::readFixedSizeByteArray($subChunk, "Data", 2048)
|
||||
self::readFixedSizeByteArray($subChunk, "Data", 2048),
|
||||
$logger
|
||||
)], $biomes3d);
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
|
||||
/**
|
||||
* @throws CorruptedChunkException
|
||||
*/
|
||||
abstract protected function deserializeChunk(string $data) : ?LoadedChunkData;
|
||||
abstract protected function deserializeChunk(string $data, \Logger $logger) : ?LoadedChunkData;
|
||||
|
||||
/**
|
||||
* @return CompoundTag[]
|
||||
@ -200,7 +200,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
|
||||
|
||||
$chunkData = $this->loadRegion($regionX, $regionZ)->readChunk($chunkX & 0x1f, $chunkZ & 0x1f);
|
||||
if($chunkData !== null){
|
||||
return $this->deserializeChunk($chunkData);
|
||||
return $this->deserializeChunk($chunkData, new \PrefixedLogger($this->logger, "Loading chunk x=$chunkX z=$chunkZ"));
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -650,6 +650,11 @@ parameters:
|
||||
count: 2
|
||||
path: ../../../src/network/mcpe/NetworkSession.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$playerInfo of class pocketmine\\\\event\\\\player\\\\PlayerResourcePackOfferEvent constructor expects pocketmine\\\\player\\\\PlayerInfo, pocketmine\\\\player\\\\PlayerInfo\\|null given\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/network/mcpe/NetworkSession.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$target of method pocketmine\\\\command\\\\Command\\:\\:testPermissionSilent\\(\\) expects pocketmine\\\\command\\\\CommandSender, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
||||
count: 1
|
||||
|
@ -47,11 +47,11 @@ class BlockStateUpgraderTest extends TestCase{
|
||||
}
|
||||
|
||||
private function getNewSchema() : BlockStateUpgradeSchema{
|
||||
return $this->getNewSchemaVersion(PHP_INT_MAX);
|
||||
return $this->getNewSchemaVersion(PHP_INT_MAX, 0);
|
||||
}
|
||||
|
||||
private function getNewSchemaVersion(int $versionId) : BlockStateUpgradeSchema{
|
||||
$schema = new BlockStateUpgradeSchema(($versionId >> 24) & 0xff, ($versionId >> 16) & 0xff, ($versionId >> 8) & 0xff, $versionId & 0xff, 0);
|
||||
private function getNewSchemaVersion(int $versionId, int $schemaId) : BlockStateUpgradeSchema{
|
||||
$schema = new BlockStateUpgradeSchema(($versionId >> 24) & 0xff, ($versionId >> 16) & 0xff, ($versionId >> 8) & 0xff, $versionId & 0xff, $schemaId);
|
||||
$this->upgrader->addSchema($schema);
|
||||
return $schema;
|
||||
}
|
||||
@ -211,20 +211,23 @@ class BlockStateUpgraderTest extends TestCase{
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-return \Generator<int, array{int, int, bool}, void, void>
|
||||
* @phpstan-return \Generator<int, array{int, int, bool, int}, void, void>
|
||||
*/
|
||||
public static function upgraderVersionCompatibilityProvider() : \Generator{
|
||||
yield [0x1_00_00_00, 0x1_00_00_00, true]; //Same version: must be altered - this may be a backwards-compatible change that Mojang didn't bother to bump for
|
||||
yield [0x1_00_01_00, 0x1_00_00_00, true]; //Schema newer than block: must be altered
|
||||
yield [0x1_00_00_00, 0x1_00_01_00, false]; //Block newer than schema: block must NOT be altered
|
||||
yield [0x1_00_00_00, 0x1_00_00_00, true, 2]; //Same version, multiple schemas targeting version - must be altered, we don't know which schemas are applicable
|
||||
yield [0x1_00_00_00, 0x1_00_00_00, false, 1]; //Same version, one schema targeting version - do not change
|
||||
yield [0x1_00_01_00, 0x1_00_00_00, true, 1]; //Schema newer than block: must be altered
|
||||
yield [0x1_00_00_00, 0x1_00_01_00, false, 1]; //Block newer than schema: block must NOT be altered
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider upgraderVersionCompatibilityProvider
|
||||
*/
|
||||
public function testUpgraderVersionCompatibility(int $schemaVersion, int $stateVersion, bool $shouldChange) : void{
|
||||
$schema = $this->getNewSchemaVersion($schemaVersion);
|
||||
public function testUpgraderVersionCompatibility(int $schemaVersion, int $stateVersion, bool $shouldChange, int $schemaCount) : void{
|
||||
for($i = 0; $i < $schemaCount; $i++){
|
||||
$schema = $this->getNewSchemaVersion($schemaVersion, $i);
|
||||
$schema->renamedIds[self::TEST_BLOCK] = self::TEST_BLOCK_2;
|
||||
}
|
||||
|
||||
$getStateData = fn() => new BlockStateData(
|
||||
self::TEST_BLOCK,
|
||||
|
@ -34,6 +34,7 @@ use pocketmine\crafting\json\SmithingTransformRecipeData;
|
||||
use pocketmine\crafting\json\SmithingTrimRecipeData;
|
||||
use pocketmine\data\bedrock\block\BlockStateData;
|
||||
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
||||
use pocketmine\data\bedrock\item\ItemTypeNames;
|
||||
use pocketmine\nbt\LittleEndianNbtSerializer;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
@ -50,12 +51,12 @@ use pocketmine\network\mcpe\protocol\CreativeContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\PacketPool;
|
||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\StartGamePacket;
|
||||
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\ItemTypeEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackExtraData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackExtraDataShield;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\ComplexAliasItemDescriptor;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\IntIdMetaItemDescriptor;
|
||||
@ -170,16 +171,21 @@ class ParserPacketHandler extends PacketHandler{
|
||||
$data->meta = $meta;
|
||||
}
|
||||
|
||||
$nbt = $itemStack->getNbt();
|
||||
$rawExtraData = $itemStack->getRawExtraData();
|
||||
if($rawExtraData !== ""){
|
||||
$decoder = PacketSerializer::decoder($rawExtraData, 0);
|
||||
$extraData = $itemStringId === ItemTypeNames::SHIELD ? ItemStackExtraDataShield::read($decoder) : ItemStackExtraData::read($decoder);
|
||||
$nbt = $extraData->getNbt();
|
||||
if($nbt !== null && count($nbt) > 0){
|
||||
$data->nbt = base64_encode((new LittleEndianNbtSerializer())->write(new TreeRoot($nbt)));
|
||||
}
|
||||
|
||||
if(count($itemStack->getCanPlaceOn()) > 0){
|
||||
$data->can_place_on = $itemStack->getCanPlaceOn();
|
||||
if(count($extraData->getCanPlaceOn()) > 0){
|
||||
$data->can_place_on = $extraData->getCanPlaceOn();
|
||||
}
|
||||
if(count($extraData->getCanDestroy()) > 0){
|
||||
$data->can_destroy = $extraData->getCanDestroy();
|
||||
}
|
||||
if(count($itemStack->getCanDestroy()) > 0){
|
||||
$data->can_destroy = $itemStack->getCanDestroy();
|
||||
}
|
||||
|
||||
return $data;
|
||||
@ -421,7 +427,7 @@ class ParserPacketHandler extends PacketHandler{
|
||||
$recipes["potion_type"][] = new PotionTypeRecipeData(
|
||||
$this->recipeIngredientToJson(new RecipeIngredient(new IntIdMetaItemDescriptor($recipe->getInputItemId(), $recipe->getInputItemMeta()), 1)),
|
||||
$this->recipeIngredientToJson(new RecipeIngredient(new IntIdMetaItemDescriptor($recipe->getIngredientItemId(), $recipe->getIngredientItemMeta()), 1)),
|
||||
$this->itemStackToJson(new ItemStack($recipe->getOutputItemId(), $recipe->getOutputItemMeta(), 1, 0, null, [], [], null)),
|
||||
$this->itemStackToJson(new ItemStack($recipe->getOutputItemId(), $recipe->getOutputItemMeta(), 1, 0, "")),
|
||||
);
|
||||
}
|
||||
|
||||
@ -571,10 +577,7 @@ function main(array $argv) : int{
|
||||
fwrite(STDERR, "Unknown packet on line " . ($lineNum + 1) . ": " . $parts[1]);
|
||||
continue;
|
||||
}
|
||||
$serializer = PacketSerializer::decoder($raw, 0, new PacketSerializerContext(
|
||||
$handler->itemTypeDictionary ??
|
||||
new ItemTypeDictionary([new ItemTypeEntry("minecraft:shield", 0, false)]))
|
||||
);
|
||||
$serializer = PacketSerializer::decoder($raw, 0);
|
||||
|
||||
$pk->decode($serializer);
|
||||
$pk->handle($handler);
|
||||
|
Loading…
x
Reference in New Issue
Block a user