mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-14 13:49:57 +00:00
Merge branch 'minor-next' into stable
This commit is contained in:
commit
54ea404d80
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";
|
@ -36,7 +36,7 @@
|
|||||||
"pocketmine/bedrock-block-upgrade-schema": "~3.5.0+bedrock-1.20.60",
|
"pocketmine/bedrock-block-upgrade-schema": "~3.5.0+bedrock-1.20.60",
|
||||||
"pocketmine/bedrock-data": "~2.8.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-item-upgrade-schema": "~1.7.0+bedrock-1.20.60",
|
||||||
"pocketmine/bedrock-protocol": "~27.0.0+bedrock-1.20.60",
|
"pocketmine/bedrock-protocol": "~28.0.0+bedrock-1.20.60",
|
||||||
"pocketmine/binaryutils": "^0.2.1",
|
"pocketmine/binaryutils": "^0.2.1",
|
||||||
"pocketmine/callback-validator": "^1.0.2",
|
"pocketmine/callback-validator": "^1.0.2",
|
||||||
"pocketmine/color": "^0.3.0",
|
"pocketmine/color": "^0.3.0",
|
||||||
|
16
composer.lock
generated
16
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "14848cb7b70d0fa63ed46b30128c2320",
|
"content-hash": "f43d60f8c44393f5c42b7ba27cd8ccc0",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adhocore/json-comment",
|
"name": "adhocore/json-comment",
|
||||||
@ -200,16 +200,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-protocol",
|
"name": "pocketmine/bedrock-protocol",
|
||||||
"version": "27.0.2+bedrock-1.20.60",
|
"version": "28.0.0+bedrock-1.20.60",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||||
"reference": "6905865133b69da8c95a13c563d349e1993c06b8"
|
"reference": "6e73f21cdc7433f0674dfcdf4817f478aa5528e6"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/6905865133b69da8c95a13c563d349e1993c06b8",
|
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/6e73f21cdc7433f0674dfcdf4817f478aa5528e6",
|
||||||
"reference": "6905865133b69da8c95a13c563d349e1993c06b8",
|
"reference": "6e73f21cdc7433f0674dfcdf4817f478aa5528e6",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -222,7 +222,7 @@
|
|||||||
"ramsey/uuid": "^4.1"
|
"ramsey/uuid": "^4.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "1.10.39",
|
"phpstan/phpstan": "1.10.59",
|
||||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||||
"phpunit/phpunit": "^9.5 || ^10.0"
|
"phpunit/phpunit": "^9.5 || ^10.0"
|
||||||
@ -240,9 +240,9 @@
|
|||||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/27.0.2+bedrock-1.20.60"
|
"source": "https://github.com/pmmp/BedrockProtocol/tree/28.0.0+bedrock-1.20.60"
|
||||||
},
|
},
|
||||||
"time": "2024-02-23T13:43:39+00:00"
|
"time": "2024-02-26T16:18:34+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/binaryutils",
|
"name": "pocketmine/binaryutils",
|
||||||
|
@ -45,4 +45,6 @@ final class BootstrapOptions{
|
|||||||
public const PLUGINS = "plugins";
|
public const PLUGINS = "plugins";
|
||||||
/** Path to store and load server data */
|
/** Path to store and load server data */
|
||||||
public const DATA = "data";
|
public const DATA = "data";
|
||||||
|
/** Shows basic server version information and exits */
|
||||||
|
public const VERSION = "version";
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ namespace pocketmine {
|
|||||||
|
|
||||||
use Composer\InstalledVersions;
|
use Composer\InstalledVersions;
|
||||||
use pocketmine\errorhandler\ErrorToExceptionHandler;
|
use pocketmine\errorhandler\ErrorToExceptionHandler;
|
||||||
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
use pocketmine\thread\ThreadManager;
|
use pocketmine\thread\ThreadManager;
|
||||||
use pocketmine\thread\ThreadSafeClassLoader;
|
use pocketmine\thread\ThreadSafeClassLoader;
|
||||||
use pocketmine\utils\Filesystem;
|
use pocketmine\utils\Filesystem;
|
||||||
@ -40,14 +41,17 @@ namespace pocketmine {
|
|||||||
use function extension_loaded;
|
use function extension_loaded;
|
||||||
use function function_exists;
|
use function function_exists;
|
||||||
use function getcwd;
|
use function getcwd;
|
||||||
|
use function getopt;
|
||||||
use function is_dir;
|
use function is_dir;
|
||||||
use function mkdir;
|
use function mkdir;
|
||||||
use function phpversion;
|
use function phpversion;
|
||||||
use function preg_match;
|
use function preg_match;
|
||||||
use function preg_quote;
|
use function preg_quote;
|
||||||
|
use function printf;
|
||||||
use function realpath;
|
use function realpath;
|
||||||
use function version_compare;
|
use function version_compare;
|
||||||
use const DIRECTORY_SEPARATOR;
|
use const DIRECTORY_SEPARATOR;
|
||||||
|
use const PHP_EOL;
|
||||||
|
|
||||||
require_once __DIR__ . '/VersionInfo.php';
|
require_once __DIR__ . '/VersionInfo.php';
|
||||||
|
|
||||||
@ -166,7 +170,7 @@ namespace pocketmine {
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function emit_performance_warnings(\Logger $logger){
|
function emit_performance_warnings(\Logger $logger){
|
||||||
if(PHP_DEBUG !== 0){
|
if(ZEND_DEBUG_BUILD){
|
||||||
$logger->warning("This PHP binary was compiled in debug mode. This has a major impact on performance.");
|
$logger->warning("This PHP binary was compiled in debug mode. This has a major impact on performance.");
|
||||||
}
|
}
|
||||||
if(extension_loaded("xdebug") && (!function_exists('xdebug_info') || count(xdebug_info('mode')) !== 0)){
|
if(extension_loaded("xdebug") && (!function_exists('xdebug_info') || count(xdebug_info('mode')) !== 0)){
|
||||||
@ -273,6 +277,11 @@ JIT_WARNING
|
|||||||
|
|
||||||
ErrorToExceptionHandler::set();
|
ErrorToExceptionHandler::set();
|
||||||
|
|
||||||
|
if(count(getopt("", [BootstrapOptions::VERSION])) > 0){
|
||||||
|
printf("%s %s (git hash %s) for Minecraft: Bedrock Edition %s\n", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(true), VersionInfo::GIT_HASH(), ProtocolInfo::MINECRAFT_VERSION);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
$cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
|
$cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
|
||||||
$dataPath = getopt_string(BootstrapOptions::DATA) ?? $cwd;
|
$dataPath = getopt_string(BootstrapOptions::DATA) ?? $cwd;
|
||||||
$pluginPath = getopt_string(BootstrapOptions::PLUGINS) ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
$pluginPath = getopt_string(BootstrapOptions::PLUGINS) ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
||||||
|
@ -59,7 +59,6 @@ use pocketmine\network\mcpe\EntityEventBroadcaster;
|
|||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
use pocketmine\network\mcpe\PacketBroadcaster;
|
use pocketmine\network\mcpe\PacketBroadcaster;
|
||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm;
|
use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm;
|
||||||
use pocketmine\network\mcpe\raklib\RakLibInterface;
|
use pocketmine\network\mcpe\raklib\RakLibInterface;
|
||||||
use pocketmine\network\mcpe\StandardEntityEventBroadcaster;
|
use pocketmine\network\mcpe\StandardEntityEventBroadcaster;
|
||||||
@ -1187,12 +1186,11 @@ class Server{
|
|||||||
bool $useQuery,
|
bool $useQuery,
|
||||||
PacketBroadcaster $packetBroadcaster,
|
PacketBroadcaster $packetBroadcaster,
|
||||||
EntityEventBroadcaster $entityEventBroadcaster,
|
EntityEventBroadcaster $entityEventBroadcaster,
|
||||||
PacketSerializerContext $packetSerializerContext,
|
|
||||||
TypeConverter $typeConverter
|
TypeConverter $typeConverter
|
||||||
) : bool{
|
) : bool{
|
||||||
$prettyIp = $ipV6 ? "[$ip]" : $ip;
|
$prettyIp = $ipV6 ? "[$ip]" : $ip;
|
||||||
try{
|
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){
|
}catch(NetworkInterfaceStartException $e){
|
||||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
|
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
|
||||||
$ip,
|
$ip,
|
||||||
@ -1219,15 +1217,14 @@ class Server{
|
|||||||
$useQuery = $this->configGroup->getConfigBool(ServerProperties::ENABLE_QUERY, true);
|
$useQuery = $this->configGroup->getConfigBool(ServerProperties::ENABLE_QUERY, true);
|
||||||
|
|
||||||
$typeConverter = TypeConverter::getInstance();
|
$typeConverter = TypeConverter::getInstance();
|
||||||
$packetSerializerContext = new PacketSerializerContext($typeConverter->getItemTypeDictionary());
|
$packetBroadcaster = new StandardPacketBroadcaster($this);
|
||||||
$packetBroadcaster = new StandardPacketBroadcaster($this, $packetSerializerContext);
|
|
||||||
$entityEventBroadcaster = new StandardEntityEventBroadcaster($packetBroadcaster, $typeConverter);
|
$entityEventBroadcaster = new StandardEntityEventBroadcaster($packetBroadcaster, $typeConverter);
|
||||||
|
|
||||||
if(
|
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->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;
|
return false;
|
||||||
|
@ -34,7 +34,6 @@ use pocketmine\math\AxisAlignedBB;
|
|||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\player\Player;
|
use pocketmine\player\Player;
|
||||||
use pocketmine\world\BlockTransaction;
|
use pocketmine\world\BlockTransaction;
|
||||||
use function array_filter;
|
|
||||||
use function assert;
|
use function assert;
|
||||||
use function count;
|
use function count;
|
||||||
|
|
||||||
@ -89,11 +88,12 @@ abstract class BaseBanner extends Transparent{
|
|||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPatterns(array $patterns) : self{
|
public function setPatterns(array $patterns) : self{
|
||||||
$checked = array_filter($patterns, fn($v) => $v instanceof BannerPatternLayer);
|
foreach($patterns as $pattern){
|
||||||
if(count($checked) !== count($patterns)){
|
if(!$pattern instanceof BannerPatternLayer){
|
||||||
throw new \TypeError("Deque must only contain " . BannerPatternLayer::class . " objects");
|
throw new \TypeError("Array must only contain " . BannerPatternLayer::class . " objects");
|
||||||
}
|
}
|
||||||
$this->patterns = $checked;
|
}
|
||||||
|
$this->patterns = $patterns;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,7 +402,7 @@ class Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AKA: Block->isPlaceable
|
* Returns whether this block can be placed when obtained as an item.
|
||||||
*/
|
*/
|
||||||
public function canBePlaced() : bool{
|
public function canBePlaced() : bool{
|
||||||
return true;
|
return true;
|
||||||
@ -572,16 +572,28 @@ class Block{
|
|||||||
return $this->getLightFilter() > 0;
|
return $this->getLightFilter() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this block allows any light to pass through it.
|
||||||
|
*/
|
||||||
public function isTransparent() : bool{
|
public function isTransparent() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated TL;DR: Don't use this function. Its results are confusing and inconsistent.
|
||||||
|
*
|
||||||
|
* No one is sure what the meaning of this property actually is. It's borrowed from Minecraft Java Edition, and is
|
||||||
|
* used by various blocks for support checks.
|
||||||
|
*
|
||||||
|
* Things like signs and banners are considered "solid" despite having no collision box, and things like skulls and
|
||||||
|
* flower pots are considered non-solid despite obviously being "solid" in the conventional, real-world sense.
|
||||||
|
*/
|
||||||
public function isSolid() : bool{
|
public function isSolid() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AKA: Block->isFlowable
|
* Returns whether this block can be destroyed by liquid flowing into its cell.
|
||||||
*/
|
*/
|
||||||
public function canBeFlowedInto() : bool{
|
public function canBeFlowedInto() : bool{
|
||||||
return false;
|
return false;
|
||||||
|
@ -26,7 +26,6 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\block\utils\AgeableTrait;
|
use pocketmine\block\utils\AgeableTrait;
|
||||||
use pocketmine\block\utils\BlockEventHelper;
|
use pocketmine\block\utils\BlockEventHelper;
|
||||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||||
use pocketmine\block\utils\SupportType;
|
|
||||||
use pocketmine\block\utils\WoodType;
|
use pocketmine\block\utils\WoodType;
|
||||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||||
use pocketmine\item\Fertilizer;
|
use pocketmine\item\Fertilizer;
|
||||||
@ -40,7 +39,7 @@ use pocketmine\player\Player;
|
|||||||
use pocketmine\world\BlockTransaction;
|
use pocketmine\world\BlockTransaction;
|
||||||
use function mt_rand;
|
use function mt_rand;
|
||||||
|
|
||||||
class CocoaBlock extends Transparent{
|
class CocoaBlock extends Flowable{
|
||||||
use HorizontalFacingTrait;
|
use HorizontalFacingTrait;
|
||||||
use AgeableTrait;
|
use AgeableTrait;
|
||||||
|
|
||||||
@ -65,10 +64,6 @@ class CocoaBlock extends Transparent{
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSupportType(int $facing) : SupportType{
|
|
||||||
return SupportType::NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function canAttachTo(Block $block) : bool{
|
private function canAttachTo(Block $block) : bool{
|
||||||
return $block instanceof Wood && $block->getWoodType() === WoodType::JUNGLE;
|
return $block instanceof Wood && $block->getWoodType() === WoodType::JUNGLE;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\block\tile\Furnace as TileFurnace;
|
use pocketmine\block\tile\Furnace as TileFurnace;
|
||||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||||
|
use pocketmine\block\utils\LightableTrait;
|
||||||
use pocketmine\crafting\FurnaceType;
|
use pocketmine\crafting\FurnaceType;
|
||||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
@ -34,11 +35,10 @@ use function mt_rand;
|
|||||||
|
|
||||||
class Furnace extends Opaque{
|
class Furnace extends Opaque{
|
||||||
use FacesOppositePlacingPlayerTrait;
|
use FacesOppositePlacingPlayerTrait;
|
||||||
|
use LightableTrait;
|
||||||
|
|
||||||
protected FurnaceType $furnaceType;
|
protected FurnaceType $furnaceType;
|
||||||
|
|
||||||
protected bool $lit = false;
|
|
||||||
|
|
||||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, FurnaceType $furnaceType){
|
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, FurnaceType $furnaceType){
|
||||||
$this->furnaceType = $furnaceType;
|
$this->furnaceType = $furnaceType;
|
||||||
parent::__construct($idInfo, $name, $typeInfo);
|
parent::__construct($idInfo, $name, $typeInfo);
|
||||||
@ -57,18 +57,6 @@ class Furnace extends Opaque{
|
|||||||
return $this->lit ? 13 : 0;
|
return $this->lit ? 13 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isLit() : bool{
|
|
||||||
return $this->lit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setLit(bool $lit = true) : self{
|
|
||||||
$this->lit = $lit;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
$furnace = $this->position->getWorld()->getTile($this->position);
|
$furnace = $this->position->getWorld()->getTile($this->position);
|
||||||
|
@ -24,7 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\utils\FortuneDropHelper;
|
use pocketmine\block\utils\FortuneDropHelper;
|
||||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
use pocketmine\block\utils\LightableTrait;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\VanillaItems;
|
use pocketmine\item\VanillaItems;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
@ -32,23 +32,7 @@ use pocketmine\player\Player;
|
|||||||
use function mt_rand;
|
use function mt_rand;
|
||||||
|
|
||||||
class RedstoneOre extends Opaque{
|
class RedstoneOre extends Opaque{
|
||||||
protected bool $lit = false;
|
use LightableTrait;
|
||||||
|
|
||||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
|
||||||
$w->bool($this->lit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isLit() : bool{
|
|
||||||
return $this->lit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setLit(bool $lit = true) : self{
|
|
||||||
$this->lit = $lit;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLightLevel() : int{
|
public function getLightLevel() : int{
|
||||||
return $this->lit ? 9 : 0;
|
return $this->lit ? 9 : 0;
|
||||||
|
@ -23,28 +23,22 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\block\utils\LightableTrait;
|
||||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||||
|
|
||||||
class RedstoneTorch extends Torch{
|
class RedstoneTorch extends Torch{
|
||||||
protected bool $lit = true;
|
use LightableTrait;
|
||||||
|
|
||||||
|
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
|
||||||
|
$this->lit = true;
|
||||||
|
parent::__construct($idInfo, $name, $typeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||||
parent::describeBlockOnlyState($w);
|
parent::describeBlockOnlyState($w);
|
||||||
$w->bool($this->lit);
|
$w->bool($this->lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isLit() : bool{
|
|
||||||
return $this->lit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setLit(bool $lit = true) : self{
|
|
||||||
$this->lit = $lit;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLightLevel() : int{
|
public function getLightLevel() : int{
|
||||||
return $this->lit ? 7 : 0;
|
return $this->lit ? 7 : 0;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block\utils;
|
namespace pocketmine\block\utils;
|
||||||
|
|
||||||
use pocketmine\block\Block;
|
use pocketmine\block\Block;
|
||||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
|
||||||
use pocketmine\entity\projectile\Projectile;
|
use pocketmine\entity\projectile\Projectile;
|
||||||
use pocketmine\item\Durable;
|
use pocketmine\item\Durable;
|
||||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||||
@ -38,24 +37,12 @@ use pocketmine\world\sound\FireExtinguishSound;
|
|||||||
use pocketmine\world\sound\FlintSteelSound;
|
use pocketmine\world\sound\FlintSteelSound;
|
||||||
|
|
||||||
trait CandleTrait{
|
trait CandleTrait{
|
||||||
private bool $lit = false;
|
use LightableTrait;
|
||||||
|
|
||||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
|
||||||
$w->bool($this->lit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLightLevel() : int{
|
public function getLightLevel() : int{
|
||||||
return $this->lit ? 3 : 0;
|
return $this->lit ? 3 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isLit() : bool{ return $this->lit; }
|
|
||||||
|
|
||||||
/** @return $this */
|
|
||||||
public function setLit(bool $lit) : self{
|
|
||||||
$this->lit = $lit;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see Block::onInteract() */
|
/** @see Block::onInteract() */
|
||||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||||
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE || $item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
|
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE || $item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
|
||||||
|
46
src/block/utils/LightableTrait.php
Normal file
46
src/block/utils/LightableTrait.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?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\block\utils;
|
||||||
|
|
||||||
|
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||||
|
|
||||||
|
trait LightableTrait{
|
||||||
|
protected bool $lit = false;
|
||||||
|
|
||||||
|
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||||
|
$w->bool($this->lit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isLit() : bool{
|
||||||
|
return $this->lit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setLit(bool $lit = true) : self{
|
||||||
|
$this->lit = $lit;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -43,44 +43,48 @@ final class BannerPatternTypeIdMap{
|
|||||||
private array $enumToId = [];
|
private array $enumToId = [];
|
||||||
|
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
$this->register("bo", BannerPatternType::BORDER);
|
foreach(BannerPatternType::cases() as $case){
|
||||||
$this->register("bri", BannerPatternType::BRICKS);
|
$this->register(match($case){
|
||||||
$this->register("mc", BannerPatternType::CIRCLE);
|
BannerPatternType::BORDER => "bo",
|
||||||
$this->register("cre", BannerPatternType::CREEPER);
|
BannerPatternType::BRICKS => "bri",
|
||||||
$this->register("cr", BannerPatternType::CROSS);
|
BannerPatternType::CIRCLE => "mc",
|
||||||
$this->register("cbo", BannerPatternType::CURLY_BORDER);
|
BannerPatternType::CREEPER => "cre",
|
||||||
$this->register("lud", BannerPatternType::DIAGONAL_LEFT);
|
BannerPatternType::CROSS => "cr",
|
||||||
$this->register("rd", BannerPatternType::DIAGONAL_RIGHT);
|
BannerPatternType::CURLY_BORDER => "cbo",
|
||||||
$this->register("ld", BannerPatternType::DIAGONAL_UP_LEFT);
|
BannerPatternType::DIAGONAL_LEFT => "lud",
|
||||||
$this->register("rud", BannerPatternType::DIAGONAL_UP_RIGHT);
|
BannerPatternType::DIAGONAL_RIGHT => "rd",
|
||||||
$this->register("flo", BannerPatternType::FLOWER);
|
BannerPatternType::DIAGONAL_UP_LEFT => "ld",
|
||||||
$this->register("gra", BannerPatternType::GRADIENT);
|
BannerPatternType::DIAGONAL_UP_RIGHT => "rud",
|
||||||
$this->register("gru", BannerPatternType::GRADIENT_UP);
|
BannerPatternType::FLOWER => "flo",
|
||||||
$this->register("hh", BannerPatternType::HALF_HORIZONTAL);
|
BannerPatternType::GRADIENT => "gra",
|
||||||
$this->register("hhb", BannerPatternType::HALF_HORIZONTAL_BOTTOM);
|
BannerPatternType::GRADIENT_UP => "gru",
|
||||||
$this->register("vh", BannerPatternType::HALF_VERTICAL);
|
BannerPatternType::HALF_HORIZONTAL => "hh",
|
||||||
$this->register("vhr", BannerPatternType::HALF_VERTICAL_RIGHT);
|
BannerPatternType::HALF_HORIZONTAL_BOTTOM => "hhb",
|
||||||
$this->register("moj", BannerPatternType::MOJANG);
|
BannerPatternType::HALF_VERTICAL => "vh",
|
||||||
$this->register("mr", BannerPatternType::RHOMBUS);
|
BannerPatternType::HALF_VERTICAL_RIGHT => "vhr",
|
||||||
$this->register("sku", BannerPatternType::SKULL);
|
BannerPatternType::MOJANG => "moj",
|
||||||
$this->register("ss", BannerPatternType::SMALL_STRIPES);
|
BannerPatternType::RHOMBUS => "mr",
|
||||||
$this->register("bl", BannerPatternType::SQUARE_BOTTOM_LEFT);
|
BannerPatternType::SKULL => "sku",
|
||||||
$this->register("br", BannerPatternType::SQUARE_BOTTOM_RIGHT);
|
BannerPatternType::SMALL_STRIPES => "ss",
|
||||||
$this->register("tl", BannerPatternType::SQUARE_TOP_LEFT);
|
BannerPatternType::SQUARE_BOTTOM_LEFT => "bl",
|
||||||
$this->register("tr", BannerPatternType::SQUARE_TOP_RIGHT);
|
BannerPatternType::SQUARE_BOTTOM_RIGHT => "br",
|
||||||
$this->register("sc", BannerPatternType::STRAIGHT_CROSS);
|
BannerPatternType::SQUARE_TOP_LEFT => "tl",
|
||||||
$this->register("bs", BannerPatternType::STRIPE_BOTTOM);
|
BannerPatternType::SQUARE_TOP_RIGHT => "tr",
|
||||||
$this->register("cs", BannerPatternType::STRIPE_CENTER);
|
BannerPatternType::STRAIGHT_CROSS => "sc",
|
||||||
$this->register("dls", BannerPatternType::STRIPE_DOWNLEFT);
|
BannerPatternType::STRIPE_BOTTOM => "bs",
|
||||||
$this->register("drs", BannerPatternType::STRIPE_DOWNRIGHT);
|
BannerPatternType::STRIPE_CENTER => "cs",
|
||||||
$this->register("ls", BannerPatternType::STRIPE_LEFT);
|
BannerPatternType::STRIPE_DOWNLEFT => "dls",
|
||||||
$this->register("ms", BannerPatternType::STRIPE_MIDDLE);
|
BannerPatternType::STRIPE_DOWNRIGHT => "drs",
|
||||||
$this->register("rs", BannerPatternType::STRIPE_RIGHT);
|
BannerPatternType::STRIPE_LEFT => "ls",
|
||||||
$this->register("ts", BannerPatternType::STRIPE_TOP);
|
BannerPatternType::STRIPE_MIDDLE => "ms",
|
||||||
$this->register("bt", BannerPatternType::TRIANGLE_BOTTOM);
|
BannerPatternType::STRIPE_RIGHT => "rs",
|
||||||
$this->register("tt", BannerPatternType::TRIANGLE_TOP);
|
BannerPatternType::STRIPE_TOP => "ts",
|
||||||
$this->register("bts", BannerPatternType::TRIANGLES_BOTTOM);
|
BannerPatternType::TRIANGLE_BOTTOM => "bt",
|
||||||
$this->register("tts", BannerPatternType::TRIANGLES_TOP);
|
BannerPatternType::TRIANGLE_TOP => "tt",
|
||||||
|
BannerPatternType::TRIANGLES_BOTTOM => "bts",
|
||||||
|
BannerPatternType::TRIANGLES_TOP => "tts",
|
||||||
|
}, $case);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function register(string $stringId, BannerPatternType $type) : void{
|
public function register(string $stringId, BannerPatternType $type) : void{
|
||||||
|
@ -111,4 +111,15 @@ final class BiomeIds{
|
|||||||
public const CRIMSON_FOREST = 179;
|
public const CRIMSON_FOREST = 179;
|
||||||
public const WARPED_FOREST = 180;
|
public const WARPED_FOREST = 180;
|
||||||
public const BASALT_DELTAS = 181;
|
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;
|
||||||
}
|
}
|
||||||
|
@ -48,22 +48,28 @@ final class DyeColorIdMap{
|
|||||||
private array $enumToItemId = [];
|
private array $enumToItemId = [];
|
||||||
|
|
||||||
private function __construct(){
|
private function __construct(){
|
||||||
$this->register(0, ItemTypeNames::WHITE_DYE, DyeColor::WHITE);
|
foreach(DyeColor::cases() as $case){
|
||||||
$this->register(1, ItemTypeNames::ORANGE_DYE, DyeColor::ORANGE);
|
[$colorId, $dyeItemId] = match($case){
|
||||||
$this->register(2, ItemTypeNames::MAGENTA_DYE, DyeColor::MAGENTA);
|
DyeColor::WHITE => [0, ItemTypeNames::WHITE_DYE],
|
||||||
$this->register(3, ItemTypeNames::LIGHT_BLUE_DYE, DyeColor::LIGHT_BLUE);
|
DyeColor::ORANGE => [1, ItemTypeNames::ORANGE_DYE],
|
||||||
$this->register(4, ItemTypeNames::YELLOW_DYE, DyeColor::YELLOW);
|
DyeColor::MAGENTA => [2, ItemTypeNames::MAGENTA_DYE],
|
||||||
$this->register(5, ItemTypeNames::LIME_DYE, DyeColor::LIME);
|
DyeColor::LIGHT_BLUE => [3, ItemTypeNames::LIGHT_BLUE_DYE],
|
||||||
$this->register(6, ItemTypeNames::PINK_DYE, DyeColor::PINK);
|
DyeColor::YELLOW => [4, ItemTypeNames::YELLOW_DYE],
|
||||||
$this->register(7, ItemTypeNames::GRAY_DYE, DyeColor::GRAY);
|
DyeColor::LIME => [5, ItemTypeNames::LIME_DYE],
|
||||||
$this->register(8, ItemTypeNames::LIGHT_GRAY_DYE, DyeColor::LIGHT_GRAY);
|
DyeColor::PINK => [6, ItemTypeNames::PINK_DYE],
|
||||||
$this->register(9, ItemTypeNames::CYAN_DYE, DyeColor::CYAN);
|
DyeColor::GRAY => [7, ItemTypeNames::GRAY_DYE],
|
||||||
$this->register(10, ItemTypeNames::PURPLE_DYE, DyeColor::PURPLE);
|
DyeColor::LIGHT_GRAY => [8, ItemTypeNames::LIGHT_GRAY_DYE],
|
||||||
$this->register(11, ItemTypeNames::BLUE_DYE, DyeColor::BLUE);
|
DyeColor::CYAN => [9, ItemTypeNames::CYAN_DYE],
|
||||||
$this->register(12, ItemTypeNames::BROWN_DYE, DyeColor::BROWN);
|
DyeColor::PURPLE => [10, ItemTypeNames::PURPLE_DYE],
|
||||||
$this->register(13, ItemTypeNames::GREEN_DYE, DyeColor::GREEN);
|
DyeColor::BLUE => [11, ItemTypeNames::BLUE_DYE],
|
||||||
$this->register(14, ItemTypeNames::RED_DYE, DyeColor::RED);
|
DyeColor::BROWN => [12, ItemTypeNames::BROWN_DYE],
|
||||||
$this->register(15, ItemTypeNames::BLACK_DYE, DyeColor::BLACK);
|
DyeColor::GREEN => [13, ItemTypeNames::GREEN_DYE],
|
||||||
|
DyeColor::RED => [14, ItemTypeNames::RED_DYE],
|
||||||
|
DyeColor::BLACK => [15, ItemTypeNames::BLACK_DYE],
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->register($colorId, $dyeItemId, $case);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function register(int $id, string $itemId, DyeColor $color) : void{
|
private function register(int $id, string $itemId, DyeColor $color) : void{
|
||||||
|
@ -32,9 +32,13 @@ final class MedicineTypeIdMap{
|
|||||||
use IntSaveIdMapTrait;
|
use IntSaveIdMapTrait;
|
||||||
|
|
||||||
private function __construct(){
|
private function __construct(){
|
||||||
$this->register(MedicineTypeIds::ANTIDOTE, MedicineType::ANTIDOTE);
|
foreach(MedicineType::cases() as $case){
|
||||||
$this->register(MedicineTypeIds::ELIXIR, MedicineType::ELIXIR);
|
$this->register(match($case){
|
||||||
$this->register(MedicineTypeIds::EYE_DROPS, MedicineType::EYE_DROPS);
|
MedicineType::ANTIDOTE => MedicineTypeIds::ANTIDOTE,
|
||||||
$this->register(MedicineTypeIds::TONIC, MedicineType::TONIC);
|
MedicineType::ELIXIR => MedicineTypeIds::ELIXIR,
|
||||||
|
MedicineType::EYE_DROPS => MedicineTypeIds::EYE_DROPS,
|
||||||
|
MedicineType::TONIC => MedicineTypeIds::TONIC,
|
||||||
|
}, $case);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,12 +32,16 @@ final class MobHeadTypeIdMap{
|
|||||||
use IntSaveIdMapTrait;
|
use IntSaveIdMapTrait;
|
||||||
|
|
||||||
private function __construct(){
|
private function __construct(){
|
||||||
$this->register(0, MobHeadType::SKELETON);
|
foreach(MobHeadType::cases() as $case){
|
||||||
$this->register(1, MobHeadType::WITHER_SKELETON);
|
$this->register(match($case){
|
||||||
$this->register(2, MobHeadType::ZOMBIE);
|
MobHeadType::SKELETON => 0,
|
||||||
$this->register(3, MobHeadType::PLAYER);
|
MobHeadType::WITHER_SKELETON => 1,
|
||||||
$this->register(4, MobHeadType::CREEPER);
|
MobHeadType::ZOMBIE => 2,
|
||||||
$this->register(5, MobHeadType::DRAGON);
|
MobHeadType::PLAYER => 3,
|
||||||
$this->register(6, MobHeadType::PIGLIN);
|
MobHeadType::CREEPER => 4,
|
||||||
|
MobHeadType::DRAGON => 5,
|
||||||
|
MobHeadType::PIGLIN => 6,
|
||||||
|
}, $case);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,16 +33,20 @@ final class MushroomBlockTypeIdMap{
|
|||||||
use IntSaveIdMapTrait;
|
use IntSaveIdMapTrait;
|
||||||
|
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_ALL_PORES, MushroomBlockType::PORES);
|
foreach(MushroomBlockType::cases() as $case){
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER, MushroomBlockType::CAP_NORTHWEST);
|
$this->register(match($case){
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_NORTH_SIDE, MushroomBlockType::CAP_NORTH);
|
MushroomBlockType::PORES => LegacyMeta::MUSHROOM_BLOCK_ALL_PORES,
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHEAST_CORNER, MushroomBlockType::CAP_NORTHEAST);
|
MushroomBlockType::CAP_NORTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER,
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_WEST_SIDE, MushroomBlockType::CAP_WEST);
|
MushroomBlockType::CAP_NORTH => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTH_SIDE,
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_TOP_ONLY, MushroomBlockType::CAP_MIDDLE);
|
MushroomBlockType::CAP_NORTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHEAST_CORNER,
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_EAST_SIDE, MushroomBlockType::CAP_EAST);
|
MushroomBlockType::CAP_WEST => LegacyMeta::MUSHROOM_BLOCK_CAP_WEST_SIDE,
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHWEST_CORNER, MushroomBlockType::CAP_SOUTHWEST);
|
MushroomBlockType::CAP_MIDDLE => LegacyMeta::MUSHROOM_BLOCK_CAP_TOP_ONLY,
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTH_SIDE, MushroomBlockType::CAP_SOUTH);
|
MushroomBlockType::CAP_EAST => LegacyMeta::MUSHROOM_BLOCK_CAP_EAST_SIDE,
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER, MushroomBlockType::CAP_SOUTHEAST);
|
MushroomBlockType::CAP_SOUTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHWEST_CORNER,
|
||||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_ALL_CAP, MushroomBlockType::ALL_CAP);
|
MushroomBlockType::CAP_SOUTH => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTH_SIDE,
|
||||||
|
MushroomBlockType::CAP_SOUTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER,
|
||||||
|
MushroomBlockType::ALL_CAP => LegacyMeta::MUSHROOM_BLOCK_ALL_CAP,
|
||||||
|
}, $case);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,21 +32,25 @@ final class NoteInstrumentIdMap{
|
|||||||
use IntSaveIdMapTrait;
|
use IntSaveIdMapTrait;
|
||||||
|
|
||||||
private function __construct(){
|
private function __construct(){
|
||||||
$this->register(0, NoteInstrument::PIANO);
|
foreach(NoteInstrument::cases() as $case){
|
||||||
$this->register(1, NoteInstrument::BASS_DRUM);
|
$this->register(match($case){
|
||||||
$this->register(2, NoteInstrument::SNARE);
|
NoteInstrument::PIANO => 0,
|
||||||
$this->register(3, NoteInstrument::CLICKS_AND_STICKS);
|
NoteInstrument::BASS_DRUM => 1,
|
||||||
$this->register(4, NoteInstrument::DOUBLE_BASS);
|
NoteInstrument::SNARE => 2,
|
||||||
$this->register(5, NoteInstrument::BELL);
|
NoteInstrument::CLICKS_AND_STICKS => 3,
|
||||||
$this->register(6, NoteInstrument::FLUTE);
|
NoteInstrument::DOUBLE_BASS => 4,
|
||||||
$this->register(7, NoteInstrument::CHIME);
|
NoteInstrument::BELL => 5,
|
||||||
$this->register(8, NoteInstrument::GUITAR);
|
NoteInstrument::FLUTE => 6,
|
||||||
$this->register(9, NoteInstrument::XYLOPHONE);
|
NoteInstrument::CHIME => 7,
|
||||||
$this->register(10, NoteInstrument::IRON_XYLOPHONE);
|
NoteInstrument::GUITAR => 8,
|
||||||
$this->register(11, NoteInstrument::COW_BELL);
|
NoteInstrument::XYLOPHONE => 9,
|
||||||
$this->register(12, NoteInstrument::DIDGERIDOO);
|
NoteInstrument::IRON_XYLOPHONE => 10,
|
||||||
$this->register(13, NoteInstrument::BIT);
|
NoteInstrument::COW_BELL => 11,
|
||||||
$this->register(14, NoteInstrument::BANJO);
|
NoteInstrument::DIDGERIDOO => 12,
|
||||||
$this->register(15, NoteInstrument::PLING);
|
NoteInstrument::BIT => 13,
|
||||||
|
NoteInstrument::BANJO => 14,
|
||||||
|
NoteInstrument::PLING => 15,
|
||||||
|
}, $case);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,48 +32,52 @@ final class PotionTypeIdMap{
|
|||||||
use IntSaveIdMapTrait;
|
use IntSaveIdMapTrait;
|
||||||
|
|
||||||
private function __construct(){
|
private function __construct(){
|
||||||
$this->register(PotionTypeIds::WATER, PotionType::WATER);
|
foreach(PotionType::cases() as $case){
|
||||||
$this->register(PotionTypeIds::MUNDANE, PotionType::MUNDANE);
|
$this->register(match($case){
|
||||||
$this->register(PotionTypeIds::LONG_MUNDANE, PotionType::LONG_MUNDANE);
|
PotionType::WATER => PotionTypeIds::WATER,
|
||||||
$this->register(PotionTypeIds::THICK, PotionType::THICK);
|
PotionType::MUNDANE => PotionTypeIds::MUNDANE,
|
||||||
$this->register(PotionTypeIds::AWKWARD, PotionType::AWKWARD);
|
PotionType::LONG_MUNDANE => PotionTypeIds::LONG_MUNDANE,
|
||||||
$this->register(PotionTypeIds::NIGHT_VISION, PotionType::NIGHT_VISION);
|
PotionType::THICK => PotionTypeIds::THICK,
|
||||||
$this->register(PotionTypeIds::LONG_NIGHT_VISION, PotionType::LONG_NIGHT_VISION);
|
PotionType::AWKWARD => PotionTypeIds::AWKWARD,
|
||||||
$this->register(PotionTypeIds::INVISIBILITY, PotionType::INVISIBILITY);
|
PotionType::NIGHT_VISION => PotionTypeIds::NIGHT_VISION,
|
||||||
$this->register(PotionTypeIds::LONG_INVISIBILITY, PotionType::LONG_INVISIBILITY);
|
PotionType::LONG_NIGHT_VISION => PotionTypeIds::LONG_NIGHT_VISION,
|
||||||
$this->register(PotionTypeIds::LEAPING, PotionType::LEAPING);
|
PotionType::INVISIBILITY => PotionTypeIds::INVISIBILITY,
|
||||||
$this->register(PotionTypeIds::LONG_LEAPING, PotionType::LONG_LEAPING);
|
PotionType::LONG_INVISIBILITY => PotionTypeIds::LONG_INVISIBILITY,
|
||||||
$this->register(PotionTypeIds::STRONG_LEAPING, PotionType::STRONG_LEAPING);
|
PotionType::LEAPING => PotionTypeIds::LEAPING,
|
||||||
$this->register(PotionTypeIds::FIRE_RESISTANCE, PotionType::FIRE_RESISTANCE);
|
PotionType::LONG_LEAPING => PotionTypeIds::LONG_LEAPING,
|
||||||
$this->register(PotionTypeIds::LONG_FIRE_RESISTANCE, PotionType::LONG_FIRE_RESISTANCE);
|
PotionType::STRONG_LEAPING => PotionTypeIds::STRONG_LEAPING,
|
||||||
$this->register(PotionTypeIds::SWIFTNESS, PotionType::SWIFTNESS);
|
PotionType::FIRE_RESISTANCE => PotionTypeIds::FIRE_RESISTANCE,
|
||||||
$this->register(PotionTypeIds::LONG_SWIFTNESS, PotionType::LONG_SWIFTNESS);
|
PotionType::LONG_FIRE_RESISTANCE => PotionTypeIds::LONG_FIRE_RESISTANCE,
|
||||||
$this->register(PotionTypeIds::STRONG_SWIFTNESS, PotionType::STRONG_SWIFTNESS);
|
PotionType::SWIFTNESS => PotionTypeIds::SWIFTNESS,
|
||||||
$this->register(PotionTypeIds::SLOWNESS, PotionType::SLOWNESS);
|
PotionType::LONG_SWIFTNESS => PotionTypeIds::LONG_SWIFTNESS,
|
||||||
$this->register(PotionTypeIds::LONG_SLOWNESS, PotionType::LONG_SLOWNESS);
|
PotionType::STRONG_SWIFTNESS => PotionTypeIds::STRONG_SWIFTNESS,
|
||||||
$this->register(PotionTypeIds::WATER_BREATHING, PotionType::WATER_BREATHING);
|
PotionType::SLOWNESS => PotionTypeIds::SLOWNESS,
|
||||||
$this->register(PotionTypeIds::LONG_WATER_BREATHING, PotionType::LONG_WATER_BREATHING);
|
PotionType::LONG_SLOWNESS => PotionTypeIds::LONG_SLOWNESS,
|
||||||
$this->register(PotionTypeIds::HEALING, PotionType::HEALING);
|
PotionType::WATER_BREATHING => PotionTypeIds::WATER_BREATHING,
|
||||||
$this->register(PotionTypeIds::STRONG_HEALING, PotionType::STRONG_HEALING);
|
PotionType::LONG_WATER_BREATHING => PotionTypeIds::LONG_WATER_BREATHING,
|
||||||
$this->register(PotionTypeIds::HARMING, PotionType::HARMING);
|
PotionType::HEALING => PotionTypeIds::HEALING,
|
||||||
$this->register(PotionTypeIds::STRONG_HARMING, PotionType::STRONG_HARMING);
|
PotionType::STRONG_HEALING => PotionTypeIds::STRONG_HEALING,
|
||||||
$this->register(PotionTypeIds::POISON, PotionType::POISON);
|
PotionType::HARMING => PotionTypeIds::HARMING,
|
||||||
$this->register(PotionTypeIds::LONG_POISON, PotionType::LONG_POISON);
|
PotionType::STRONG_HARMING => PotionTypeIds::STRONG_HARMING,
|
||||||
$this->register(PotionTypeIds::STRONG_POISON, PotionType::STRONG_POISON);
|
PotionType::POISON => PotionTypeIds::POISON,
|
||||||
$this->register(PotionTypeIds::REGENERATION, PotionType::REGENERATION);
|
PotionType::LONG_POISON => PotionTypeIds::LONG_POISON,
|
||||||
$this->register(PotionTypeIds::LONG_REGENERATION, PotionType::LONG_REGENERATION);
|
PotionType::STRONG_POISON => PotionTypeIds::STRONG_POISON,
|
||||||
$this->register(PotionTypeIds::STRONG_REGENERATION, PotionType::STRONG_REGENERATION);
|
PotionType::REGENERATION => PotionTypeIds::REGENERATION,
|
||||||
$this->register(PotionTypeIds::STRENGTH, PotionType::STRENGTH);
|
PotionType::LONG_REGENERATION => PotionTypeIds::LONG_REGENERATION,
|
||||||
$this->register(PotionTypeIds::LONG_STRENGTH, PotionType::LONG_STRENGTH);
|
PotionType::STRONG_REGENERATION => PotionTypeIds::STRONG_REGENERATION,
|
||||||
$this->register(PotionTypeIds::STRONG_STRENGTH, PotionType::STRONG_STRENGTH);
|
PotionType::STRENGTH => PotionTypeIds::STRENGTH,
|
||||||
$this->register(PotionTypeIds::WEAKNESS, PotionType::WEAKNESS);
|
PotionType::LONG_STRENGTH => PotionTypeIds::LONG_STRENGTH,
|
||||||
$this->register(PotionTypeIds::LONG_WEAKNESS, PotionType::LONG_WEAKNESS);
|
PotionType::STRONG_STRENGTH => PotionTypeIds::STRONG_STRENGTH,
|
||||||
$this->register(PotionTypeIds::WITHER, PotionType::WITHER);
|
PotionType::WEAKNESS => PotionTypeIds::WEAKNESS,
|
||||||
$this->register(PotionTypeIds::TURTLE_MASTER, PotionType::TURTLE_MASTER);
|
PotionType::LONG_WEAKNESS => PotionTypeIds::LONG_WEAKNESS,
|
||||||
$this->register(PotionTypeIds::LONG_TURTLE_MASTER, PotionType::LONG_TURTLE_MASTER);
|
PotionType::WITHER => PotionTypeIds::WITHER,
|
||||||
$this->register(PotionTypeIds::STRONG_TURTLE_MASTER, PotionType::STRONG_TURTLE_MASTER);
|
PotionType::TURTLE_MASTER => PotionTypeIds::TURTLE_MASTER,
|
||||||
$this->register(PotionTypeIds::SLOW_FALLING, PotionType::SLOW_FALLING);
|
PotionType::LONG_TURTLE_MASTER => PotionTypeIds::LONG_TURTLE_MASTER,
|
||||||
$this->register(PotionTypeIds::LONG_SLOW_FALLING, PotionType::LONG_SLOW_FALLING);
|
PotionType::STRONG_TURTLE_MASTER => PotionTypeIds::STRONG_TURTLE_MASTER,
|
||||||
$this->register(PotionTypeIds::STRONG_SLOWNESS, PotionType::STRONG_SLOWNESS);
|
PotionType::SLOW_FALLING => PotionTypeIds::SLOW_FALLING,
|
||||||
|
PotionType::LONG_SLOW_FALLING => PotionTypeIds::LONG_SLOW_FALLING,
|
||||||
|
PotionType::STRONG_SLOWNESS => PotionTypeIds::STRONG_SLOWNESS,
|
||||||
|
}, $case);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,20 @@ final class SuspiciousStewTypeIdMap{
|
|||||||
use IntSaveIdMapTrait;
|
use IntSaveIdMapTrait;
|
||||||
|
|
||||||
private function __construct(){
|
private function __construct(){
|
||||||
$this->register(SuspiciousStewTypeIds::POPPY, SuspiciousStewType::POPPY);
|
foreach(SuspiciousStewType::cases() as $case){
|
||||||
$this->register(SuspiciousStewTypeIds::CORNFLOWER, SuspiciousStewType::CORNFLOWER);
|
$this->register(match($case){
|
||||||
$this->register(SuspiciousStewTypeIds::TULIP, SuspiciousStewType::TULIP);
|
SuspiciousStewType::POPPY => SuspiciousStewTypeIds::POPPY,
|
||||||
$this->register(SuspiciousStewTypeIds::AZURE_BLUET, SuspiciousStewType::AZURE_BLUET);
|
SuspiciousStewType::CORNFLOWER => SuspiciousStewTypeIds::CORNFLOWER,
|
||||||
$this->register(SuspiciousStewTypeIds::LILY_OF_THE_VALLEY, SuspiciousStewType::LILY_OF_THE_VALLEY);
|
SuspiciousStewType::TULIP => SuspiciousStewTypeIds::TULIP,
|
||||||
$this->register(SuspiciousStewTypeIds::DANDELION, SuspiciousStewType::DANDELION);
|
SuspiciousStewType::AZURE_BLUET => SuspiciousStewTypeIds::AZURE_BLUET,
|
||||||
$this->register(SuspiciousStewTypeIds::BLUE_ORCHID, SuspiciousStewType::BLUE_ORCHID);
|
SuspiciousStewType::LILY_OF_THE_VALLEY => SuspiciousStewTypeIds::LILY_OF_THE_VALLEY,
|
||||||
$this->register(SuspiciousStewTypeIds::ALLIUM, SuspiciousStewType::ALLIUM);
|
SuspiciousStewType::DANDELION => SuspiciousStewTypeIds::DANDELION,
|
||||||
$this->register(SuspiciousStewTypeIds::OXEYE_DAISY, SuspiciousStewType::OXEYE_DAISY);
|
SuspiciousStewType::BLUE_ORCHID => SuspiciousStewTypeIds::BLUE_ORCHID,
|
||||||
$this->register(SuspiciousStewTypeIds::WITHER_ROSE, SuspiciousStewType::WITHER_ROSE);
|
SuspiciousStewType::ALLIUM => SuspiciousStewTypeIds::ALLIUM,
|
||||||
|
SuspiciousStewType::OXEYE_DAISY => SuspiciousStewTypeIds::OXEYE_DAISY,
|
||||||
|
SuspiciousStewType::WITHER_ROSE => SuspiciousStewTypeIds::WITHER_ROSE,
|
||||||
|
}, $case);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,6 +305,7 @@ final class ItemSerializerDeserializerRegistrar{
|
|||||||
$this->map1to1Item(Ids::MUSIC_DISC_WAIT, Items::RECORD_WAIT());
|
$this->map1to1Item(Ids::MUSIC_DISC_WAIT, Items::RECORD_WAIT());
|
||||||
$this->map1to1Item(Ids::MUSIC_DISC_WARD, Items::RECORD_WARD());
|
$this->map1to1Item(Ids::MUSIC_DISC_WARD, Items::RECORD_WARD());
|
||||||
$this->map1to1Item(Ids::MUTTON, Items::RAW_MUTTON());
|
$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::NAUTILUS_SHELL, Items::NAUTILUS_SHELL());
|
||||||
$this->map1to1Item(Ids::NETHER_STAR, Items::NETHER_STAR());
|
$this->map1to1Item(Ids::NETHER_STAR, Items::NETHER_STAR());
|
||||||
$this->map1to1Item(Ids::NETHERBRICK, Items::NETHER_BRICK());
|
$this->map1to1Item(Ids::NETHERBRICK, Items::NETHER_BRICK());
|
||||||
|
@ -44,10 +44,14 @@ final class GameModeIdMap{
|
|||||||
private array $enumToId = [];
|
private array $enumToId = [];
|
||||||
|
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
$this->register(0, GameMode::SURVIVAL);
|
foreach(GameMode::cases() as $case){
|
||||||
$this->register(1, GameMode::CREATIVE);
|
$this->register(match($case){
|
||||||
$this->register(2, GameMode::ADVENTURE);
|
GameMode::SURVIVAL => 0,
|
||||||
$this->register(3, GameMode::SPECTATOR);
|
GameMode::CREATIVE => 1,
|
||||||
|
GameMode::ADVENTURE => 2,
|
||||||
|
GameMode::SPECTATOR => 3,
|
||||||
|
}, $case);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function register(int $id, GameMode $type) : void{
|
private function register(int $id, GameMode $type) : void{
|
||||||
|
@ -29,11 +29,6 @@ namespace pocketmine\data\runtime;
|
|||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
trait LegacyRuntimeEnumDescriberTrait{
|
trait LegacyRuntimeEnumDescriberTrait{
|
||||||
|
|
||||||
/**
|
|
||||||
* @phpstan-template T of \UnitEnum
|
|
||||||
* @phpstan-param T $case
|
|
||||||
*/
|
|
||||||
abstract protected function enum(\UnitEnum &$case) : void;
|
abstract protected function enum(\UnitEnum &$case) : void;
|
||||||
|
|
||||||
public function bellAttachmentType(\pocketmine\block\utils\BellAttachmentType &$value) : void{
|
public function bellAttachmentType(\pocketmine\block\utils\BellAttachmentType &$value) : void{
|
||||||
|
@ -89,10 +89,6 @@ interface RuntimeDataDescriber extends RuntimeEnumDescriber{
|
|||||||
|
|
||||||
public function straightOnlyRailShape(int &$railShape) : void;
|
public function straightOnlyRailShape(int &$railShape) : void;
|
||||||
|
|
||||||
/**
|
|
||||||
* @phpstan-template T of \UnitEnum
|
|
||||||
* @phpstan-param T $case
|
|
||||||
*/
|
|
||||||
public function enum(\UnitEnum &$case) : void;
|
public function enum(\UnitEnum &$case) : void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -252,6 +252,14 @@ abstract class Entity{
|
|||||||
return $this->alwaysShowNameTag;
|
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{
|
public function setNameTag(string $name) : void{
|
||||||
$this->nameTag = $name;
|
$this->nameTag = $name;
|
||||||
$this->networkPropertiesDirty = true;
|
$this->networkPropertiesDirty = true;
|
||||||
|
@ -132,6 +132,10 @@ abstract class Living extends Entity{
|
|||||||
|
|
||||||
abstract public function getName() : string;
|
abstract public function getName() : string;
|
||||||
|
|
||||||
|
public function canBeRenamed() : bool{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected function initEntity(CompoundTag $nbt) : void{
|
protected function initEntity(CompoundTag $nbt) : void{
|
||||||
parent::initEntity($nbt);
|
parent::initEntity($nbt);
|
||||||
|
|
||||||
|
@ -37,8 +37,7 @@ class HandlerList{
|
|||||||
private array $affectedHandlerCaches = [];
|
private array $affectedHandlerCaches = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-template TEvent of Event
|
* @phpstan-param class-string<covariant Event> $class
|
||||||
* @phpstan-param class-string<TEvent> $class
|
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private string $class,
|
private string $class,
|
||||||
|
@ -86,8 +86,7 @@ class HandlerListManager{
|
|||||||
*
|
*
|
||||||
* Calling this method also lazily initializes the $classMap inheritance tree of handler lists.
|
* Calling this method also lazily initializes the $classMap inheritance tree of handler lists.
|
||||||
*
|
*
|
||||||
* @phpstan-template TEvent of Event
|
* @phpstan-param class-string<covariant Event> $event
|
||||||
* @phpstan-param class-string<TEvent> $event
|
|
||||||
*
|
*
|
||||||
* @throws \ReflectionException
|
* @throws \ReflectionException
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
@ -113,8 +112,7 @@ class HandlerListManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-template TEvent of Event
|
* @phpstan-param class-string<covariant Event> $event
|
||||||
* @phpstan-param class-string<TEvent> $event
|
|
||||||
*
|
*
|
||||||
* @return RegisteredListener[]
|
* @return RegisteredListener[]
|
||||||
*/
|
*/
|
||||||
|
@ -323,8 +323,9 @@ final class ItemTypeIds{
|
|||||||
public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = 20284;
|
public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = 20284;
|
||||||
public const SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = 20285;
|
public const SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = 20285;
|
||||||
public const PITCHER_POD = 20286;
|
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;
|
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;
|
||||||
|
|
||||||
|
@ -21,18 +21,20 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\data\bedrock;
|
namespace pocketmine\item;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\block\utils\DyeColor;
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\player\Player;
|
||||||
|
|
||||||
class DyeColorIdMapTest extends TestCase{
|
class NameTag extends Item{
|
||||||
|
|
||||||
public function testAllColorsMapped() : void{
|
public function onInteractEntity(Player $player, Entity $entity, Vector3 $clickVector) : bool{
|
||||||
foreach(DyeColor::cases() as $color){
|
if($entity->canBeRenamed() && $this->hasCustomName()){
|
||||||
$id = DyeColorIdMap::getInstance()->toId($color);
|
$entity->setNameTag($this->getCustomName());
|
||||||
$color2 = DyeColorIdMap::getInstance()->fromId($id);
|
$this->pop();
|
||||||
self::assertTrue($color === $color2);
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1384,6 +1384,7 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->register("mutton_raw", fn() => Items::RAW_MUTTON());
|
$result->register("mutton_raw", fn() => Items::RAW_MUTTON());
|
||||||
$result->register("muttoncooked", fn() => Items::COOKED_MUTTON());
|
$result->register("muttoncooked", fn() => Items::COOKED_MUTTON());
|
||||||
$result->register("muttonraw", fn() => Items::RAW_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("nautilus_shell", fn() => Items::NAUTILUS_SHELL());
|
||||||
$result->register("nether_brick", fn() => Items::NETHER_BRICK());
|
$result->register("nether_brick", fn() => Items::NETHER_BRICK());
|
||||||
$result->register("nether_quartz", fn() => Items::NETHER_QUARTZ());
|
$result->register("nether_quartz", fn() => Items::NETHER_QUARTZ());
|
||||||
|
@ -219,6 +219,7 @@ use function strtolower;
|
|||||||
* @method static MilkBucket MILK_BUCKET()
|
* @method static MilkBucket MILK_BUCKET()
|
||||||
* @method static Minecart MINECART()
|
* @method static Minecart MINECART()
|
||||||
* @method static MushroomStew MUSHROOM_STEW()
|
* @method static MushroomStew MUSHROOM_STEW()
|
||||||
|
* @method static NameTag NAME_TAG()
|
||||||
* @method static Item NAUTILUS_SHELL()
|
* @method static Item NAUTILUS_SHELL()
|
||||||
* @method static Axe NETHERITE_AXE()
|
* @method static Axe NETHERITE_AXE()
|
||||||
* @method static Armor NETHERITE_BOOTS()
|
* @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("milk_bucket", new MilkBucket(new IID(Ids::MILK_BUCKET), "Milk Bucket"));
|
||||||
self::register("minecart", new Minecart(new IID(Ids::MINECART), "Minecart"));
|
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("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("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_brick", new Item(new IID(Ids::NETHER_BRICK), "Nether Brick"));
|
||||||
self::register("nether_quartz", new Item(new IID(Ids::NETHER_QUARTZ), "Nether Quartz"));
|
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\convert\TypeConverter;
|
||||||
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
|
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
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\ChunkPosition;
|
||||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||||
use pocketmine\network\mcpe\serializer\ChunkSerializer;
|
use pocketmine\network\mcpe\serializer\ChunkSerializer;
|
||||||
@ -72,11 +71,10 @@ class ChunkRequestTask extends AsyncTask{
|
|||||||
|
|
||||||
$subCount = ChunkSerializer::getSubChunkCount($chunk, $dimensionId);
|
$subCount = ChunkSerializer::getSubChunkCount($chunk, $dimensionId);
|
||||||
$converter = TypeConverter::getInstance();
|
$converter = TypeConverter::getInstance();
|
||||||
$encoderContext = new PacketSerializerContext($converter->getItemTypeDictionary());
|
$payload = ChunkSerializer::serializeFullChunk($chunk, $dimensionId, $converter->getBlockTranslator(), $this->tiles);
|
||||||
$payload = ChunkSerializer::serializeFullChunk($chunk, $dimensionId, $converter->getBlockTranslator(), $encoderContext, $this->tiles);
|
|
||||||
|
|
||||||
$stream = new BinaryStream();
|
$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();
|
$compressor = $this->compressor->deserialize();
|
||||||
$this->setResult(chr($compressor->getNetworkId()) . $compressor->compress($stream->getBuffer()));
|
$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{
|
public function onSlotChange(Inventory $inventory, int $slot) : void{
|
||||||
$inventoryEntry = $this->inventories[spl_object_id($inventory)] ?? null;
|
$inventoryEntry = $this->inventories[spl_object_id($inventory)] ?? null;
|
||||||
if($inventoryEntry === null){
|
if($inventoryEntry === null){
|
||||||
@ -432,7 +467,7 @@ class InventoryManager{
|
|||||||
}
|
}
|
||||||
$currentItem = $this->session->getTypeConverter()->coreItemStackToNet($inventory->getItem($slot));
|
$currentItem = $this->session->getTypeConverter()->coreItemStackToNet($inventory->getItem($slot));
|
||||||
$clientSideItem = $inventoryEntry->predictions[$slot] ?? null;
|
$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
|
//no prediction or incorrect - do not associate this with the currently active itemstack request
|
||||||
$this->trackItemStack($inventoryEntry, $slot, $currentItem, null);
|
$this->trackItemStack($inventoryEntry, $slot, $currentItem, null);
|
||||||
$inventoryEntry->pendingSyncs[$slot] = $currentItem;
|
$inventoryEntry->pendingSyncs[$slot] = $currentItem;
|
||||||
|
@ -67,7 +67,6 @@ use pocketmine\network\mcpe\protocol\PlayStatusPacket;
|
|||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
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\ServerboundPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
|
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
|
||||||
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
|
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
|
||||||
@ -180,7 +179,6 @@ class NetworkSession{
|
|||||||
private Server $server,
|
private Server $server,
|
||||||
private NetworkSessionManager $manager,
|
private NetworkSessionManager $manager,
|
||||||
private PacketPool $packetPool,
|
private PacketPool $packetPool,
|
||||||
private PacketSerializerContext $packetSerializerContext,
|
|
||||||
private PacketSender $sender,
|
private PacketSender $sender,
|
||||||
private PacketBroadcaster $broadcaster,
|
private PacketBroadcaster $broadcaster,
|
||||||
private EntityEventBroadcaster $entityEventBroadcaster,
|
private EntityEventBroadcaster $entityEventBroadcaster,
|
||||||
@ -435,7 +433,7 @@ class NetworkSession{
|
|||||||
$decodeTimings = Timings::getDecodeDataPacketTimings($packet);
|
$decodeTimings = Timings::getDecodeDataPacketTimings($packet);
|
||||||
$decodeTimings->startTiming();
|
$decodeTimings->startTiming();
|
||||||
try{
|
try{
|
||||||
$stream = PacketSerializer::decoder($buffer, 0, $this->packetSerializerContext);
|
$stream = PacketSerializer::decoder($buffer, 0);
|
||||||
try{
|
try{
|
||||||
$packet->decode($stream);
|
$packet->decode($stream);
|
||||||
}catch(PacketDecodeException $e){
|
}catch(PacketDecodeException $e){
|
||||||
@ -494,7 +492,7 @@ class NetworkSession{
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach($packets as $evPacket){
|
foreach($packets as $evPacket){
|
||||||
$this->addToSendBuffer(self::encodePacketTimed(PacketSerializer::encoder($this->packetSerializerContext), $evPacket));
|
$this->addToSendBuffer(self::encodePacketTimed(PacketSerializer::encoder(), $evPacket));
|
||||||
}
|
}
|
||||||
if($immediate){
|
if($immediate){
|
||||||
$this->flushSendBuffer(true);
|
$this->flushSendBuffer(true);
|
||||||
@ -554,8 +552,6 @@ class NetworkSession{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPacketSerializerContext() : PacketSerializerContext{ return $this->packetSerializerContext; }
|
|
||||||
|
|
||||||
public function getBroadcaster() : PacketBroadcaster{ return $this->broadcaster; }
|
public function getBroadcaster() : PacketBroadcaster{ return $this->broadcaster; }
|
||||||
|
|
||||||
public function getEntityEventBroadcaster() : EntityEventBroadcaster{ return $this->entityEventBroadcaster; }
|
public function getEntityEventBroadcaster() : EntityEventBroadcaster{ return $this->entityEventBroadcaster; }
|
||||||
|
@ -26,7 +26,6 @@ namespace pocketmine\network\mcpe;
|
|||||||
use pocketmine\event\server\DataPacketSendEvent;
|
use pocketmine\event\server\DataPacketSendEvent;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
use pocketmine\timings\Timings;
|
use pocketmine\timings\Timings;
|
||||||
use pocketmine\utils\BinaryStream;
|
use pocketmine\utils\BinaryStream;
|
||||||
@ -37,8 +36,7 @@ use function strlen;
|
|||||||
|
|
||||||
final class StandardPacketBroadcaster implements PacketBroadcaster{
|
final class StandardPacketBroadcaster implements PacketBroadcaster{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private Server $server,
|
private Server $server
|
||||||
private PacketSerializerContext $protocolContext
|
|
||||||
){}
|
){}
|
||||||
|
|
||||||
public function broadcastPackets(array $recipients, array $packets) : void{
|
public function broadcastPackets(array $recipients, array $packets) : void{
|
||||||
@ -58,10 +56,6 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
|
|||||||
/** @var NetworkSession[][] $targetsByCompressor */
|
/** @var NetworkSession[][] $targetsByCompressor */
|
||||||
$targetsByCompressor = [];
|
$targetsByCompressor = [];
|
||||||
foreach($recipients as $recipient){
|
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
|
//TODO: different compressors might be compatible, it might not be necessary to split them up by object
|
||||||
$compressor = $recipient->getCompressor();
|
$compressor = $recipient->getCompressor();
|
||||||
$compressors[spl_object_id($compressor)] = $compressor;
|
$compressors[spl_object_id($compressor)] = $compressor;
|
||||||
@ -72,7 +66,7 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
|
|||||||
$totalLength = 0;
|
$totalLength = 0;
|
||||||
$packetBuffers = [];
|
$packetBuffers = [];
|
||||||
foreach($packets as $packet){
|
foreach($packets as $packet){
|
||||||
$buffer = NetworkSession::encodePacketTimed(PacketSerializer::encoder($this->protocolContext), $packet);
|
$buffer = NetworkSession::encodePacketTimed(PacketSerializer::encoder(), $packet);
|
||||||
//varint length prefix + packet buffer
|
//varint length prefix + packet buffer
|
||||||
$totalLength += (((int) log(strlen($buffer), 128)) + 1) + strlen($buffer);
|
$totalLength += (((int) log(strlen($buffer), 128)) + 1) + strlen($buffer);
|
||||||
$packetBuffers[] = $buffer;
|
$packetBuffers[] = $buffer;
|
||||||
|
@ -39,16 +39,6 @@ use function time;
|
|||||||
class ProcessLoginTask extends AsyncTask{
|
class ProcessLoginTask extends AsyncTask{
|
||||||
private const TLS_KEY_ON_COMPLETION = "completion";
|
private const TLS_KEY_ON_COMPLETION = "completion";
|
||||||
|
|
||||||
/**
|
|
||||||
* Old Mojang root auth key. This was used since the introduction of Xbox Live authentication in 0.15.0.
|
|
||||||
* This key is expected to be replaced by the key below in the future, but this has not yet happened as of
|
|
||||||
* 2023-07-01.
|
|
||||||
* Ideally we would place a time expiry on this key, but since Mojang have not given a hard date for the key change,
|
|
||||||
* and one bad guess has already caused a major outage, we can't do this.
|
|
||||||
* TODO: This needs to be removed as soon as the new key is deployed by Mojang's authentication servers.
|
|
||||||
*/
|
|
||||||
public const MOJANG_OLD_ROOT_PUBLIC_KEY = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* New Mojang root auth key. Mojang notified third-party developers of this change prior to the release of 1.20.0.
|
* New Mojang root auth key. Mojang notified third-party developers of this change prior to the release of 1.20.0.
|
||||||
* Expectations were that this would be used starting a "couple of weeks" after the release, but as of 2023-07-01,
|
* Expectations were that this would be used starting a "couple of weeks" after the release, but as of 2023-07-01,
|
||||||
@ -128,7 +118,6 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
try{
|
try{
|
||||||
[$headersArray, $claimsArray, ] = JwtUtils::parse($jwt);
|
[$headersArray, $claimsArray, ] = JwtUtils::parse($jwt);
|
||||||
}catch(JwtException $e){
|
}catch(JwtException $e){
|
||||||
//TODO: we shouldn't be showing internal information like this to the client
|
|
||||||
throw new VerifyLoginException("Failed to parse JWT: " . $e->getMessage(), null, 0, $e);
|
throw new VerifyLoginException("Failed to parse JWT: " . $e->getMessage(), null, 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,13 +131,11 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
/** @var JwtHeader $headers */
|
/** @var JwtHeader $headers */
|
||||||
$headers = $mapper->map($headersArray, new JwtHeader());
|
$headers = $mapper->map($headersArray, new JwtHeader());
|
||||||
}catch(\JsonMapper_Exception $e){
|
}catch(\JsonMapper_Exception $e){
|
||||||
//TODO: we shouldn't be showing internal information like this to the client
|
|
||||||
throw new VerifyLoginException("Invalid JWT header: " . $e->getMessage(), null, 0, $e);
|
throw new VerifyLoginException("Invalid JWT header: " . $e->getMessage(), null, 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$headerDerKey = base64_decode($headers->x5u, true);
|
$headerDerKey = base64_decode($headers->x5u, true);
|
||||||
if($headerDerKey === false){
|
if($headerDerKey === false){
|
||||||
//TODO: we shouldn't be showing internal information like this to the client
|
|
||||||
throw new VerifyLoginException("Invalid JWT public key: base64 decoding error decoding x5u");
|
throw new VerifyLoginException("Invalid JWT public key: base64 decoding error decoding x5u");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +151,6 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
try{
|
try{
|
||||||
$signingKeyOpenSSL = JwtUtils::parseDerPublicKey($headerDerKey);
|
$signingKeyOpenSSL = JwtUtils::parseDerPublicKey($headerDerKey);
|
||||||
}catch(JwtException $e){
|
}catch(JwtException $e){
|
||||||
//TODO: we shouldn't be showing this internal information to the client
|
|
||||||
throw new VerifyLoginException("Invalid JWT public key: " . $e->getMessage(), null, 0, $e);
|
throw new VerifyLoginException("Invalid JWT public key: " . $e->getMessage(), null, 0, $e);
|
||||||
}
|
}
|
||||||
try{
|
try{
|
||||||
@ -175,7 +161,7 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
throw new VerifyLoginException($e->getMessage(), null, 0, $e);
|
throw new VerifyLoginException($e->getMessage(), null, 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($headers->x5u === self::MOJANG_ROOT_PUBLIC_KEY || $headers->x5u === self::MOJANG_OLD_ROOT_PUBLIC_KEY){
|
if($headers->x5u === self::MOJANG_ROOT_PUBLIC_KEY){
|
||||||
$this->authenticated = true; //we're signed into xbox live
|
$this->authenticated = true; //we're signed into xbox live
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,13 +30,17 @@ use pocketmine\crafting\RecipeIngredient;
|
|||||||
use pocketmine\crafting\TagWildcardRecipeIngredient;
|
use pocketmine\crafting\TagWildcardRecipeIngredient;
|
||||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||||
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
||||||
|
use pocketmine\data\bedrock\item\ItemTypeNames;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\VanillaItems;
|
use pocketmine\item\VanillaItems;
|
||||||
use pocketmine\nbt\NbtException;
|
use pocketmine\nbt\NbtException;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
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\GameMode as ProtocolGameMode;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
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\IntIdMetaItemDescriptor;
|
||||||
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient as ProtocolRecipeIngredient;
|
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient as ProtocolRecipeIngredient;
|
||||||
use pocketmine\network\mcpe\protocol\types\recipe\StringIdMetaItemDescriptor;
|
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->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->itemTranslator = new ItemTranslator(
|
||||||
$this->itemTypeDictionary,
|
$this->itemTypeDictionary,
|
||||||
@ -217,26 +221,36 @@ class TypeConverter{
|
|||||||
[$id, $meta, $blockRuntimeId] = $idMeta;
|
[$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(
|
return new ItemStack(
|
||||||
$id,
|
$id,
|
||||||
$meta,
|
$meta,
|
||||||
$itemStack->getCount(),
|
$itemStack->getCount(),
|
||||||
$blockRuntimeId ?? ItemTranslator::NO_BLOCK_RUNTIME_ID,
|
$blockRuntimeId ?? ItemTranslator::NO_BLOCK_RUNTIME_ID,
|
||||||
$nbt,
|
$extraDataSerializer->getBuffer(),
|
||||||
[],
|
|
||||||
[],
|
|
||||||
$id === $this->shieldRuntimeId ? 0 : null
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 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
|
* @throws TypeConversionException
|
||||||
*/
|
*/
|
||||||
public function netItemStackToCore(ItemStack $itemStack) : Item{
|
public function netItemStackToCore(ItemStack $itemStack) : Item{
|
||||||
if($itemStack->getId() === 0){
|
if($itemStack->getId() === 0){
|
||||||
return VanillaItems::AIR();
|
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());
|
$itemResult = $this->itemTranslator->fromNetworkId($itemStack->getId(), $itemStack->getMeta(), $itemStack->getBlockRuntimeId());
|
||||||
|
|
||||||
@ -255,4 +269,11 @@ class TypeConverter{
|
|||||||
|
|
||||||
return $itemResult;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,9 +444,18 @@ class InGamePacketHandler extends PacketHandler{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$serverItemStack = $this->session->getTypeConverter()->coreItemStackToNet($sourceSlotItem);
|
$serverItemStack = $this->session->getTypeConverter()->coreItemStackToNet($sourceSlotItem);
|
||||||
//because the client doesn't tell us the expected itemstack ID, we have to deep-compare our known
|
//Sadly we don't have itemstack IDs here, so we have to compare the basic item properties to ensure that we're
|
||||||
//itemstack info with the one the client sent. This is costly, but we don't have any other option :(
|
//dropping the item the client expects (inventory might be out of sync with the client).
|
||||||
if(!$serverItemStack->equals($clientItemStack)){
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ use pocketmine\network\mcpe\NetworkSession;
|
|||||||
use pocketmine\network\mcpe\PacketBroadcaster;
|
use pocketmine\network\mcpe\PacketBroadcaster;
|
||||||
use pocketmine\network\mcpe\protocol\PacketPool;
|
use pocketmine\network\mcpe\protocol\PacketPool;
|
||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
|
||||||
use pocketmine\network\Network;
|
use pocketmine\network\Network;
|
||||||
use pocketmine\network\NetworkInterfaceStartException;
|
use pocketmine\network\NetworkInterfaceStartException;
|
||||||
use pocketmine\network\PacketHandlingException;
|
use pocketmine\network\PacketHandlingException;
|
||||||
@ -84,7 +83,6 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
|||||||
|
|
||||||
private PacketBroadcaster $packetBroadcaster;
|
private PacketBroadcaster $packetBroadcaster;
|
||||||
private EntityEventBroadcaster $entityEventBroadcaster;
|
private EntityEventBroadcaster $entityEventBroadcaster;
|
||||||
private PacketSerializerContext $packetSerializerContext;
|
|
||||||
private TypeConverter $typeConverter;
|
private TypeConverter $typeConverter;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@ -94,12 +92,10 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
|||||||
bool $ipV6,
|
bool $ipV6,
|
||||||
PacketBroadcaster $packetBroadcaster,
|
PacketBroadcaster $packetBroadcaster,
|
||||||
EntityEventBroadcaster $entityEventBroadcaster,
|
EntityEventBroadcaster $entityEventBroadcaster,
|
||||||
PacketSerializerContext $packetSerializerContext,
|
|
||||||
TypeConverter $typeConverter
|
TypeConverter $typeConverter
|
||||||
){
|
){
|
||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
$this->packetBroadcaster = $packetBroadcaster;
|
$this->packetBroadcaster = $packetBroadcaster;
|
||||||
$this->packetSerializerContext = $packetSerializerContext;
|
|
||||||
$this->entityEventBroadcaster = $entityEventBroadcaster;
|
$this->entityEventBroadcaster = $entityEventBroadcaster;
|
||||||
$this->typeConverter = $typeConverter;
|
$this->typeConverter = $typeConverter;
|
||||||
|
|
||||||
@ -192,7 +188,6 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
|||||||
$this->server,
|
$this->server,
|
||||||
$this->network->getSessionManager(),
|
$this->network->getSessionManager(),
|
||||||
PacketPool::getInstance(),
|
PacketPool::getInstance(),
|
||||||
$this->packetSerializerContext,
|
|
||||||
new RakLibPacketSender($sessionId, $this),
|
new RakLibPacketSender($sessionId, $this),
|
||||||
$this->packetBroadcaster,
|
$this->packetBroadcaster,
|
||||||
$this->entityEventBroadcaster,
|
$this->entityEventBroadcaster,
|
||||||
|
@ -30,7 +30,6 @@ use pocketmine\nbt\TreeRoot;
|
|||||||
use pocketmine\network\mcpe\convert\BlockTranslator;
|
use pocketmine\network\mcpe\convert\BlockTranslator;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
|
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
use pocketmine\utils\BinaryStream;
|
use pocketmine\utils\BinaryStream;
|
||||||
@ -84,8 +83,8 @@ final class ChunkSerializer{
|
|||||||
/**
|
/**
|
||||||
* @phpstan-param DimensionIds::* $dimensionId
|
* @phpstan-param DimensionIds::* $dimensionId
|
||||||
*/
|
*/
|
||||||
public static function serializeFullChunk(Chunk $chunk, int $dimensionId, BlockTranslator $blockTranslator, PacketSerializerContext $encoderContext, ?string $tiles = null) : string{
|
public static function serializeFullChunk(Chunk $chunk, int $dimensionId, BlockTranslator $blockTranslator, ?string $tiles = null) : string{
|
||||||
$stream = PacketSerializer::encoder($encoderContext);
|
$stream = PacketSerializer::encoder();
|
||||||
|
|
||||||
$subChunkCount = self::getSubChunkCount($chunk, $dimensionId);
|
$subChunkCount = self::getSubChunkCount($chunk, $dimensionId);
|
||||||
$writtenCount = 0;
|
$writtenCount = 0;
|
||||||
|
@ -630,6 +630,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
$this->displayName = $ev->getNewName();
|
$this->displayName = $ev->getNewName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function canBeRenamed() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the player's locale, e.g. en_US.
|
* Returns the player's locale, e.g. en_US.
|
||||||
*/
|
*/
|
||||||
|
@ -650,6 +650,11 @@ class PluginManager{
|
|||||||
|
|
||||||
$handlerName = Utils::getNiceClosureName($handler);
|
$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()){
|
if(!$plugin->isEnabled()){
|
||||||
throw new PluginException("Plugin attempted to register event handler " . $handlerName . "() to event " . $event . " while not enabled");
|
throw new PluginException("Plugin attempted to register event handler " . $handlerName . "() to event " . $event . " while not enabled");
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\promise;
|
namespace pocketmine\promise;
|
||||||
|
|
||||||
|
use function count;
|
||||||
use function spl_object_id;
|
use function spl_object_id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,4 +58,53 @@ final class Promise{
|
|||||||
//rejected or just hasn't been resolved yet
|
//rejected or just hasn't been resolved yet
|
||||||
return $this->shared->state === true;
|
return $this->shared->state === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise that will resolve only once all the Promises in
|
||||||
|
* `$promises` have resolved. The resolution value of the returned promise
|
||||||
|
* will be an array containing the resolution values of each Promises in
|
||||||
|
* `$promises` indexed by the respective Promises' array keys.
|
||||||
|
*
|
||||||
|
* @param Promise[] $promises
|
||||||
|
*
|
||||||
|
* @phpstan-template TPromiseValue
|
||||||
|
* @phpstan-template TKey of array-key
|
||||||
|
* @phpstan-param non-empty-array<TKey, Promise<TPromiseValue>> $promises
|
||||||
|
*
|
||||||
|
* @phpstan-return Promise<array<TKey, TPromiseValue>>
|
||||||
|
*/
|
||||||
|
public static function all(array $promises) : Promise{
|
||||||
|
if(count($promises) === 0){
|
||||||
|
throw new \InvalidArgumentException("At least one promise must be provided");
|
||||||
|
}
|
||||||
|
/** @phpstan-var PromiseResolver<array<TKey, TPromiseValue>> $resolver */
|
||||||
|
$resolver = new PromiseResolver();
|
||||||
|
$values = [];
|
||||||
|
$toResolve = count($promises);
|
||||||
|
$continue = true;
|
||||||
|
|
||||||
|
foreach($promises as $key => $promise){
|
||||||
|
$promise->onCompletion(
|
||||||
|
function(mixed $value) use ($resolver, $key, $toResolve, &$values) : void{
|
||||||
|
$values[$key] = $value;
|
||||||
|
|
||||||
|
if(count($values) === $toResolve){
|
||||||
|
$resolver->resolve($values);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function() use ($resolver, &$continue) : void{
|
||||||
|
if($continue){
|
||||||
|
$continue = false;
|
||||||
|
$resolver->reject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!$continue){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $resolver->getPromise();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,10 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\scheduler;
|
namespace pocketmine\scheduler;
|
||||||
|
|
||||||
use pmmp\thread\Runnable;
|
use pmmp\thread\Runnable;
|
||||||
use pmmp\thread\Thread as NativeThread;
|
|
||||||
use pmmp\thread\ThreadSafe;
|
use pmmp\thread\ThreadSafe;
|
||||||
use pmmp\thread\ThreadSafeArray;
|
use pmmp\thread\ThreadSafeArray;
|
||||||
use pocketmine\thread\NonThreadSafeValue;
|
use pocketmine\thread\NonThreadSafeValue;
|
||||||
use function array_key_exists;
|
use function array_key_exists;
|
||||||
use function assert;
|
|
||||||
use function igbinary_serialize;
|
use function igbinary_serialize;
|
||||||
use function igbinary_unserialize;
|
use function igbinary_unserialize;
|
||||||
use function is_null;
|
use function is_null;
|
||||||
@ -83,9 +81,7 @@ abstract class AsyncTask extends Runnable{
|
|||||||
$this->onRun();
|
$this->onRun();
|
||||||
|
|
||||||
$this->finished = true;
|
$this->finished = true;
|
||||||
$worker = NativeThread::getCurrentThread();
|
AsyncWorker::getNotifier()->wakeupSleeper();
|
||||||
assert($worker instanceof AsyncWorker);
|
|
||||||
$worker->getNotifier()->wakeupSleeper();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,7 +36,7 @@ class AsyncWorker extends Worker{
|
|||||||
/** @var mixed[] */
|
/** @var mixed[] */
|
||||||
private static array $store = [];
|
private static array $store = [];
|
||||||
|
|
||||||
private const TLS_KEY_NOTIFIER = self::class . "::notifier";
|
private static ?SleeperNotifier $notifier = null;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private ThreadSafeLogger $logger,
|
private ThreadSafeLogger $logger,
|
||||||
@ -45,12 +45,11 @@ class AsyncWorker extends Worker{
|
|||||||
private SleeperHandlerEntry $sleeperEntry
|
private SleeperHandlerEntry $sleeperEntry
|
||||||
){}
|
){}
|
||||||
|
|
||||||
public function getNotifier() : SleeperNotifier{
|
public static function getNotifier() : SleeperNotifier{
|
||||||
$notifier = $this->getFromThreadStore(self::TLS_KEY_NOTIFIER);
|
if(self::$notifier !== null){
|
||||||
if(!$notifier instanceof SleeperNotifier){
|
return self::$notifier;
|
||||||
throw new AssumptionFailedError("SleeperNotifier not found in thread-local storage");
|
|
||||||
}
|
}
|
||||||
return $notifier;
|
throw new AssumptionFailedError("SleeperNotifier not found in thread-local storage");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function onRun() : void{
|
protected function onRun() : void{
|
||||||
@ -66,7 +65,7 @@ class AsyncWorker extends Worker{
|
|||||||
$this->logger->debug("No memory limit set");
|
$this->logger->debug("No memory limit set");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->saveToThreadStore(self::TLS_KEY_NOTIFIER, $this->sleeperEntry->createNotifier());
|
self::$notifier = $this->sleeperEntry->createNotifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLogger() : ThreadSafeLogger{
|
public function getLogger() : ThreadSafeLogger{
|
||||||
@ -84,6 +83,8 @@ class AsyncWorker extends Worker{
|
|||||||
/**
|
/**
|
||||||
* Saves mixed data into the worker's thread-local object store. This can be used to store objects which you
|
* Saves mixed data into the worker's thread-local object store. This can be used to store objects which you
|
||||||
* want to use on this worker thread from multiple AsyncTasks.
|
* want to use on this worker thread from multiple AsyncTasks.
|
||||||
|
*
|
||||||
|
* @deprecated Use static class properties instead.
|
||||||
*/
|
*/
|
||||||
public function saveToThreadStore(string $identifier, mixed $value) : void{
|
public function saveToThreadStore(string $identifier, mixed $value) : void{
|
||||||
if(NativeThread::getCurrentThread() !== $this){
|
if(NativeThread::getCurrentThread() !== $this){
|
||||||
@ -99,6 +100,8 @@ class AsyncWorker extends Worker{
|
|||||||
* account for the possibility that what you're trying to retrieve might not exist.
|
* account for the possibility that what you're trying to retrieve might not exist.
|
||||||
*
|
*
|
||||||
* Objects stored in this storage may ONLY be retrieved while the task is running.
|
* Objects stored in this storage may ONLY be retrieved while the task is running.
|
||||||
|
*
|
||||||
|
* @deprecated Use static class properties instead.
|
||||||
*/
|
*/
|
||||||
public function getFromThreadStore(string $identifier) : mixed{
|
public function getFromThreadStore(string $identifier) : mixed{
|
||||||
if(NativeThread::getCurrentThread() !== $this){
|
if(NativeThread::getCurrentThread() !== $this){
|
||||||
@ -109,6 +112,8 @@ class AsyncWorker extends Worker{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes previously-stored mixed data from the worker's thread-local object store.
|
* Removes previously-stored mixed data from the worker's thread-local object store.
|
||||||
|
*
|
||||||
|
* @deprecated Use static class properties instead.
|
||||||
*/
|
*/
|
||||||
public function removeFromThreadStore(string $identifier) : void{
|
public function removeFromThreadStore(string $identifier) : void{
|
||||||
if(NativeThread::getCurrentThread() !== $this){
|
if(NativeThread::getCurrentThread() !== $this){
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\thread;
|
namespace pocketmine\thread;
|
||||||
|
|
||||||
|
use pmmp\thread\Thread as NativeThread;
|
||||||
use pmmp\thread\ThreadSafeArray;
|
use pmmp\thread\ThreadSafeArray;
|
||||||
use pocketmine\errorhandler\ErrorToExceptionHandler;
|
use pocketmine\errorhandler\ErrorToExceptionHandler;
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
@ -77,9 +78,7 @@ trait CommonThreadPartsTrait{
|
|||||||
/**
|
/**
|
||||||
* Registers the class loaders for this thread.
|
* Registers the class loaders for this thread.
|
||||||
*
|
*
|
||||||
* WARNING: This method MUST be called from any descendent threads' run() method to make autoloading usable.
|
* @internal
|
||||||
* If you do not do this, you will not be able to use new classes that were not loaded when the thread was started
|
|
||||||
* (unless you are using a custom autoloader).
|
|
||||||
*/
|
*/
|
||||||
public function registerClassLoaders() : void{
|
public function registerClassLoaders() : void{
|
||||||
if($this->composerAutoloaderPath !== null){
|
if($this->composerAutoloaderPath !== null){
|
||||||
@ -96,6 +95,15 @@ trait CommonThreadPartsTrait{
|
|||||||
|
|
||||||
public function getCrashInfo() : ?ThreadCrashInfo{ return $this->crashInfo; }
|
public function getCrashInfo() : ?ThreadCrashInfo{ return $this->crashInfo; }
|
||||||
|
|
||||||
|
public function start(int $options = NativeThread::INHERIT_NONE) : bool{
|
||||||
|
ThreadManager::getInstance()->add($this);
|
||||||
|
|
||||||
|
if($this->getClassLoaders() === null){
|
||||||
|
$this->setClassLoaders();
|
||||||
|
}
|
||||||
|
return parent::start($options);
|
||||||
|
}
|
||||||
|
|
||||||
final public function run() : void{
|
final public function run() : void{
|
||||||
error_reporting(-1);
|
error_reporting(-1);
|
||||||
$this->registerClassLoaders();
|
$this->registerClassLoaders();
|
||||||
@ -110,6 +118,20 @@ trait CommonThreadPartsTrait{
|
|||||||
$this->isKilled = true;
|
$this->isKilled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
|
||||||
|
*/
|
||||||
|
public function quit() : void{
|
||||||
|
$this->isKilled = true;
|
||||||
|
|
||||||
|
if(!$this->isJoined()){
|
||||||
|
$this->notify();
|
||||||
|
$this->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadManager::getInstance()->remove($this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by set_exception_handler() when an uncaught exception is thrown.
|
* Called by set_exception_handler() when an uncaught exception is thrown.
|
||||||
*/
|
*/
|
||||||
|
@ -37,28 +37,4 @@ use pocketmine\scheduler\AsyncTask;
|
|||||||
*/
|
*/
|
||||||
abstract class Thread extends NativeThread{
|
abstract class Thread extends NativeThread{
|
||||||
use CommonThreadPartsTrait;
|
use CommonThreadPartsTrait;
|
||||||
|
|
||||||
public function start(int $options = NativeThread::INHERIT_NONE) : bool{
|
|
||||||
//this is intentionally not traitified
|
|
||||||
ThreadManager::getInstance()->add($this);
|
|
||||||
|
|
||||||
if($this->getClassLoaders() === null){
|
|
||||||
$this->setClassLoaders();
|
|
||||||
}
|
|
||||||
return parent::start($options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
|
|
||||||
*/
|
|
||||||
public function quit() : void{
|
|
||||||
$this->isKilled = true;
|
|
||||||
|
|
||||||
if(!$this->isJoined()){
|
|
||||||
$this->notify();
|
|
||||||
$this->join();
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadManager::getInstance()->remove($this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -51,12 +51,12 @@ class ThreadSafeClassLoader extends ThreadSafe{
|
|||||||
* @var ThreadSafeArray|string[]
|
* @var ThreadSafeArray|string[]
|
||||||
* @phpstan-var ThreadSafeArray<int, string>
|
* @phpstan-var ThreadSafeArray<int, string>
|
||||||
*/
|
*/
|
||||||
private $fallbackLookup;
|
private ThreadSafeArray $fallbackLookup;
|
||||||
/**
|
/**
|
||||||
* @var ThreadSafeArray|string[][]
|
* @var ThreadSafeArray|string[][]
|
||||||
* @phpstan-var ThreadSafeArray<string, ThreadSafeArray<int, string>>
|
* @phpstan-var ThreadSafeArray<string, ThreadSafeArray<int, string>>
|
||||||
*/
|
*/
|
||||||
private $psr4Lookup;
|
private ThreadSafeArray $psr4Lookup;
|
||||||
|
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
$this->fallbackLookup = new ThreadSafeArray();
|
$this->fallbackLookup = new ThreadSafeArray();
|
||||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\thread;
|
namespace pocketmine\thread;
|
||||||
|
|
||||||
use pmmp\thread\Thread as NativeThread;
|
|
||||||
use pmmp\thread\Worker as NativeWorker;
|
use pmmp\thread\Worker as NativeWorker;
|
||||||
use pocketmine\scheduler\AsyncTask;
|
use pocketmine\scheduler\AsyncTask;
|
||||||
|
|
||||||
@ -39,31 +38,4 @@ use pocketmine\scheduler\AsyncTask;
|
|||||||
*/
|
*/
|
||||||
abstract class Worker extends NativeWorker{
|
abstract class Worker extends NativeWorker{
|
||||||
use CommonThreadPartsTrait;
|
use CommonThreadPartsTrait;
|
||||||
|
|
||||||
public function start(int $options = NativeThread::INHERIT_NONE) : bool{
|
|
||||||
//this is intentionally not traitified
|
|
||||||
ThreadManager::getInstance()->add($this);
|
|
||||||
|
|
||||||
if($this->getClassLoaders() === null){
|
|
||||||
$this->setClassLoaders();
|
|
||||||
}
|
|
||||||
return parent::start($options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
|
|
||||||
*/
|
|
||||||
public function quit() : void{
|
|
||||||
$this->isKilled = true;
|
|
||||||
|
|
||||||
if(!$this->isShutdown()){
|
|
||||||
$this->synchronized(function() : void{
|
|
||||||
while($this->unstack() !== null);
|
|
||||||
});
|
|
||||||
$this->notify();
|
|
||||||
$this->shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadManager::getInstance()->remove($this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -210,8 +210,7 @@ abstract class Timings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-template T of object
|
* @phpstan-param class-string<covariant object> $class
|
||||||
* @phpstan-param class-string<T> $class
|
|
||||||
*/
|
*/
|
||||||
private static function shortenCoreClassName(string $class, string $prefix) : string{
|
private static function shortenCoreClassName(string $class, string $prefix) : string{
|
||||||
if(str_starts_with($class, $prefix)){
|
if(str_starts_with($class, $prefix)){
|
||||||
@ -302,8 +301,7 @@ abstract class Timings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-template TEvent of Event
|
* @phpstan-param class-string<covariant Event> $event
|
||||||
* @phpstan-param class-string<TEvent> $event
|
|
||||||
*/
|
*/
|
||||||
public static function getEventHandlerTimings(string $event, string $handlerName, string $group) : TimingsHandler{
|
public static function getEventHandlerTimings(string $event, string $handlerName, string $group) : TimingsHandler{
|
||||||
if(!isset(self::$eventHandlers[$event][$handlerName])){
|
if(!isset(self::$eventHandlers[$event][$handlerName])){
|
||||||
|
@ -129,10 +129,6 @@ class WorldManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$ev = new WorldUnloadEvent($world);
|
$ev = new WorldUnloadEvent($world);
|
||||||
if($world === $this->defaultWorld && !$forceUnload){
|
|
||||||
$ev->cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
$ev->call();
|
$ev->call();
|
||||||
|
|
||||||
if(!$forceUnload && $ev->isCancelled()){
|
if(!$forceUnload && $ev->isCancelled()){
|
||||||
|
@ -208,6 +208,7 @@ abstract class Noise{
|
|||||||
throw new \InvalidArgumentException("xSize % samplingRate must return 0");
|
throw new \InvalidArgumentException("xSize % samplingRate must return 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @phpstan-var \SplFixedArray<float> $noiseArray */
|
||||||
$noiseArray = new \SplFixedArray($xSize + 1);
|
$noiseArray = new \SplFixedArray($xSize + 1);
|
||||||
|
|
||||||
for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
|
for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
|
||||||
@ -217,7 +218,13 @@ abstract class Noise{
|
|||||||
for($xx = 0; $xx < $xSize; ++$xx){
|
for($xx = 0; $xx < $xSize; ++$xx){
|
||||||
if($xx % $samplingRate !== 0){
|
if($xx % $samplingRate !== 0){
|
||||||
$nx = (int) ($xx / $samplingRate) * $samplingRate;
|
$nx = (int) ($xx / $samplingRate) * $samplingRate;
|
||||||
$noiseArray[$xx] = self::linearLerp($xx, $nx, $nx + $samplingRate, $noiseArray[$nx], $noiseArray[$nx + $samplingRate]);
|
$noiseArray[$xx] = self::linearLerp(
|
||||||
|
x: $xx,
|
||||||
|
x1: $nx,
|
||||||
|
x2: $nx + $samplingRate,
|
||||||
|
q0: $noiseArray[$nx],
|
||||||
|
q1: $noiseArray[$nx + $samplingRate]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +241,7 @@ abstract class Noise{
|
|||||||
assert($xSize % $samplingRate === 0, new \InvalidArgumentException("xSize % samplingRate must return 0"));
|
assert($xSize % $samplingRate === 0, new \InvalidArgumentException("xSize % samplingRate must return 0"));
|
||||||
assert($zSize % $samplingRate === 0, new \InvalidArgumentException("zSize % samplingRate must return 0"));
|
assert($zSize % $samplingRate === 0, new \InvalidArgumentException("zSize % samplingRate must return 0"));
|
||||||
|
|
||||||
|
/** @phpstan-var \SplFixedArray<\SplFixedArray<float>> $noiseArray */
|
||||||
$noiseArray = new \SplFixedArray($xSize + 1);
|
$noiseArray = new \SplFixedArray($xSize + 1);
|
||||||
|
|
||||||
for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
|
for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
|
||||||
@ -253,9 +261,16 @@ abstract class Noise{
|
|||||||
$nx = (int) ($xx / $samplingRate) * $samplingRate;
|
$nx = (int) ($xx / $samplingRate) * $samplingRate;
|
||||||
$nz = (int) ($zz / $samplingRate) * $samplingRate;
|
$nz = (int) ($zz / $samplingRate) * $samplingRate;
|
||||||
$noiseArray[$xx][$zz] = Noise::bilinearLerp(
|
$noiseArray[$xx][$zz] = Noise::bilinearLerp(
|
||||||
$xx, $zz, $noiseArray[$nx][$nz], $noiseArray[$nx][$nz + $samplingRate],
|
x: $xx,
|
||||||
$noiseArray[$nx + $samplingRate][$nz], $noiseArray[$nx + $samplingRate][$nz + $samplingRate],
|
y: $zz,
|
||||||
$nx, $nx + $samplingRate, $nz, $nz + $samplingRate
|
q00: $noiseArray[$nx][$nz],
|
||||||
|
q01: $noiseArray[$nx][$nz + $samplingRate],
|
||||||
|
q10: $noiseArray[$nx + $samplingRate][$nz],
|
||||||
|
q11: $noiseArray[$nx + $samplingRate][$nz + $samplingRate],
|
||||||
|
x1: $nx,
|
||||||
|
x2: $nx + $samplingRate,
|
||||||
|
y1: $nz,
|
||||||
|
y2: $nz + $samplingRate
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1070,6 +1070,21 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/world/generator/hell/Nether.php
|
path: ../../../src/world/generator/hell/Nether.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Offset int does not exist on SplFixedArray\\<float\\>\\|null\\.$#"
|
||||||
|
count: 4
|
||||||
|
path: ../../../src/world/generator/noise/Noise.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Parameter \\$q0 of static method pocketmine\\\\world\\\\generator\\\\noise\\\\Noise\\:\\:linearLerp\\(\\) expects float, float\\|null given\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/world/generator/noise/Noise.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Parameter \\$q1 of static method pocketmine\\\\world\\\\generator\\\\noise\\\\Noise\\:\\:linearLerp\\(\\) expects float, float\\|null given\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/world/generator/noise/Noise.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#"
|
message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
parameters:
|
parameters:
|
||||||
ignoreErrors:
|
ignoreErrors:
|
||||||
-
|
|
||||||
message: "#^Instanceof between pocketmine\\\\block\\\\utils\\\\BannerPatternLayer and pocketmine\\\\block\\\\utils\\\\BannerPatternLayer will always evaluate to true\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/block/BaseBanner.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method pocketmine\\\\block\\\\CakeWithCandle\\:\\:onInteractCandle\\(\\) has parameter \\$returnedItems with no value type specified in iterable type array\\.$#"
|
message: "#^Method pocketmine\\\\block\\\\CakeWithCandle\\:\\:onInteractCandle\\(\\) has parameter \\$returnedItems with no value type specified in iterable type array\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@ -40,3 +35,18 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/world/generator/normal/Normal.php
|
path: ../../../src/world/generator/normal/Normal.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertFalse\\(\\) with false will always evaluate to true\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../phpunit/promise/PromiseTest.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertTrue\\(\\) with false and 'All promise should…' will always evaluate to false\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../phpunit/promise/PromiseTest.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertTrue\\(\\) with false will always evaluate to false\\.$#"
|
||||||
|
count: 2
|
||||||
|
path: ../../phpunit/promise/PromiseTest.php
|
||||||
|
|
||||||
|
@ -39,4 +39,110 @@ final class PromiseTest extends TestCase{
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAllPreResolved() : void{
|
||||||
|
$resolver = new PromiseResolver();
|
||||||
|
$resolver->resolve(1);
|
||||||
|
|
||||||
|
$allPromise = Promise::all([$resolver->getPromise()]);
|
||||||
|
$done = false;
|
||||||
|
$allPromise->onCompletion(
|
||||||
|
function($value) use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
self::assertEquals([1], $value);
|
||||||
|
},
|
||||||
|
function() use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
self::fail("Promise was rejected");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
self::assertTrue($done);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAllPostResolved() : void{
|
||||||
|
$resolver = new PromiseResolver();
|
||||||
|
|
||||||
|
$allPromise = Promise::all([$resolver->getPromise()]);
|
||||||
|
$done = false;
|
||||||
|
$allPromise->onCompletion(
|
||||||
|
function($value) use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
self::assertEquals([1], $value);
|
||||||
|
},
|
||||||
|
function() use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
self::fail("Promise was rejected");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
self::assertFalse($done);
|
||||||
|
$resolver->resolve(1);
|
||||||
|
self::assertTrue($done);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAllResolve() : void{
|
||||||
|
$resolver1 = new PromiseResolver();
|
||||||
|
$resolver2 = new PromiseResolver();
|
||||||
|
|
||||||
|
$allPromise = Promise::all([$resolver1->getPromise(), $resolver2->getPromise()]);
|
||||||
|
$done = false;
|
||||||
|
$allPromise->onCompletion(
|
||||||
|
function($value) use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
self::assertEquals([1, 2], $value);
|
||||||
|
},
|
||||||
|
function() use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
self::fail("Promise was rejected");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
self::assertFalse($done);
|
||||||
|
$resolver1->resolve(1);
|
||||||
|
self::assertFalse($done);
|
||||||
|
$resolver2->resolve(2);
|
||||||
|
self::assertTrue($done);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAllPartialReject() : void{
|
||||||
|
$resolver1 = new PromiseResolver();
|
||||||
|
$resolver2 = new PromiseResolver();
|
||||||
|
|
||||||
|
$allPromise = Promise::all([$resolver1->getPromise(), $resolver2->getPromise()]);
|
||||||
|
$done = false;
|
||||||
|
$allPromise->onCompletion(
|
||||||
|
function($value) use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
self::fail("Promise was unexpectedly resolved");
|
||||||
|
},
|
||||||
|
function() use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
self::assertFalse($done);
|
||||||
|
$resolver2->reject();
|
||||||
|
self::assertTrue($done, "All promise should be rejected immediately after the first constituent rejection");
|
||||||
|
$resolver1->resolve(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promise::all() should return a rejected promise if any of the input promises were rejected at the call time
|
||||||
|
*/
|
||||||
|
public function testAllPartialPreReject() : void{
|
||||||
|
$resolver1 = new PromiseResolver();
|
||||||
|
$resolver2 = new PromiseResolver();
|
||||||
|
$resolver2->reject();
|
||||||
|
|
||||||
|
$allPromise = Promise::all([$resolver1->getPromise(), $resolver2->getPromise()]);
|
||||||
|
$done = false;
|
||||||
|
$allPromise->onCompletion(
|
||||||
|
function($value) use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
self::fail("Promise was unexpectedly resolved");
|
||||||
|
},
|
||||||
|
function() use (&$done) : void{
|
||||||
|
$done = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
self::assertTrue($done, "All promise should be rejected immediately after the first constituent rejection");
|
||||||
|
$resolver1->resolve(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ use pocketmine\crafting\json\SmithingTransformRecipeData;
|
|||||||
use pocketmine\crafting\json\SmithingTrimRecipeData;
|
use pocketmine\crafting\json\SmithingTrimRecipeData;
|
||||||
use pocketmine\data\bedrock\block\BlockStateData;
|
use pocketmine\data\bedrock\block\BlockStateData;
|
||||||
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
||||||
|
use pocketmine\data\bedrock\item\ItemTypeNames;
|
||||||
use pocketmine\nbt\LittleEndianNbtSerializer;
|
use pocketmine\nbt\LittleEndianNbtSerializer;
|
||||||
use pocketmine\nbt\NBT;
|
use pocketmine\nbt\NBT;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
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\PacketPool;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
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\StartGamePacket;
|
||||||
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
|
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
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\ComplexAliasItemDescriptor;
|
||||||
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe;
|
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe;
|
||||||
use pocketmine\network\mcpe\protocol\types\recipe\IntIdMetaItemDescriptor;
|
use pocketmine\network\mcpe\protocol\types\recipe\IntIdMetaItemDescriptor;
|
||||||
@ -170,16 +171,21 @@ class ParserPacketHandler extends PacketHandler{
|
|||||||
$data->meta = $meta;
|
$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){
|
if($nbt !== null && count($nbt) > 0){
|
||||||
$data->nbt = base64_encode((new LittleEndianNbtSerializer())->write(new TreeRoot($nbt)));
|
$data->nbt = base64_encode((new LittleEndianNbtSerializer())->write(new TreeRoot($nbt)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count($itemStack->getCanPlaceOn()) > 0){
|
if(count($extraData->getCanPlaceOn()) > 0){
|
||||||
$data->can_place_on = $itemStack->getCanPlaceOn();
|
$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;
|
return $data;
|
||||||
@ -421,7 +427,7 @@ class ParserPacketHandler extends PacketHandler{
|
|||||||
$recipes["potion_type"][] = new PotionTypeRecipeData(
|
$recipes["potion_type"][] = new PotionTypeRecipeData(
|
||||||
$this->recipeIngredientToJson(new RecipeIngredient(new IntIdMetaItemDescriptor($recipe->getInputItemId(), $recipe->getInputItemMeta()), 1)),
|
$this->recipeIngredientToJson(new RecipeIngredient(new IntIdMetaItemDescriptor($recipe->getInputItemId(), $recipe->getInputItemMeta()), 1)),
|
||||||
$this->recipeIngredientToJson(new RecipeIngredient(new IntIdMetaItemDescriptor($recipe->getIngredientItemId(), $recipe->getIngredientItemMeta()), 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]);
|
fwrite(STDERR, "Unknown packet on line " . ($lineNum + 1) . ": " . $parts[1]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$serializer = PacketSerializer::decoder($raw, 0, new PacketSerializerContext(
|
$serializer = PacketSerializer::decoder($raw, 0);
|
||||||
$handler->itemTypeDictionary ??
|
|
||||||
new ItemTypeDictionary([new ItemTypeEntry("minecraft:shield", 0, false)]))
|
|
||||||
);
|
|
||||||
|
|
||||||
$pk->decode($serializer);
|
$pk->decode($serializer);
|
||||||
$pk->handle($handler);
|
$pk->handle($handler);
|
||||||
|
@ -40,6 +40,7 @@ use function get_class;
|
|||||||
use function json_encode;
|
use function json_encode;
|
||||||
use function ksort;
|
use function ksort;
|
||||||
use const JSON_PRETTY_PRINT;
|
use const JSON_PRETTY_PRINT;
|
||||||
|
use const SORT_NATURAL;
|
||||||
use const SORT_STRING;
|
use const SORT_STRING;
|
||||||
use const STDERR;
|
use const STDERR;
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ foreach($states as $state){
|
|||||||
|
|
||||||
foreach(Utils::stringifyKeys($reportMap) as $blockName => $propertyList){
|
foreach(Utils::stringifyKeys($reportMap) as $blockName => $propertyList){
|
||||||
foreach(Utils::stringifyKeys($propertyList) as $propertyName => $propertyValues){
|
foreach(Utils::stringifyKeys($propertyList) as $propertyName => $propertyValues){
|
||||||
ksort($reportMap[$blockName][$propertyName]);
|
ksort($propertyValues, SORT_NATURAL);
|
||||||
$reportMap[$blockName][$propertyName] = array_values($propertyValues);
|
$reportMap[$blockName][$propertyName] = array_values($propertyValues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user