mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-04 09:10:00 +00:00
Merge branch 'minor-next' into stable
This commit is contained in:
commit
61decaa2f8
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
|||||||
- name: Setup PHP and tools
|
- name: Setup PHP and tools
|
||||||
uses: shivammathur/setup-php@2.28.0
|
uses: shivammathur/setup-php@2.28.0
|
||||||
with:
|
with:
|
||||||
php-version: 8.1
|
php-version: 8.2
|
||||||
|
|
||||||
- name: Restore Composer package cache
|
- name: Restore Composer package cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
|
2
.github/workflows/draft-release.yml
vendored
2
.github/workflows/draft-release.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
php-version: [8.1]
|
php-version: [8.2]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -175,8 +175,8 @@ jobs:
|
|||||||
- name: Setup PHP and tools
|
- name: Setup PHP and tools
|
||||||
uses: shivammathur/setup-php@2.28.0
|
uses: shivammathur/setup-php@2.28.0
|
||||||
with:
|
with:
|
||||||
php-version: 8.1
|
php-version: 8.2
|
||||||
tools: php-cs-fixer:3.17
|
tools: php-cs-fixer:3.38
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
## Pre-requisites
|
## Pre-requisites
|
||||||
- A bash shell (git bash is sufficient for Windows)
|
- A bash shell (git bash is sufficient for Windows)
|
||||||
- [`git`](https://git-scm.com) available in your shell
|
- [`git`](https://git-scm.com) available in your shell
|
||||||
- PHP 8.1 or newer available in your shell
|
- PHP 8.2 or newer available in your shell
|
||||||
- [`composer`](https://getcomposer.org) available in your shell
|
- [`composer`](https://getcomposer.org) available in your shell
|
||||||
|
|
||||||
## Custom PHP binaries
|
## Custom PHP binaries
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit b0ffbdbe33cdfbb84b4214b7d516fdfbd34a13b5
|
Subproject commit 6dc09c57eb2a044b3c71e65fa3760dfcaed7fa5e
|
48
src/BootstrapOptions.php
Normal file
48
src/BootstrapOptions.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants for all the command-line options that PocketMine-MP supports.
|
||||||
|
* Other options not listed here can be used to override server.properties and pocketmine.yml values temporarily.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class BootstrapOptions{
|
||||||
|
|
||||||
|
private function __construct(){
|
||||||
|
//NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Disables the setup wizard on first startup */
|
||||||
|
public const NO_WIZARD = "no-wizard";
|
||||||
|
/** Force-disables console text colour and formatting */
|
||||||
|
public const DISABLE_ANSI = "disable-ansi";
|
||||||
|
/** Force-enables console text colour and formatting */
|
||||||
|
public const ENABLE_ANSI = "enable-ansi";
|
||||||
|
/** Path to look in for plugins */
|
||||||
|
public const PLUGINS = "plugins";
|
||||||
|
/** Path to store and load server data */
|
||||||
|
public const DATA = "data";
|
||||||
|
}
|
@ -274,8 +274,8 @@ JIT_WARNING
|
|||||||
ErrorToExceptionHandler::set();
|
ErrorToExceptionHandler::set();
|
||||||
|
|
||||||
$cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
|
$cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
|
||||||
$dataPath = getopt_string("data") ?? $cwd;
|
$dataPath = getopt_string(BootstrapOptions::DATA) ?? $cwd;
|
||||||
$pluginPath = getopt_string("plugins") ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
$pluginPath = getopt_string(BootstrapOptions::PLUGINS) ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
||||||
Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX);
|
Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX);
|
||||||
|
|
||||||
if(!@mkdir($dataPath, 0777, true) && !is_dir($dataPath)){
|
if(!@mkdir($dataPath, 0777, true) && !is_dir($dataPath)){
|
||||||
@ -308,10 +308,10 @@ JIT_WARNING
|
|||||||
//Logger has a dependency on timezone
|
//Logger has a dependency on timezone
|
||||||
Timezone::init();
|
Timezone::init();
|
||||||
|
|
||||||
$opts = getopt("", ["no-wizard", "enable-ansi", "disable-ansi"]);
|
$opts = getopt("", [BootstrapOptions::NO_WIZARD, BootstrapOptions::ENABLE_ANSI, BootstrapOptions::DISABLE_ANSI]);
|
||||||
if(isset($opts["enable-ansi"])){
|
if(isset($opts[BootstrapOptions::ENABLE_ANSI])){
|
||||||
Terminal::init(true);
|
Terminal::init(true);
|
||||||
}elseif(isset($opts["disable-ansi"])){
|
}elseif(isset($opts[BootstrapOptions::DISABLE_ANSI])){
|
||||||
Terminal::init(false);
|
Terminal::init(false);
|
||||||
}else{
|
}else{
|
||||||
Terminal::init();
|
Terminal::init();
|
||||||
@ -324,7 +324,7 @@ JIT_WARNING
|
|||||||
|
|
||||||
$exitCode = 0;
|
$exitCode = 0;
|
||||||
do{
|
do{
|
||||||
if(!file_exists(Path::join($dataPath, "server.properties")) && !isset($opts["no-wizard"])){
|
if(!file_exists(Path::join($dataPath, "server.properties")) && !isset($opts[BootstrapOptions::NO_WIZARD])){
|
||||||
$installer = new SetupWizard($dataPath);
|
$installer = new SetupWizard($dataPath);
|
||||||
if(!$installer->run()){
|
if(!$installer->run()){
|
||||||
$exitCode = -1;
|
$exitCode = -1;
|
||||||
|
@ -523,7 +523,7 @@ class Server{
|
|||||||
return $this->playerDataProvider->loadData($name);
|
return $this->playerDataProvider->loadData($name);
|
||||||
}catch(PlayerDataLoadException $e){
|
}catch(PlayerDataLoadException $e){
|
||||||
$this->logger->debug("Failed to load player data for $name: " . $e->getMessage());
|
$this->logger->debug("Failed to load player data for $name: " . $e->getMessage());
|
||||||
$this->logger->error($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
$this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -542,7 +542,7 @@ class Server{
|
|||||||
try{
|
try{
|
||||||
$this->playerDataProvider->saveData($name, $ev->getSaveData());
|
$this->playerDataProvider->saveData($name, $ev->getSaveData());
|
||||||
}catch(PlayerDataSaveException $e){
|
}catch(PlayerDataSaveException $e){
|
||||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
$this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
||||||
$this->logger->logException($e);
|
$this->logger->logException($e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -854,7 +854,7 @@ class Server{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::language_selected($this->getLanguage()->getName(), $this->getLanguage()->getLang())));
|
$this->logger->info($this->language->translate(KnownTranslationFactory::language_selected($this->language->getName(), $this->language->getLang())));
|
||||||
|
|
||||||
if(VersionInfo::IS_DEVELOPMENT_BUILD){
|
if(VersionInfo::IS_DEVELOPMENT_BUILD){
|
||||||
if(!$this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_DEV_BUILDS, false)){
|
if(!$this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_DEV_BUILDS, false)){
|
||||||
@ -877,7 +877,7 @@ class Server{
|
|||||||
|
|
||||||
$this->memoryManager = new MemoryManager($this);
|
$this->memoryManager = new MemoryManager($this);
|
||||||
|
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
|
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
|
||||||
|
|
||||||
if(($poolSize = $this->configGroup->getPropertyString(Yml::SETTINGS_ASYNC_WORKERS, "auto")) === "auto"){
|
if(($poolSize = $this->configGroup->getPropertyString(Yml::SETTINGS_ASYNC_WORKERS, "auto")) === "auto"){
|
||||||
$poolSize = 2;
|
$poolSize = 2;
|
||||||
@ -937,11 +937,11 @@ class Server{
|
|||||||
|
|
||||||
$this->onlineMode = $this->configGroup->getConfigBool(ServerProperties::XBOX_AUTH, true);
|
$this->onlineMode = $this->configGroup->getConfigBool(ServerProperties::XBOX_AUTH, true);
|
||||||
if($this->onlineMode){
|
if($this->onlineMode){
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
|
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
|
||||||
}else{
|
}else{
|
||||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_disabled()));
|
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_disabled()));
|
||||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authWarning()));
|
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authWarning()));
|
||||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||||
@ -952,17 +952,17 @@ class Server{
|
|||||||
|
|
||||||
$this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort());
|
$this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort());
|
||||||
|
|
||||||
$this->getLogger()->debug("Server unique id: " . $this->getServerUniqueId());
|
$this->logger->debug("Server unique id: " . $this->getServerUniqueId());
|
||||||
$this->getLogger()->debug("Machine unique id: " . Utils::getMachineUniqueId());
|
$this->logger->debug("Machine unique id: " . Utils::getMachineUniqueId());
|
||||||
|
|
||||||
$this->network = new Network($this->logger);
|
$this->network = new Network($this->logger);
|
||||||
$this->network->setName($this->getMotd());
|
$this->network->setName($this->getMotd());
|
||||||
|
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_info(
|
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_info(
|
||||||
$this->getName(),
|
$this->getName(),
|
||||||
(VersionInfo::IS_DEVELOPMENT_BUILD ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET
|
(VersionInfo::IS_DEVELOPMENT_BUILD ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET
|
||||||
)));
|
)));
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||||
|
|
||||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
|
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
|
||||||
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
|
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
|
||||||
@ -973,7 +973,7 @@ class Server{
|
|||||||
|
|
||||||
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes"));
|
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes"));
|
||||||
|
|
||||||
$this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger);
|
$this->resourceManager = new ResourcePackManager(Path::join($this->dataPath, "resource_packs"), $this->logger);
|
||||||
|
|
||||||
$pluginGraylist = null;
|
$pluginGraylist = null;
|
||||||
$graylistFile = Path::join($this->dataPath, "plugin_list.yml");
|
$graylistFile = Path::join($this->dataPath, "plugin_list.yml");
|
||||||
@ -987,7 +987,7 @@ class Server{
|
|||||||
$this->forceShutdownExit();
|
$this->forceShutdownExit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
|
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->dataPath, "plugin_data"), $pluginGraylist);
|
||||||
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||||
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||||
|
|
||||||
@ -1049,9 +1049,9 @@ class Server{
|
|||||||
|
|
||||||
$this->configGroup->save();
|
$this->configGroup->save();
|
||||||
|
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
|
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
|
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
|
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
|
||||||
|
|
||||||
$forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language);
|
$forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language);
|
||||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $forwarder);
|
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $forwarder);
|
||||||
@ -1139,13 +1139,13 @@ class Server{
|
|||||||
if($this->worldManager->getDefaultWorld() === null){
|
if($this->worldManager->getDefaultWorld() === null){
|
||||||
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||||
if(trim($default) == ""){
|
if(trim($default) == ""){
|
||||||
$this->getLogger()->warning("level-name cannot be null, using default");
|
$this->logger->warning("level-name cannot be null, using default");
|
||||||
$default = "world";
|
$default = "world";
|
||||||
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||||
}
|
}
|
||||||
if(!$this->worldManager->loadWorld($default, true)){
|
if(!$this->worldManager->loadWorld($default, true)){
|
||||||
if($this->worldManager->isWorldGenerated($default)){
|
if($this->worldManager->isWorldGenerated($default)){
|
||||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1154,7 +1154,7 @@ class Server{
|
|||||||
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
|
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
|
||||||
|
|
||||||
if($generatorClass === null){
|
if($generatorClass === null){
|
||||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$creationOptions = WorldCreationOptions::create()
|
$creationOptions = WorldCreationOptions::create()
|
||||||
@ -1200,7 +1200,7 @@ class Server{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if($rakLibRegistered){
|
if($rakLibRegistered){
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
|
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
|
||||||
}
|
}
|
||||||
if($useQuery){
|
if($useQuery){
|
||||||
if(!$rakLibRegistered){
|
if(!$rakLibRegistered){
|
||||||
@ -1208,7 +1208,7 @@ class Server{
|
|||||||
//if it's not registered we need to make sure Query still works
|
//if it's not registered we need to make sure Query still works
|
||||||
$this->network->registerInterface(new DedicatedQueryNetworkInterface($ip, $port, $ipV6, new \PrefixedLogger($this->logger, "Dedicated Query Interface")));
|
$this->network->registerInterface(new DedicatedQueryNetworkInterface($ip, $port, $ipV6, new \PrefixedLogger($this->logger, "Dedicated Query Interface")));
|
||||||
}
|
}
|
||||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
|
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1368,7 +1368,7 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null).
|
* @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null).
|
||||||
*/
|
*/
|
||||||
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise{
|
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise|string{
|
||||||
$timings ??= Timings::$playerNetworkSendCompress;
|
$timings ??= Timings::$playerNetworkSendCompress;
|
||||||
try{
|
try{
|
||||||
$timings->startTiming();
|
$timings->startTiming();
|
||||||
@ -1378,15 +1378,14 @@ class Server{
|
|||||||
$sync = !$this->networkCompressionAsync || $threshold === null || strlen($buffer) < $threshold;
|
$sync = !$this->networkCompressionAsync || $threshold === null || strlen($buffer) < $threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
$promise = new CompressBatchPromise();
|
|
||||||
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
|
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
|
||||||
|
$promise = new CompressBatchPromise();
|
||||||
$task = new CompressBatchTask($buffer, $promise, $compressor);
|
$task = new CompressBatchTask($buffer, $promise, $compressor);
|
||||||
$this->asyncPool->submitTask($task);
|
$this->asyncPool->submitTask($task);
|
||||||
}else{
|
return $promise;
|
||||||
$promise->resolve($compressor->compress($buffer));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $promise;
|
return $compressor->compress($buffer);
|
||||||
}finally{
|
}finally{
|
||||||
$timings->stopTiming();
|
$timings->stopTiming();
|
||||||
}
|
}
|
||||||
@ -1463,7 +1462,7 @@ class Server{
|
|||||||
$this->shutdown();
|
$this->shutdown();
|
||||||
|
|
||||||
if(isset($this->pluginManager)){
|
if(isset($this->pluginManager)){
|
||||||
$this->getLogger()->debug("Disabling all plugins");
|
$this->logger->debug("Disabling all plugins");
|
||||||
$this->pluginManager->disablePlugins();
|
$this->pluginManager->disablePlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1472,34 +1471,34 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(isset($this->worldManager)){
|
if(isset($this->worldManager)){
|
||||||
$this->getLogger()->debug("Unloading all worlds");
|
$this->logger->debug("Unloading all worlds");
|
||||||
foreach($this->worldManager->getWorlds() as $world){
|
foreach($this->worldManager->getWorlds() as $world){
|
||||||
$this->worldManager->unloadWorld($world, true);
|
$this->worldManager->unloadWorld($world, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLogger()->debug("Removing event handlers");
|
$this->logger->debug("Removing event handlers");
|
||||||
HandlerListManager::global()->unregisterAll();
|
HandlerListManager::global()->unregisterAll();
|
||||||
|
|
||||||
if(isset($this->asyncPool)){
|
if(isset($this->asyncPool)){
|
||||||
$this->getLogger()->debug("Shutting down async task worker pool");
|
$this->logger->debug("Shutting down async task worker pool");
|
||||||
$this->asyncPool->shutdown();
|
$this->asyncPool->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($this->configGroup)){
|
if(isset($this->configGroup)){
|
||||||
$this->getLogger()->debug("Saving properties");
|
$this->logger->debug("Saving properties");
|
||||||
$this->configGroup->save();
|
$this->configGroup->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->console !== null){
|
if($this->console !== null){
|
||||||
$this->getLogger()->debug("Closing console");
|
$this->logger->debug("Closing console");
|
||||||
$this->console->quit();
|
$this->console->quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($this->network)){
|
if(isset($this->network)){
|
||||||
$this->getLogger()->debug("Stopping network interfaces");
|
$this->logger->debug("Stopping network interfaces");
|
||||||
foreach($this->network->getInterfaces() as $interface){
|
foreach($this->network->getInterfaces() as $interface){
|
||||||
$this->getLogger()->debug("Stopping network interface " . get_class($interface));
|
$this->logger->debug("Stopping network interface " . get_class($interface));
|
||||||
$this->network->unregisterInterface($interface);
|
$this->network->unregisterInterface($interface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1567,7 +1566,7 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function writeCrashDumpFile(CrashDump $dump) : string{
|
private function writeCrashDumpFile(CrashDump $dump) : string{
|
||||||
$crashFolder = Path::join($this->getDataPath(), "crashdumps");
|
$crashFolder = Path::join($this->dataPath, "crashdumps");
|
||||||
if(!is_dir($crashFolder)){
|
if(!is_dir($crashFolder)){
|
||||||
mkdir($crashFolder);
|
mkdir($crashFolder);
|
||||||
}
|
}
|
||||||
@ -1598,17 +1597,17 @@ class Server{
|
|||||||
ini_set("error_reporting", '0');
|
ini_set("error_reporting", '0');
|
||||||
ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems
|
ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems
|
||||||
try{
|
try{
|
||||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_create()));
|
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_create()));
|
||||||
$dump = new CrashDump($this, $this->pluginManager ?? null);
|
$dump = new CrashDump($this, $this->pluginManager ?? null);
|
||||||
|
|
||||||
$crashDumpPath = $this->writeCrashDumpFile($dump);
|
$crashDumpPath = $this->writeCrashDumpFile($dump);
|
||||||
|
|
||||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
|
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
|
||||||
|
|
||||||
if($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_ENABLED, true)){
|
if($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_ENABLED, true)){
|
||||||
$report = true;
|
$report = true;
|
||||||
|
|
||||||
$stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash");
|
$stamp = Path::join($this->dataPath, "crashdumps", ".last_crash");
|
||||||
$crashInterval = 120; //2 minutes
|
$crashInterval = 120; //2 minutes
|
||||||
if(($lastReportTime = @filemtime($stamp)) !== false && $lastReportTime + $crashInterval >= time()){
|
if(($lastReportTime = @filemtime($stamp)) !== false && $lastReportTime + $crashInterval >= time()){
|
||||||
$report = false;
|
$report = false;
|
||||||
@ -1639,7 +1638,7 @@ class Server{
|
|||||||
if(isset($data->crashId) && is_int($data->crashId) && isset($data->crashUrl) && is_string($data->crashUrl)){
|
if(isset($data->crashId) && is_int($data->crashId) && isset($data->crashUrl) && is_string($data->crashUrl)){
|
||||||
$reportId = $data->crashId;
|
$reportId = $data->crashId;
|
||||||
$reportUrl = $data->crashUrl;
|
$reportUrl = $data->crashUrl;
|
||||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
|
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
|
||||||
}elseif(isset($data->error) && is_string($data->error)){
|
}elseif(isset($data->error) && is_string($data->error)){
|
||||||
$this->logger->emergency("Automatic crash report submission failed: $data->error");
|
$this->logger->emergency("Automatic crash report submission failed: $data->error");
|
||||||
}else{
|
}else{
|
||||||
@ -1653,7 +1652,7 @@ class Server{
|
|||||||
}catch(\Throwable $e){
|
}catch(\Throwable $e){
|
||||||
$this->logger->logException($e);
|
$this->logger->logException($e);
|
||||||
try{
|
try{
|
||||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage())));
|
$this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage())));
|
||||||
}catch(\Throwable $e){}
|
}catch(\Throwable $e){}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1771,7 +1770,7 @@ class Server{
|
|||||||
|
|
||||||
echo "\x1b]0;" . $this->getName() . " " .
|
echo "\x1b]0;" . $this->getName() . " " .
|
||||||
$this->getPocketMineVersion() .
|
$this->getPocketMineVersion() .
|
||||||
" | Online $online/" . $this->getMaxPlayers() .
|
" | Online $online/" . $this->maxPlayers .
|
||||||
($connecting > 0 ? " (+$connecting connecting)" : "") .
|
($connecting > 0 ? " (+$connecting connecting)" : "") .
|
||||||
" | Memory " . $usage .
|
" | Memory " . $usage .
|
||||||
" | U " . round($bandwidthStats->getSend()->getAverageBytes() / 1024, 2) .
|
" | U " . round($bandwidthStats->getSend()->getAverageBytes() / 1024, 2) .
|
||||||
@ -1836,10 +1835,10 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(($this->tickCounter % self::TICKS_PER_TPS_OVERLOAD_WARNING) === 0 && $this->getTicksPerSecondAverage() < self::TPS_OVERLOAD_WARNING_THRESHOLD){
|
if(($this->tickCounter % self::TICKS_PER_TPS_OVERLOAD_WARNING) === 0 && $this->getTicksPerSecondAverage() < self::TPS_OVERLOAD_WARNING_THRESHOLD){
|
||||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getMemoryManager()->check();
|
$this->memoryManager->check();
|
||||||
|
|
||||||
if($this->console !== null){
|
if($this->console !== null){
|
||||||
Timings::$serverCommand->startTiming();
|
Timings::$serverCommand->startTiming();
|
||||||
|
@ -24,7 +24,9 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine;
|
namespace pocketmine;
|
||||||
|
|
||||||
use pocketmine\snooze\SleeperHandler;
|
use pocketmine\snooze\SleeperHandler;
|
||||||
|
use pocketmine\snooze\SleeperHandlerEntry;
|
||||||
use pocketmine\timings\TimingsHandler;
|
use pocketmine\timings\TimingsHandler;
|
||||||
|
use pocketmine\utils\Utils;
|
||||||
use function hrtime;
|
use function hrtime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,12 +37,29 @@ final class TimeTrackingSleeperHandler extends SleeperHandler{
|
|||||||
|
|
||||||
private int $notificationProcessingTimeNs = 0;
|
private int $notificationProcessingTimeNs = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var TimingsHandler[]
|
||||||
|
* @phpstan-var array<string, TimingsHandler>
|
||||||
|
*/
|
||||||
|
private static array $handlerTimings = [];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private TimingsHandler $timings
|
private TimingsHandler $timings
|
||||||
){
|
){
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addNotifier(\Closure $handler) : SleeperHandlerEntry{
|
||||||
|
$name = Utils::getNiceClosureName($handler);
|
||||||
|
$timings = self::$handlerTimings[$name] ??= new TimingsHandler("Snooze Handler: " . $name, $this->timings);
|
||||||
|
|
||||||
|
return parent::addNotifier(function() use ($timings, $handler) : void{
|
||||||
|
$timings->startTiming();
|
||||||
|
$handler();
|
||||||
|
$timings->stopTiming();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the time in nanoseconds spent processing notifications since the last reset.
|
* Returns the time in nanoseconds spent processing notifications since the last reset.
|
||||||
*/
|
*/
|
||||||
|
@ -173,7 +173,7 @@ class Bamboo extends Transparent{
|
|||||||
$newHeight = $height + $growAmount;
|
$newHeight = $height + $growAmount;
|
||||||
|
|
||||||
$stemBlock = (clone $this)->setReady(false)->setLeafSize(self::NO_LEAVES);
|
$stemBlock = (clone $this)->setReady(false)->setLeafSize(self::NO_LEAVES);
|
||||||
if($newHeight >= 4 && !$stemBlock->isThick()){ //don't change it to false if height is less, because it might have been chopped
|
if($newHeight >= 4 && !$stemBlock->thick){ //don't change it to false if height is less, because it might have been chopped
|
||||||
$stemBlock = $stemBlock->setThick(true);
|
$stemBlock = $stemBlock->setThick(true);
|
||||||
}
|
}
|
||||||
$smallLeavesBlock = (clone $stemBlock)->setLeafSize(self::SMALL_LEAVES);
|
$smallLeavesBlock = (clone $stemBlock)->setLeafSize(self::SMALL_LEAVES);
|
||||||
|
@ -55,12 +55,12 @@ class Barrel extends Opaque{
|
|||||||
|
|
||||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||||
if($player !== null){
|
if($player !== null){
|
||||||
if(abs($player->getPosition()->getX() - $this->position->getX()) < 2 && abs($player->getPosition()->getZ() - $this->position->getZ()) < 2){
|
if(abs($player->getPosition()->x - $this->position->x) < 2 && abs($player->getPosition()->z - $this->position->z) < 2){
|
||||||
$y = $player->getEyePos()->getY();
|
$y = $player->getEyePos()->y;
|
||||||
|
|
||||||
if($y - $this->position->getY() > 2){
|
if($y - $this->position->y > 2){
|
||||||
$this->facing = Facing::UP;
|
$this->facing = Facing::UP;
|
||||||
}elseif($this->position->getY() - $y > 0){
|
}elseif($this->position->y - $y > 0){
|
||||||
$this->facing = Facing::DOWN;
|
$this->facing = Facing::DOWN;
|
||||||
}else{
|
}else{
|
||||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||||
|
@ -65,8 +65,8 @@ abstract class BaseBigDripleaf extends Transparent{
|
|||||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||||
}
|
}
|
||||||
if($block instanceof BaseBigDripleaf){
|
if($block instanceof BaseBigDripleaf){
|
||||||
$this->facing = $block->getFacing();
|
$this->facing = $block->facing;
|
||||||
$tx->addBlock($block->getPosition(), VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($this->facing));
|
$tx->addBlock($block->position, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($this->facing));
|
||||||
}
|
}
|
||||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ abstract class BaseBigDripleaf extends Transparent{
|
|||||||
if($head === null){
|
if($head === null){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$pos = $head->getPosition();
|
$pos = $head->position;
|
||||||
$up = $pos->up();
|
$up = $pos->up();
|
||||||
$world = $pos->getWorld();
|
$world = $pos->getWorld();
|
||||||
if(
|
if(
|
||||||
@ -110,8 +110,8 @@ abstract class BaseBigDripleaf extends Transparent{
|
|||||||
|
|
||||||
$tx = new BlockTransaction($world);
|
$tx = new BlockTransaction($world);
|
||||||
|
|
||||||
$tx->addBlock($pos, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($head->getFacing()));
|
$tx->addBlock($pos, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($head->facing));
|
||||||
$tx->addBlock($up, VanillaBlocks::BIG_DRIPLEAF_HEAD()->setFacing($head->getFacing()));
|
$tx->addBlock($up, VanillaBlocks::BIG_DRIPLEAF_HEAD()->setFacing($head->facing));
|
||||||
|
|
||||||
$ev = new StructureGrowEvent($head, $tx, $player);
|
$ev = new StructureGrowEvent($head, $tx, $player);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
|
@ -145,7 +145,7 @@ class Bed extends Transparent{
|
|||||||
|
|
||||||
$b = ($this->isHeadPart() ? $this : $other);
|
$b = ($this->isHeadPart() ? $this : $other);
|
||||||
|
|
||||||
if($b->isOccupied()){
|
if($b->occupied){
|
||||||
$player->sendMessage(KnownTranslationFactory::tile_bed_occupied()->prefix(TextFormat::GRAY));
|
$player->sendMessage(KnownTranslationFactory::tile_bed_occupied()->prefix(TextFormat::GRAY));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -270,11 +270,22 @@ class Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function encodeFullState() : int{
|
private function encodeFullState() : int{
|
||||||
$writer = new RuntimeDataWriter($this->requiredBlockItemStateDataBits + $this->requiredBlockOnlyStateDataBits);
|
$blockItemBits = $this->requiredBlockItemStateDataBits;
|
||||||
$writer->writeInt($this->requiredBlockItemStateDataBits, $this->encodeBlockItemState());
|
$blockOnlyBits = $this->requiredBlockOnlyStateDataBits;
|
||||||
$writer->writeInt($this->requiredBlockOnlyStateDataBits, $this->encodeBlockOnlyState());
|
|
||||||
|
|
||||||
return $writer->getValue();
|
if($blockOnlyBits === 0 && $blockItemBits === 0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = 0;
|
||||||
|
if($blockItemBits > 0){
|
||||||
|
$result |= $this->encodeBlockItemState();
|
||||||
|
}
|
||||||
|
if($blockOnlyBits > 0){
|
||||||
|
$result |= $this->encodeBlockOnlyState() << $blockItemBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,7 +97,7 @@ class ChiseledBookshelf extends Opaque{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$x = Facing::axis($face) === Axis::X ? $clickVector->getZ() : $clickVector->getX();
|
$x = Facing::axis($face) === Axis::X ? $clickVector->z : $clickVector->x;
|
||||||
$slot = ChiseledBookshelfSlot::fromBlockFaceCoordinates(
|
$slot = ChiseledBookshelfSlot::fromBlockFaceCoordinates(
|
||||||
Facing::isPositive(Facing::rotateY($face, true)) ? 1 - $x : $x,
|
Facing::isPositive(Facing::rotateY($face, true)) ? 1 - $x : $x,
|
||||||
$clickVector->y
|
$clickVector->y
|
||||||
|
@ -54,7 +54,7 @@ final class ChorusFlower extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function canBeSupportedAt(Block $block) : bool{
|
private function canBeSupportedAt(Block $block) : bool{
|
||||||
$position = $block->getPosition();
|
$position = $block->position;
|
||||||
$world = $position->getWorld();
|
$world = $position->getWorld();
|
||||||
$down = $world->getBlock($position->down());
|
$down = $world->getBlock($position->down());
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ final class ChorusFlower extends Flowable{
|
|||||||
if($tx === null){
|
if($tx === null){
|
||||||
$tx = new BlockTransaction($this->position->getWorld());
|
$tx = new BlockTransaction($this->position->getWorld());
|
||||||
}
|
}
|
||||||
$tx->addBlock($this->position->getSide($facing), (clone $this)->setAge(min(self::MAX_AGE, $this->getAge() + $ageChange)));
|
$tx->addBlock($this->position->getSide($facing), (clone $this)->setAge(min(self::MAX_AGE, $this->age + $ageChange)));
|
||||||
|
|
||||||
return $tx;
|
return $tx;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ final class ChorusPlant extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function canBeSupportedAt(Block $block) : bool{
|
private function canBeSupportedAt(Block $block) : bool{
|
||||||
$position = $block->getPosition();
|
$position = $block->position;
|
||||||
$world = $position->getWorld();
|
$world = $position->getWorld();
|
||||||
|
|
||||||
$down = $world->getBlock($position->down());
|
$down = $world->getBlock($position->down());
|
||||||
|
@ -25,6 +25,7 @@ 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\CropGrowthHelper;
|
||||||
use pocketmine\block\utils\StaticSupportTrait;
|
use pocketmine\block\utils\StaticSupportTrait;
|
||||||
use pocketmine\item\Fertilizer;
|
use pocketmine\item\Fertilizer;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
@ -66,7 +67,7 @@ abstract class Crops extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onRandomTick() : void{
|
public function onRandomTick() : void{
|
||||||
if($this->age < self::MAX_AGE && mt_rand(0, 2) === 1){
|
if($this->age < self::MAX_AGE && CropGrowthHelper::canGrow($this)){
|
||||||
$block = clone $this;
|
$block = clone $this;
|
||||||
++$block->age;
|
++$block->age;
|
||||||
BlockEventHelper::grow($this, $block, null);
|
BlockEventHelper::grow($this, $block, null);
|
||||||
|
@ -24,17 +24,18 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\utils\AgeableTrait;
|
use pocketmine\block\utils\AgeableTrait;
|
||||||
|
use pocketmine\block\utils\CropGrowthHelper;
|
||||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||||
use pocketmine\event\block\StructureGrowEvent;
|
use pocketmine\event\block\StructureGrowEvent;
|
||||||
use pocketmine\item\Fertilizer;
|
use pocketmine\item\Fertilizer;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\VanillaItems;
|
||||||
use pocketmine\math\Axis;
|
use pocketmine\math\Axis;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Facing;
|
use pocketmine\math\Facing;
|
||||||
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 mt_rand;
|
|
||||||
|
|
||||||
final class DoublePitcherCrop extends DoublePlant{
|
final class DoublePitcherCrop extends DoublePlant{
|
||||||
use AgeableTrait {
|
use AgeableTrait {
|
||||||
@ -101,10 +102,19 @@ final class DoublePitcherCrop extends DoublePlant{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onRandomTick() : void{
|
public function onRandomTick() : void{
|
||||||
//TODO: the growth speed is influenced by farmland and nearby crops
|
|
||||||
//only the bottom half of the plant can grow randomly
|
//only the bottom half of the plant can grow randomly
|
||||||
if(mt_rand(0, 2) === 0 && !$this->top){
|
if(CropGrowthHelper::canGrow($this) && !$this->top){
|
||||||
$this->grow(null);
|
$this->grow(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
|
return [
|
||||||
|
$this->age >= self::MAX_AGE ? VanillaBlocks::PITCHER_PLANT()->asItem() : VanillaItems::PITCHER_POD()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asItem() : Item{
|
||||||
|
return VanillaItems::PITCHER_POD();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ class Farmland extends Transparent{
|
|||||||
$ev = new EntityTrampleFarmlandEvent($entity, $this);
|
$ev = new EntityTrampleFarmlandEvent($entity, $this);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->getPosition()->getWorld()->setBlock($this->getPosition(), VanillaBlocks::DIRT());
|
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::DIRT());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -140,7 +140,7 @@ class Fire extends BaseFire{
|
|||||||
$block->onIncinerate();
|
$block->onIncinerate();
|
||||||
|
|
||||||
$world = $this->position->getWorld();
|
$world = $this->position->getWorld();
|
||||||
if($world->getBlock($block->getPosition())->isSameState($block)){
|
if($world->getBlock($block->position)->isSameState($block)){
|
||||||
$spreadedFire = false;
|
$spreadedFire = false;
|
||||||
if(mt_rand(0, $this->age + 9) < 5){ //TODO: check rain
|
if(mt_rand(0, $this->age + 9) < 5){ //TODO: check rain
|
||||||
$fire = clone $this;
|
$fire = clone $this;
|
||||||
|
@ -58,7 +58,7 @@ final class FloorCoralFan extends BaseCoral{
|
|||||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||||
if($player !== null){
|
if($player !== null){
|
||||||
$playerBlockPos = $player->getPosition()->floor();
|
$playerBlockPos = $player->getPosition()->floor();
|
||||||
$directionVector = $blockReplace->getPosition()->subtractVector($playerBlockPos)->normalize();
|
$directionVector = $blockReplace->position->subtractVector($playerBlockPos)->normalize();
|
||||||
$angle = rad2deg(atan2($directionVector->getZ(), $directionVector->getX()));
|
$angle = rad2deg(atan2($directionVector->getZ(), $directionVector->getX()));
|
||||||
|
|
||||||
if($angle <= 45 || 315 <= $angle || (135 <= $angle && $angle <= 225)){
|
if($angle <= 45 || 315 <= $angle || (135 <= $angle && $angle <= 225)){
|
||||||
|
@ -61,7 +61,7 @@ class Jukebox extends Opaque{
|
|||||||
|
|
||||||
public function ejectRecord() : void{
|
public function ejectRecord() : void{
|
||||||
if($this->record !== null){
|
if($this->record !== null){
|
||||||
$this->getPosition()->getWorld()->dropItem($this->getPosition()->add(0.5, 1, 0.5), $this->record);
|
$this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $this->record);
|
||||||
$this->record = null;
|
$this->record = null;
|
||||||
$this->stopSound();
|
$this->stopSound();
|
||||||
}
|
}
|
||||||
@ -76,12 +76,12 @@ class Jukebox extends Opaque{
|
|||||||
|
|
||||||
public function startSound() : void{
|
public function startSound() : void{
|
||||||
if($this->record !== null){
|
if($this->record !== null){
|
||||||
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordSound($this->record->getRecordType()));
|
$this->position->getWorld()->addSound($this->position, new RecordSound($this->record->getRecordType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stopSound() : void{
|
public function stopSound() : void{
|
||||||
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordStopSound());
|
$this->position->getWorld()->addSound($this->position, new RecordStopSound());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{
|
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||||
|
@ -108,8 +108,8 @@ class NetherVines extends Flowable{
|
|||||||
|
|
||||||
private function grow(?Player $player, int $growthAmount = 1) : bool{
|
private function grow(?Player $player, int $growthAmount = 1) : bool{
|
||||||
$top = $this->seekToTip();
|
$top = $this->seekToTip();
|
||||||
$age = $top->getAge();
|
$age = $top->age;
|
||||||
$pos = $top->getPosition();
|
$pos = $top->position;
|
||||||
$world = $pos->getWorld();
|
$world = $pos->getWorld();
|
||||||
$changedBlocks = 0;
|
$changedBlocks = 0;
|
||||||
|
|
||||||
|
@ -70,13 +70,13 @@ class PinkPetals extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||||
return ($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT) || $this->supportedWhenPlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
return ($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT) || $this->supportedWhenPlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||||
if($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT){
|
if($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT){
|
||||||
$this->count = $blockReplace->getCount() + 1;
|
$this->count = $blockReplace->count + 1;
|
||||||
$this->facing = $blockReplace->getFacing();
|
$this->facing = $blockReplace->facing;
|
||||||
}elseif($player !== null){
|
}elseif($player !== null){
|
||||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||||
}
|
}
|
||||||
|
@ -25,17 +25,18 @@ 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\CropGrowthHelper;
|
||||||
use pocketmine\block\utils\StaticSupportTrait;
|
use pocketmine\block\utils\StaticSupportTrait;
|
||||||
use pocketmine\event\block\StructureGrowEvent;
|
use pocketmine\event\block\StructureGrowEvent;
|
||||||
use pocketmine\item\Fertilizer;
|
use pocketmine\item\Fertilizer;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\VanillaItems;
|
||||||
use pocketmine\math\Axis;
|
use pocketmine\math\Axis;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Facing;
|
use pocketmine\math\Facing;
|
||||||
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 mt_rand;
|
|
||||||
|
|
||||||
final class PitcherCrop extends Flowable{
|
final class PitcherCrop extends Flowable{
|
||||||
use AgeableTrait;
|
use AgeableTrait;
|
||||||
@ -97,9 +98,12 @@ final class PitcherCrop extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onRandomTick() : void{
|
public function onRandomTick() : void{
|
||||||
//TODO: the growth speed is influenced by farmland and nearby crops
|
if(CropGrowthHelper::canGrow($this)){
|
||||||
if(mt_rand(0, 2) === 0){
|
|
||||||
$this->grow(null);
|
$this->grow(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function asItem() : Item{
|
||||||
|
return VanillaItems::PITCHER_POD();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ class RedMushroom extends Flowable{
|
|||||||
|
|
||||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||||
$down = $this->getSide(Facing::DOWN);
|
$down = $this->getSide(Facing::DOWN);
|
||||||
$position = $this->getPosition();
|
$position = $this->position;
|
||||||
$lightLevel = $position->getWorld()->getFullLightAt($position->x, $position->y, $position->z);
|
$lightLevel = $position->getWorld()->getFullLightAt($position->x, $position->y, $position->z);
|
||||||
$downId = $down->getTypeId();
|
$downId = $down->getTypeId();
|
||||||
//TODO: nylium support
|
//TODO: nylium support
|
||||||
|
@ -83,7 +83,7 @@ class SmallDripleaf extends Transparent{
|
|||||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||||
}
|
}
|
||||||
|
|
||||||
$tx->addBlock($block->getPosition(), VanillaBlocks::SMALL_DRIPLEAF()
|
$tx->addBlock($block->position, VanillaBlocks::SMALL_DRIPLEAF()
|
||||||
->setFacing($this->facing)
|
->setFacing($this->facing)
|
||||||
->setTop(true)
|
->setTop(true)
|
||||||
);
|
);
|
||||||
@ -117,7 +117,7 @@ class SmallDripleaf extends Transparent{
|
|||||||
$height = mt_rand(2, 5);
|
$height = mt_rand(2, 5);
|
||||||
$grown = 0;
|
$grown = 0;
|
||||||
for($i = 0; $i < $height; $i++){
|
for($i = 0; $i < $height; $i++){
|
||||||
$pos = $bottomBlock->getSide(Facing::UP, $i)->getPosition();
|
$pos = $bottomBlock->getSide(Facing::UP, $i)->position;
|
||||||
if(!$this->canGrowTo($pos)){
|
if(!$this->canGrowTo($pos)){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -106,8 +106,8 @@ class Stair extends Transparent{
|
|||||||
|
|
||||||
public function getSupportType(int $facing) : SupportType{
|
public function getSupportType(int $facing) : SupportType{
|
||||||
if(
|
if(
|
||||||
$facing === Facing::UP && $this->isUpsideDown() ||
|
$facing === Facing::UP && $this->upsideDown ||
|
||||||
$facing === Facing::DOWN && !$this->isUpsideDown() ||
|
$facing === Facing::DOWN && !$this->upsideDown ||
|
||||||
($facing === $this->facing && $this->shape !== StairShape::OUTER_LEFT && $this->shape !== StairShape::OUTER_RIGHT) ||
|
($facing === $this->facing && $this->shape !== StairShape::OUTER_LEFT && $this->shape !== StairShape::OUTER_RIGHT) ||
|
||||||
($facing === Facing::rotate($this->facing, Axis::Y, false) && $this->shape === StairShape::INNER_LEFT) ||
|
($facing === Facing::rotate($this->facing, Axis::Y, false) && $this->shape === StairShape::INNER_LEFT) ||
|
||||||
($facing === Facing::rotate($this->facing, Axis::Y, true) && $this->shape === StairShape::INNER_RIGHT)
|
($facing === Facing::rotate($this->facing, Axis::Y, true) && $this->shape === StairShape::INNER_RIGHT)
|
||||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\utils\BlockEventHelper;
|
use pocketmine\block\utils\BlockEventHelper;
|
||||||
|
use pocketmine\block\utils\CropGrowthHelper;
|
||||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\math\Facing;
|
use pocketmine\math\Facing;
|
||||||
@ -63,7 +64,7 @@ abstract class Stem extends Crops{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onRandomTick() : void{
|
public function onRandomTick() : void{
|
||||||
if($this->facing === Facing::UP && mt_rand(0, 2) === 1){
|
if($this->facing === Facing::UP && CropGrowthHelper::canGrow($this)){
|
||||||
$world = $this->position->getWorld();
|
$world = $this->position->getWorld();
|
||||||
if($this->age < self::MAX_AGE){
|
if($this->age < self::MAX_AGE){
|
||||||
$block = clone $this;
|
$block = clone $this;
|
||||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\utils\BlockEventHelper;
|
use pocketmine\block\utils\BlockEventHelper;
|
||||||
|
use pocketmine\block\utils\CropGrowthHelper;
|
||||||
use pocketmine\block\utils\StaticSupportTrait;
|
use pocketmine\block\utils\StaticSupportTrait;
|
||||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||||
use pocketmine\item\Fertilizer;
|
use pocketmine\item\Fertilizer;
|
||||||
@ -32,7 +33,6 @@ use pocketmine\item\VanillaItems;
|
|||||||
use pocketmine\math\Facing;
|
use pocketmine\math\Facing;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\player\Player;
|
use pocketmine\player\Player;
|
||||||
use function mt_rand;
|
|
||||||
|
|
||||||
final class TorchflowerCrop extends Flowable{
|
final class TorchflowerCrop extends Flowable{
|
||||||
use StaticSupportTrait;
|
use StaticSupportTrait;
|
||||||
@ -79,7 +79,7 @@ final class TorchflowerCrop extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onRandomTick() : void{
|
public function onRandomTick() : void{
|
||||||
if(mt_rand(0, 2) === 1){
|
if(CropGrowthHelper::canGrow($this)){
|
||||||
BlockEventHelper::grow($this, $this->getNextState(), null);
|
BlockEventHelper::grow($this, $this->getNextState(), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,20 +47,20 @@ trait AnimatedBlockInventoryTrait{
|
|||||||
public function onOpen(Player $who) : void{
|
public function onOpen(Player $who) : void{
|
||||||
parent::onOpen($who);
|
parent::onOpen($who);
|
||||||
|
|
||||||
if($this->getHolder()->isValid() && $this->getViewerCount() === 1){
|
if($this->holder->isValid() && $this->getViewerCount() === 1){
|
||||||
//TODO: this crap really shouldn't be managed by the inventory
|
//TODO: this crap really shouldn't be managed by the inventory
|
||||||
$this->animateBlock(true);
|
$this->animateBlock(true);
|
||||||
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
$this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract protected function animateBlock(bool $isOpen) : void;
|
abstract protected function animateBlock(bool $isOpen) : void;
|
||||||
|
|
||||||
public function onClose(Player $who) : void{
|
public function onClose(Player $who) : void{
|
||||||
if($this->getHolder()->isValid() && $this->getViewerCount() === 1){
|
if($this->holder->isValid() && $this->getViewerCount() === 1){
|
||||||
//TODO: this crap really shouldn't be managed by the inventory
|
//TODO: this crap really shouldn't be managed by the inventory
|
||||||
$this->animateBlock(false);
|
$this->animateBlock(false);
|
||||||
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
$this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
||||||
}
|
}
|
||||||
parent::onClose($who);
|
parent::onClose($who);
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ class Chest extends Spawnable implements Container, Nameable{
|
|||||||
if($pair->doubleInventory !== null){
|
if($pair->doubleInventory !== null){
|
||||||
$this->doubleInventory = $pair->doubleInventory;
|
$this->doubleInventory = $pair->doubleInventory;
|
||||||
}else{
|
}else{
|
||||||
if(($pair->getPosition()->x + ($pair->getPosition()->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly
|
if(($pair->position->x + ($pair->position->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly
|
||||||
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($pair->inventory, $this->inventory);
|
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($pair->inventory, $this->inventory);
|
||||||
}else{
|
}else{
|
||||||
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($this->inventory, $pair->inventory);
|
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($this->inventory, $pair->inventory);
|
||||||
|
120
src/block/utils/CropGrowthHelper.php
Normal file
120
src/block/utils/CropGrowthHelper.php
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?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\block\Block;
|
||||||
|
use pocketmine\block\Farmland;
|
||||||
|
use function mt_rand;
|
||||||
|
|
||||||
|
final class CropGrowthHelper{
|
||||||
|
|
||||||
|
private const ON_HYDRATED_FARMLAND_BONUS = 3;
|
||||||
|
private const ON_DRY_FARMLAND_BONUS = 1;
|
||||||
|
private const ADJACENT_HYDRATED_FARMLAND_BONUS = 3 / 4;
|
||||||
|
private const ADJACENT_DRY_FARMLAND_BONUS = 1 / 4;
|
||||||
|
|
||||||
|
private const IMPROPER_ARRANGEMENT_DIVISOR = 2;
|
||||||
|
|
||||||
|
private const MIN_LIGHT_LEVEL = 9;
|
||||||
|
|
||||||
|
private function __construct(){
|
||||||
|
//NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the speed at which this crop will grow, depending on its surroundings.
|
||||||
|
* The default is once every 26 random ticks.
|
||||||
|
*
|
||||||
|
* Things which influence this include nearby farmland (bonus for hydrated farmland) and the position of other
|
||||||
|
* nearby crops of the same type (nearby crops of the same type will negatively influence growth speed unless
|
||||||
|
* planted in rows and properly spaced apart).
|
||||||
|
*/
|
||||||
|
public static function calculateMultiplier(Block $block) : float{
|
||||||
|
$result = 1;
|
||||||
|
|
||||||
|
$position = $block->getPosition();
|
||||||
|
|
||||||
|
$world = $position->getWorld();
|
||||||
|
$baseX = $position->getFloorX();
|
||||||
|
$baseY = $position->getFloorY();
|
||||||
|
$baseZ = $position->getFloorZ();
|
||||||
|
|
||||||
|
$farmland = $world->getBlockAt($baseX, $baseY - 1, $baseZ);
|
||||||
|
|
||||||
|
if($farmland instanceof Farmland){
|
||||||
|
$result += $farmland->getWetness() > 0 ? self::ON_HYDRATED_FARMLAND_BONUS : self::ON_DRY_FARMLAND_BONUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xRow = false;
|
||||||
|
$zRow = false;
|
||||||
|
$improperArrangement = false;
|
||||||
|
|
||||||
|
for($x = -1; $x <= 1; $x++){
|
||||||
|
for($z = -1; $z <= 1; $z++){
|
||||||
|
if($x === 0 && $z === 0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$nextFarmland = $world->getBlockAt($baseX + $x, $baseY - 1, $baseZ + $z);
|
||||||
|
|
||||||
|
if(!$nextFarmland instanceof Farmland){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result += $nextFarmland->getWetness() > 0 ? self::ADJACENT_HYDRATED_FARMLAND_BONUS : self::ADJACENT_DRY_FARMLAND_BONUS;
|
||||||
|
|
||||||
|
if(!$improperArrangement){
|
||||||
|
$nextCrop = $world->getBlockAt($baseX + $x, $baseY, $baseZ + $z);
|
||||||
|
if($nextCrop->hasSameTypeId($block)){
|
||||||
|
match(0){
|
||||||
|
$x => $zRow ? $improperArrangement = true : $xRow = true,
|
||||||
|
$z => $xRow ? $improperArrangement = true : $zRow = true,
|
||||||
|
default => $improperArrangement = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//crops can be arranged in rows, but the rows must not cross and must be spaced apart by at least one block
|
||||||
|
if($improperArrangement){
|
||||||
|
$result /= self::IMPROPER_ARRANGEMENT_DIVISOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function hasEnoughLight(Block $block, int $minLevel = self::MIN_LIGHT_LEVEL) : bool{
|
||||||
|
$position = $block->getPosition();
|
||||||
|
$world = $position->getWorld();
|
||||||
|
|
||||||
|
//crop growth is not affected by time of day since 1.11 or so
|
||||||
|
return $world->getPotentialLightAt($position->x, $position->y, $position->z) >= $minLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function canGrow(Block $block) : bool{
|
||||||
|
//while it may be tempting to use mt_rand(0, 25) < multiplier, this would make crops grow a bit faster than
|
||||||
|
//vanilla in most cases due to the remainder of 25 / multiplier not being discarded
|
||||||
|
return mt_rand(0, (int) (25 / self::calculateMultiplier($block))) === 0 && self::hasEnoughLight($block);
|
||||||
|
}
|
||||||
|
}
|
@ -147,7 +147,6 @@ final class ItemSerializerDeserializerRegistrar{
|
|||||||
$this->map1to1Block(Ids::JUNGLE_DOOR, Blocks::JUNGLE_DOOR());
|
$this->map1to1Block(Ids::JUNGLE_DOOR, Blocks::JUNGLE_DOOR());
|
||||||
$this->map1to1Block(Ids::MANGROVE_DOOR, Blocks::MANGROVE_DOOR());
|
$this->map1to1Block(Ids::MANGROVE_DOOR, Blocks::MANGROVE_DOOR());
|
||||||
$this->map1to1Block(Ids::NETHER_WART, Blocks::NETHER_WART());
|
$this->map1to1Block(Ids::NETHER_WART, Blocks::NETHER_WART());
|
||||||
$this->map1to1Block(Ids::PITCHER_POD, Blocks::PITCHER_CROP());
|
|
||||||
$this->map1to1Block(Ids::REPEATER, Blocks::REDSTONE_REPEATER());
|
$this->map1to1Block(Ids::REPEATER, Blocks::REDSTONE_REPEATER());
|
||||||
$this->map1to1Block(Ids::SPRUCE_DOOR, Blocks::SPRUCE_DOOR());
|
$this->map1to1Block(Ids::SPRUCE_DOOR, Blocks::SPRUCE_DOOR());
|
||||||
$this->map1to1Block(Ids::SUGAR_CANE, Blocks::SUGARCANE());
|
$this->map1to1Block(Ids::SUGAR_CANE, Blocks::SUGARCANE());
|
||||||
@ -193,6 +192,7 @@ final class ItemSerializerDeserializerRegistrar{
|
|||||||
$this->map1to1Item(Ids::CLAY_BALL, Items::CLAY());
|
$this->map1to1Item(Ids::CLAY_BALL, Items::CLAY());
|
||||||
$this->map1to1Item(Ids::CLOCK, Items::CLOCK());
|
$this->map1to1Item(Ids::CLOCK, Items::CLOCK());
|
||||||
$this->map1to1Item(Ids::COAL, Items::COAL());
|
$this->map1to1Item(Ids::COAL, Items::COAL());
|
||||||
|
$this->map1to1Item(Ids::COAST_ARMOR_TRIM_SMITHING_TEMPLATE, Items::COAST_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::COCOA_BEANS, Items::COCOA_BEANS());
|
$this->map1to1Item(Ids::COCOA_BEANS, Items::COCOA_BEANS());
|
||||||
$this->map1to1Item(Ids::COD, Items::RAW_FISH());
|
$this->map1to1Item(Ids::COD, Items::RAW_FISH());
|
||||||
$this->map1to1Item(Ids::COMPASS, Items::COMPASS());
|
$this->map1to1Item(Ids::COMPASS, Items::COMPASS());
|
||||||
@ -221,6 +221,7 @@ final class ItemSerializerDeserializerRegistrar{
|
|||||||
$this->map1to1Item(Ids::DISC_FRAGMENT_5, Items::DISC_FRAGMENT_5());
|
$this->map1to1Item(Ids::DISC_FRAGMENT_5, Items::DISC_FRAGMENT_5());
|
||||||
$this->map1to1Item(Ids::DRAGON_BREATH, Items::DRAGON_BREATH());
|
$this->map1to1Item(Ids::DRAGON_BREATH, Items::DRAGON_BREATH());
|
||||||
$this->map1to1Item(Ids::DRIED_KELP, Items::DRIED_KELP());
|
$this->map1to1Item(Ids::DRIED_KELP, Items::DRIED_KELP());
|
||||||
|
$this->map1to1Item(Ids::DUNE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::DUNE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::ECHO_SHARD, Items::ECHO_SHARD());
|
$this->map1to1Item(Ids::ECHO_SHARD, Items::ECHO_SHARD());
|
||||||
$this->map1to1Item(Ids::EGG, Items::EGG());
|
$this->map1to1Item(Ids::EGG, Items::EGG());
|
||||||
$this->map1to1Item(Ids::EMERALD, Items::EMERALD());
|
$this->map1to1Item(Ids::EMERALD, Items::EMERALD());
|
||||||
@ -228,6 +229,7 @@ final class ItemSerializerDeserializerRegistrar{
|
|||||||
$this->map1to1Item(Ids::ENCHANTED_GOLDEN_APPLE, Items::ENCHANTED_GOLDEN_APPLE());
|
$this->map1to1Item(Ids::ENCHANTED_GOLDEN_APPLE, Items::ENCHANTED_GOLDEN_APPLE());
|
||||||
$this->map1to1Item(Ids::ENDER_PEARL, Items::ENDER_PEARL());
|
$this->map1to1Item(Ids::ENDER_PEARL, Items::ENDER_PEARL());
|
||||||
$this->map1to1Item(Ids::EXPERIENCE_BOTTLE, Items::EXPERIENCE_BOTTLE());
|
$this->map1to1Item(Ids::EXPERIENCE_BOTTLE, Items::EXPERIENCE_BOTTLE());
|
||||||
|
$this->map1to1Item(Ids::EYE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::EYE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::FEATHER, Items::FEATHER());
|
$this->map1to1Item(Ids::FEATHER, Items::FEATHER());
|
||||||
$this->map1to1Item(Ids::FERMENTED_SPIDER_EYE, Items::FERMENTED_SPIDER_EYE());
|
$this->map1to1Item(Ids::FERMENTED_SPIDER_EYE, Items::FERMENTED_SPIDER_EYE());
|
||||||
$this->map1to1Item(Ids::FIRE_CHARGE, Items::FIRE_CHARGE());
|
$this->map1to1Item(Ids::FIRE_CHARGE, Items::FIRE_CHARGE());
|
||||||
@ -257,6 +259,7 @@ final class ItemSerializerDeserializerRegistrar{
|
|||||||
$this->map1to1Item(Ids::HEART_OF_THE_SEA, Items::HEART_OF_THE_SEA());
|
$this->map1to1Item(Ids::HEART_OF_THE_SEA, Items::HEART_OF_THE_SEA());
|
||||||
$this->map1to1Item(Ids::HONEY_BOTTLE, Items::HONEY_BOTTLE());
|
$this->map1to1Item(Ids::HONEY_BOTTLE, Items::HONEY_BOTTLE());
|
||||||
$this->map1to1Item(Ids::HONEYCOMB, Items::HONEYCOMB());
|
$this->map1to1Item(Ids::HONEYCOMB, Items::HONEYCOMB());
|
||||||
|
$this->map1to1Item(Ids::HOST_ARMOR_TRIM_SMITHING_TEMPLATE, Items::HOST_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::INK_SAC, Items::INK_SAC());
|
$this->map1to1Item(Ids::INK_SAC, Items::INK_SAC());
|
||||||
$this->map1to1Item(Ids::IRON_AXE, Items::IRON_AXE());
|
$this->map1to1Item(Ids::IRON_AXE, Items::IRON_AXE());
|
||||||
$this->map1to1Item(Ids::IRON_BOOTS, Items::IRON_BOOTS());
|
$this->map1to1Item(Ids::IRON_BOOTS, Items::IRON_BOOTS());
|
||||||
@ -316,11 +319,13 @@ final class ItemSerializerDeserializerRegistrar{
|
|||||||
$this->map1to1Item(Ids::NETHERITE_SCRAP, Items::NETHERITE_SCRAP());
|
$this->map1to1Item(Ids::NETHERITE_SCRAP, Items::NETHERITE_SCRAP());
|
||||||
$this->map1to1Item(Ids::NETHERITE_SHOVEL, Items::NETHERITE_SHOVEL());
|
$this->map1to1Item(Ids::NETHERITE_SHOVEL, Items::NETHERITE_SHOVEL());
|
||||||
$this->map1to1Item(Ids::NETHERITE_SWORD, Items::NETHERITE_SWORD());
|
$this->map1to1Item(Ids::NETHERITE_SWORD, Items::NETHERITE_SWORD());
|
||||||
|
$this->map1to1Item(Ids::NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items::NETHERITE_UPGRADE_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::OAK_BOAT, Items::OAK_BOAT());
|
$this->map1to1Item(Ids::OAK_BOAT, Items::OAK_BOAT());
|
||||||
$this->map1to1Item(Ids::OAK_SIGN, Items::OAK_SIGN());
|
$this->map1to1Item(Ids::OAK_SIGN, Items::OAK_SIGN());
|
||||||
$this->map1to1Item(Ids::PAINTING, Items::PAINTING());
|
$this->map1to1Item(Ids::PAINTING, Items::PAINTING());
|
||||||
$this->map1to1Item(Ids::PAPER, Items::PAPER());
|
$this->map1to1Item(Ids::PAPER, Items::PAPER());
|
||||||
$this->map1to1Item(Ids::PHANTOM_MEMBRANE, Items::PHANTOM_MEMBRANE());
|
$this->map1to1Item(Ids::PHANTOM_MEMBRANE, Items::PHANTOM_MEMBRANE());
|
||||||
|
$this->map1to1Item(Ids::PITCHER_POD, Items::PITCHER_POD());
|
||||||
$this->map1to1Item(Ids::POISONOUS_POTATO, Items::POISONOUS_POTATO());
|
$this->map1to1Item(Ids::POISONOUS_POTATO, Items::POISONOUS_POTATO());
|
||||||
$this->map1to1Item(Ids::POPPED_CHORUS_FRUIT, Items::POPPED_CHORUS_FRUIT());
|
$this->map1to1Item(Ids::POPPED_CHORUS_FRUIT, Items::POPPED_CHORUS_FRUIT());
|
||||||
$this->map1to1Item(Ids::PORKCHOP, Items::RAW_PORKCHOP());
|
$this->map1to1Item(Ids::PORKCHOP, Items::RAW_PORKCHOP());
|
||||||
@ -335,18 +340,25 @@ final class ItemSerializerDeserializerRegistrar{
|
|||||||
$this->map1to1Item(Ids::RABBIT_FOOT, Items::RABBIT_FOOT());
|
$this->map1to1Item(Ids::RABBIT_FOOT, Items::RABBIT_FOOT());
|
||||||
$this->map1to1Item(Ids::RABBIT_HIDE, Items::RABBIT_HIDE());
|
$this->map1to1Item(Ids::RABBIT_HIDE, Items::RABBIT_HIDE());
|
||||||
$this->map1to1Item(Ids::RABBIT_STEW, Items::RABBIT_STEW());
|
$this->map1to1Item(Ids::RABBIT_STEW, Items::RABBIT_STEW());
|
||||||
|
$this->map1to1Item(Ids::RAISER_ARMOR_TRIM_SMITHING_TEMPLATE, Items::RAISER_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::RAW_COPPER, Items::RAW_COPPER());
|
$this->map1to1Item(Ids::RAW_COPPER, Items::RAW_COPPER());
|
||||||
$this->map1to1Item(Ids::RAW_GOLD, Items::RAW_GOLD());
|
$this->map1to1Item(Ids::RAW_GOLD, Items::RAW_GOLD());
|
||||||
$this->map1to1Item(Ids::RAW_IRON, Items::RAW_IRON());
|
$this->map1to1Item(Ids::RAW_IRON, Items::RAW_IRON());
|
||||||
$this->map1to1Item(Ids::REDSTONE, Items::REDSTONE_DUST());
|
$this->map1to1Item(Ids::REDSTONE, Items::REDSTONE_DUST());
|
||||||
|
$this->map1to1Item(Ids::RIB_ARMOR_TRIM_SMITHING_TEMPLATE, Items::RIB_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::ROTTEN_FLESH, Items::ROTTEN_FLESH());
|
$this->map1to1Item(Ids::ROTTEN_FLESH, Items::ROTTEN_FLESH());
|
||||||
$this->map1to1Item(Ids::SALMON, Items::RAW_SALMON());
|
$this->map1to1Item(Ids::SALMON, Items::RAW_SALMON());
|
||||||
$this->map1to1Item(Ids::SCUTE, Items::SCUTE());
|
$this->map1to1Item(Ids::SCUTE, Items::SCUTE());
|
||||||
|
$this->map1to1Item(Ids::SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
|
$this->map1to1Item(Ids::SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::SHEARS, Items::SHEARS());
|
$this->map1to1Item(Ids::SHEARS, Items::SHEARS());
|
||||||
$this->map1to1Item(Ids::SHULKER_SHELL, Items::SHULKER_SHELL());
|
$this->map1to1Item(Ids::SHULKER_SHELL, Items::SHULKER_SHELL());
|
||||||
|
$this->map1to1Item(Ids::SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::SLIME_BALL, Items::SLIMEBALL());
|
$this->map1to1Item(Ids::SLIME_BALL, Items::SLIMEBALL());
|
||||||
|
$this->map1to1Item(Ids::SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::SNOWBALL, Items::SNOWBALL());
|
$this->map1to1Item(Ids::SNOWBALL, Items::SNOWBALL());
|
||||||
$this->map1to1Item(Ids::SPIDER_EYE, Items::SPIDER_EYE());
|
$this->map1to1Item(Ids::SPIDER_EYE, Items::SPIDER_EYE());
|
||||||
|
$this->map1to1Item(Ids::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::SPRUCE_BOAT, Items::SPRUCE_BOAT());
|
$this->map1to1Item(Ids::SPRUCE_BOAT, Items::SPRUCE_BOAT());
|
||||||
$this->map1to1Item(Ids::SPRUCE_SIGN, Items::SPRUCE_SIGN());
|
$this->map1to1Item(Ids::SPRUCE_SIGN, Items::SPRUCE_SIGN());
|
||||||
$this->map1to1Item(Ids::SPYGLASS, Items::SPYGLASS());
|
$this->map1to1Item(Ids::SPYGLASS, Items::SPYGLASS());
|
||||||
@ -361,14 +373,19 @@ final class ItemSerializerDeserializerRegistrar{
|
|||||||
$this->map1to1Item(Ids::SUGAR, Items::SUGAR());
|
$this->map1to1Item(Ids::SUGAR, Items::SUGAR());
|
||||||
$this->map1to1Item(Ids::SWEET_BERRIES, Items::SWEET_BERRIES());
|
$this->map1to1Item(Ids::SWEET_BERRIES, Items::SWEET_BERRIES());
|
||||||
$this->map1to1Item(Ids::TORCHFLOWER_SEEDS, Items::TORCHFLOWER_SEEDS());
|
$this->map1to1Item(Ids::TORCHFLOWER_SEEDS, Items::TORCHFLOWER_SEEDS());
|
||||||
|
$this->map1to1Item(Ids::TIDE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::TIDE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::TOTEM_OF_UNDYING, Items::TOTEM());
|
$this->map1to1Item(Ids::TOTEM_OF_UNDYING, Items::TOTEM());
|
||||||
$this->map1to1Item(Ids::TROPICAL_FISH, Items::CLOWNFISH());
|
$this->map1to1Item(Ids::TROPICAL_FISH, Items::CLOWNFISH());
|
||||||
$this->map1to1Item(Ids::TURTLE_HELMET, Items::TURTLE_HELMET());
|
$this->map1to1Item(Ids::TURTLE_HELMET, Items::TURTLE_HELMET());
|
||||||
|
$this->map1to1Item(Ids::VEX_ARMOR_TRIM_SMITHING_TEMPLATE, Items::VEX_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::VILLAGER_SPAWN_EGG, Items::VILLAGER_SPAWN_EGG());
|
$this->map1to1Item(Ids::VILLAGER_SPAWN_EGG, Items::VILLAGER_SPAWN_EGG());
|
||||||
|
$this->map1to1Item(Ids::WARD_ARMOR_TRIM_SMITHING_TEMPLATE, Items::WARD_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::WARPED_SIGN, Items::WARPED_SIGN());
|
$this->map1to1Item(Ids::WARPED_SIGN, Items::WARPED_SIGN());
|
||||||
$this->map1to1Item(Ids::WATER_BUCKET, Items::WATER_BUCKET());
|
$this->map1to1Item(Ids::WATER_BUCKET, Items::WATER_BUCKET());
|
||||||
|
$this->map1to1Item(Ids::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE, Items::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::WHEAT, Items::WHEAT());
|
$this->map1to1Item(Ids::WHEAT, Items::WHEAT());
|
||||||
$this->map1to1Item(Ids::WHEAT_SEEDS, Items::WHEAT_SEEDS());
|
$this->map1to1Item(Ids::WHEAT_SEEDS, Items::WHEAT_SEEDS());
|
||||||
|
$this->map1to1Item(Ids::WILD_ARMOR_TRIM_SMITHING_TEMPLATE, Items::WILD_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$this->map1to1Item(Ids::WOODEN_AXE, Items::WOODEN_AXE());
|
$this->map1to1Item(Ids::WOODEN_AXE, Items::WOODEN_AXE());
|
||||||
$this->map1to1Item(Ids::WOODEN_HOE, Items::WOODEN_HOE());
|
$this->map1to1Item(Ids::WOODEN_HOE, Items::WOODEN_HOE());
|
||||||
$this->map1to1Item(Ids::WOODEN_PICKAXE, Items::WOODEN_PICKAXE());
|
$this->map1to1Item(Ids::WOODEN_PICKAXE, Items::WOODEN_PICKAXE());
|
||||||
|
@ -173,8 +173,9 @@ abstract class Projectile extends Entity{
|
|||||||
$entityHit = null;
|
$entityHit = null;
|
||||||
$hitResult = null;
|
$hitResult = null;
|
||||||
|
|
||||||
|
$world = $this->getWorld();
|
||||||
foreach(VoxelRayTrace::betweenPoints($start, $end) as $vector3){
|
foreach(VoxelRayTrace::betweenPoints($start, $end) as $vector3){
|
||||||
$block = $this->getWorld()->getBlockAt($vector3->x, $vector3->y, $vector3->z);
|
$block = $world->getBlockAt($vector3->x, $vector3->y, $vector3->z);
|
||||||
|
|
||||||
$blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end);
|
$blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end);
|
||||||
if($blockHitResult !== null){
|
if($blockHitResult !== null){
|
||||||
@ -188,7 +189,7 @@ abstract class Projectile extends Entity{
|
|||||||
$entityDistance = PHP_INT_MAX;
|
$entityDistance = PHP_INT_MAX;
|
||||||
|
|
||||||
$newDiff = $end->subtractVector($start);
|
$newDiff = $end->subtractVector($start);
|
||||||
foreach($this->getWorld()->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){
|
foreach($world->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){
|
||||||
if($entity->getId() === $this->getOwningEntityId() && $this->ticksLived < 5){
|
if($entity->getId() === $this->getOwningEntityId() && $this->ticksLived < 5){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -256,7 +257,7 @@ abstract class Projectile extends Entity{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getWorld()->onEntityMoved($this);
|
$world->onEntityMoved($this);
|
||||||
$this->checkBlockIntersections();
|
$this->checkBlockIntersections();
|
||||||
|
|
||||||
Timings::$projectileMove->stopTiming();
|
Timings::$projectileMove->stopTiming();
|
||||||
|
@ -31,8 +31,9 @@ class Snowball extends Throwable{
|
|||||||
public static function getNetworkTypeId() : string{ return EntityIds::SNOWBALL; }
|
public static function getNetworkTypeId() : string{ return EntityIds::SNOWBALL; }
|
||||||
|
|
||||||
protected function onHit(ProjectileHitEvent $event) : void{
|
protected function onHit(ProjectileHitEvent $event) : void{
|
||||||
|
$world = $this->getWorld();
|
||||||
for($i = 0; $i < 6; ++$i){
|
for($i = 0; $i < 6; ++$i){
|
||||||
$this->getWorld()->addParticle($this->location, new SnowballPoofParticle());
|
$world->addParticle($this->location, new SnowballPoofParticle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,8 +305,26 @@ final class ItemTypeIds{
|
|||||||
public const CHERRY_SIGN = 20266;
|
public const CHERRY_SIGN = 20266;
|
||||||
public const ENCHANTED_BOOK = 20267;
|
public const ENCHANTED_BOOK = 20267;
|
||||||
public const TORCHFLOWER_SEEDS = 20268;
|
public const TORCHFLOWER_SEEDS = 20268;
|
||||||
|
public const NETHERITE_UPGRADE_SMITHING_TEMPLATE = 20269;
|
||||||
|
public const SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE = 20270;
|
||||||
|
public const VEX_ARMOR_TRIM_SMITHING_TEMPLATE = 20271;
|
||||||
|
public const WILD_ARMOR_TRIM_SMITHING_TEMPLATE = 20272;
|
||||||
|
public const COAST_ARMOR_TRIM_SMITHING_TEMPLATE = 20273;
|
||||||
|
public const DUNE_ARMOR_TRIM_SMITHING_TEMPLATE = 20274;
|
||||||
|
public const WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE = 20275;
|
||||||
|
public const RAISER_ARMOR_TRIM_SMITHING_TEMPLATE = 20276;
|
||||||
|
public const SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE = 20277;
|
||||||
|
public const HOST_ARMOR_TRIM_SMITHING_TEMPLATE = 20278;
|
||||||
|
public const WARD_ARMOR_TRIM_SMITHING_TEMPLATE = 20279;
|
||||||
|
public const SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE = 20280;
|
||||||
|
public const TIDE_ARMOR_TRIM_SMITHING_TEMPLATE = 20281;
|
||||||
|
public const SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE = 20282;
|
||||||
|
public const RIB_ARMOR_TRIM_SMITHING_TEMPLATE = 20283;
|
||||||
|
public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = 20284;
|
||||||
|
public const SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = 20285;
|
||||||
|
public const PITCHER_POD = 20286;
|
||||||
|
|
||||||
public const FIRST_UNUSED_ITEM_ID = 20269;
|
public const FIRST_UNUSED_ITEM_ID = 20287;
|
||||||
|
|
||||||
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;
|
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;
|
||||||
|
|
||||||
|
34
src/item/PitcherPod.php
Normal file
34
src/item/PitcherPod.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\item;
|
||||||
|
|
||||||
|
use pocketmine\block\Block;
|
||||||
|
use pocketmine\block\VanillaBlocks;
|
||||||
|
|
||||||
|
final class PitcherPod extends Item{
|
||||||
|
|
||||||
|
public function getBlock(?int $clickedFace = null) : Block{
|
||||||
|
return VanillaBlocks::PITCHER_CROP();
|
||||||
|
}
|
||||||
|
}
|
@ -869,7 +869,6 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->registerBlock("pink_tulip", fn() => Blocks::PINK_TULIP());
|
$result->registerBlock("pink_tulip", fn() => Blocks::PINK_TULIP());
|
||||||
$result->registerBlock("piglin_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PIGLIN));
|
$result->registerBlock("piglin_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PIGLIN));
|
||||||
$result->registerBlock("pitcher_plant", fn() => Blocks::PITCHER_PLANT());
|
$result->registerBlock("pitcher_plant", fn() => Blocks::PITCHER_PLANT());
|
||||||
$result->registerBlock("pitcher_pod", fn() => Blocks::PITCHER_CROP());
|
|
||||||
$result->registerBlock("plank", fn() => Blocks::OAK_PLANKS());
|
$result->registerBlock("plank", fn() => Blocks::OAK_PLANKS());
|
||||||
$result->registerBlock("planks", fn() => Blocks::OAK_PLANKS());
|
$result->registerBlock("planks", fn() => Blocks::OAK_PLANKS());
|
||||||
$result->registerBlock("player_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PLAYER));
|
$result->registerBlock("player_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PLAYER));
|
||||||
@ -1266,6 +1265,7 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->register("clown_fish", fn() => Items::CLOWNFISH());
|
$result->register("clown_fish", fn() => Items::CLOWNFISH());
|
||||||
$result->register("clownfish", fn() => Items::CLOWNFISH());
|
$result->register("clownfish", fn() => Items::CLOWNFISH());
|
||||||
$result->register("coal", fn() => Items::COAL());
|
$result->register("coal", fn() => Items::COAL());
|
||||||
|
$result->register("coast_armor_trim_smithing_template", fn() => Items::COAST_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("cocoa_beans", fn() => Items::COCOA_BEANS());
|
$result->register("cocoa_beans", fn() => Items::COCOA_BEANS());
|
||||||
$result->register("cod", fn() => Items::RAW_FISH());
|
$result->register("cod", fn() => Items::RAW_FISH());
|
||||||
$result->register("compass", fn() => Items::COMPASS());
|
$result->register("compass", fn() => Items::COMPASS());
|
||||||
@ -1294,6 +1294,7 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->register("disc_fragment_5", fn() => Items::DISC_FRAGMENT_5());
|
$result->register("disc_fragment_5", fn() => Items::DISC_FRAGMENT_5());
|
||||||
$result->register("dragon_breath", fn() => Items::DRAGON_BREATH());
|
$result->register("dragon_breath", fn() => Items::DRAGON_BREATH());
|
||||||
$result->register("dried_kelp", fn() => Items::DRIED_KELP());
|
$result->register("dried_kelp", fn() => Items::DRIED_KELP());
|
||||||
|
$result->register("dune_armor_trim_smithing_template", fn() => Items::DUNE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("dye", fn() => Items::INK_SAC());
|
$result->register("dye", fn() => Items::INK_SAC());
|
||||||
$result->register("echo_shard", fn() => Items::ECHO_SHARD());
|
$result->register("echo_shard", fn() => Items::ECHO_SHARD());
|
||||||
$result->register("egg", fn() => Items::EGG());
|
$result->register("egg", fn() => Items::EGG());
|
||||||
@ -1304,6 +1305,7 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->register("enchanting_bottle", fn() => Items::EXPERIENCE_BOTTLE());
|
$result->register("enchanting_bottle", fn() => Items::EXPERIENCE_BOTTLE());
|
||||||
$result->register("ender_pearl", fn() => Items::ENDER_PEARL());
|
$result->register("ender_pearl", fn() => Items::ENDER_PEARL());
|
||||||
$result->register("experience_bottle", fn() => Items::EXPERIENCE_BOTTLE());
|
$result->register("experience_bottle", fn() => Items::EXPERIENCE_BOTTLE());
|
||||||
|
$result->register("eye_armor_trim_smithing_template", fn() => Items::EYE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("eye_drops", fn() => Items::MEDICINE()->setType(MedicineType::EYE_DROPS));
|
$result->register("eye_drops", fn() => Items::MEDICINE()->setType(MedicineType::EYE_DROPS));
|
||||||
$result->register("feather", fn() => Items::FEATHER());
|
$result->register("feather", fn() => Items::FEATHER());
|
||||||
$result->register("fermented_spider_eye", fn() => Items::FERMENTED_SPIDER_EYE());
|
$result->register("fermented_spider_eye", fn() => Items::FERMENTED_SPIDER_EYE());
|
||||||
@ -1345,6 +1347,7 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->register("gunpowder", fn() => Items::GUNPOWDER());
|
$result->register("gunpowder", fn() => Items::GUNPOWDER());
|
||||||
$result->register("heart_of_the_sea", fn() => Items::HEART_OF_THE_SEA());
|
$result->register("heart_of_the_sea", fn() => Items::HEART_OF_THE_SEA());
|
||||||
$result->register("honey_bottle", fn() => Items::HONEY_BOTTLE());
|
$result->register("honey_bottle", fn() => Items::HONEY_BOTTLE());
|
||||||
|
$result->register("host_armor_trim_smithing_template", fn() => Items::HOST_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("honeycomb", fn() => Items::HONEYCOMB());
|
$result->register("honeycomb", fn() => Items::HONEYCOMB());
|
||||||
$result->register("ink_sac", fn() => Items::INK_SAC());
|
$result->register("ink_sac", fn() => Items::INK_SAC());
|
||||||
$result->register("iron_axe", fn() => Items::IRON_AXE());
|
$result->register("iron_axe", fn() => Items::IRON_AXE());
|
||||||
@ -1398,10 +1401,12 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->register("netherite_shovel", fn() => Items::NETHERITE_SHOVEL());
|
$result->register("netherite_shovel", fn() => Items::NETHERITE_SHOVEL());
|
||||||
$result->register("netherite_sword", fn() => Items::NETHERITE_SWORD());
|
$result->register("netherite_sword", fn() => Items::NETHERITE_SWORD());
|
||||||
$result->register("netherstar", fn() => Items::NETHER_STAR());
|
$result->register("netherstar", fn() => Items::NETHER_STAR());
|
||||||
|
$result->register("netherite_upgrade_smithing_template", fn() => Items::NETHERITE_UPGRADE_SMITHING_TEMPLATE());
|
||||||
$result->register("oak_boat", fn() => Items::OAK_BOAT());
|
$result->register("oak_boat", fn() => Items::OAK_BOAT());
|
||||||
$result->register("painting", fn() => Items::PAINTING());
|
$result->register("painting", fn() => Items::PAINTING());
|
||||||
$result->register("paper", fn() => Items::PAPER());
|
$result->register("paper", fn() => Items::PAPER());
|
||||||
$result->register("phantom_membrane", fn() => Items::PHANTOM_MEMBRANE());
|
$result->register("phantom_membrane", fn() => Items::PHANTOM_MEMBRANE());
|
||||||
|
$result->register("pitcher_pod", fn() => Items::PITCHER_POD());
|
||||||
$result->register("poisonous_potato", fn() => Items::POISONOUS_POTATO());
|
$result->register("poisonous_potato", fn() => Items::POISONOUS_POTATO());
|
||||||
$result->register("popped_chorus_fruit", fn() => Items::POPPED_CHORUS_FRUIT());
|
$result->register("popped_chorus_fruit", fn() => Items::POPPED_CHORUS_FRUIT());
|
||||||
$result->register("porkchop", fn() => Items::RAW_PORKCHOP());
|
$result->register("porkchop", fn() => Items::RAW_PORKCHOP());
|
||||||
@ -1418,6 +1423,7 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->register("rabbit_foot", fn() => Items::RABBIT_FOOT());
|
$result->register("rabbit_foot", fn() => Items::RABBIT_FOOT());
|
||||||
$result->register("rabbit_hide", fn() => Items::RABBIT_HIDE());
|
$result->register("rabbit_hide", fn() => Items::RABBIT_HIDE());
|
||||||
$result->register("rabbit_stew", fn() => Items::RABBIT_STEW());
|
$result->register("rabbit_stew", fn() => Items::RABBIT_STEW());
|
||||||
|
$result->register("raiser_armor_trim_smithing_template", fn() => Items::RAISER_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("raw_beef", fn() => Items::RAW_BEEF());
|
$result->register("raw_beef", fn() => Items::RAW_BEEF());
|
||||||
$result->register("raw_cod", fn() => Items::RAW_FISH());
|
$result->register("raw_cod", fn() => Items::RAW_FISH());
|
||||||
$result->register("raw_copper", fn() => Items::RAW_COPPER());
|
$result->register("raw_copper", fn() => Items::RAW_COPPER());
|
||||||
@ -1446,17 +1452,23 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->register("record_ward", fn() => Items::RECORD_WARD());
|
$result->register("record_ward", fn() => Items::RECORD_WARD());
|
||||||
$result->register("redstone", fn() => Items::REDSTONE_DUST());
|
$result->register("redstone", fn() => Items::REDSTONE_DUST());
|
||||||
$result->register("redstone_dust", fn() => Items::REDSTONE_DUST());
|
$result->register("redstone_dust", fn() => Items::REDSTONE_DUST());
|
||||||
|
$result->register("rib_armor_trim_smithing_template", fn() => Items::RIB_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("rotten_flesh", fn() => Items::ROTTEN_FLESH());
|
$result->register("rotten_flesh", fn() => Items::ROTTEN_FLESH());
|
||||||
$result->register("salmon", fn() => Items::RAW_SALMON());
|
$result->register("salmon", fn() => Items::RAW_SALMON());
|
||||||
$result->register("scute", fn() => Items::SCUTE());
|
$result->register("scute", fn() => Items::SCUTE());
|
||||||
|
$result->register("sentry_armor_trim_smithing_template", fn() => Items::SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
|
$result->register("shaper_armor_trim_smithing_template", fn() => Items::SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("seeds", fn() => Items::WHEAT_SEEDS());
|
$result->register("seeds", fn() => Items::WHEAT_SEEDS());
|
||||||
$result->register("shears", fn() => Items::SHEARS());
|
$result->register("shears", fn() => Items::SHEARS());
|
||||||
$result->register("shulker_shell", fn() => Items::SHULKER_SHELL());
|
$result->register("shulker_shell", fn() => Items::SHULKER_SHELL());
|
||||||
|
$result->register("silence_armor_trim_smithing_template", fn() => Items::SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("slime_ball", fn() => Items::SLIMEBALL());
|
$result->register("slime_ball", fn() => Items::SLIMEBALL());
|
||||||
|
$result->register("snout_armor_trim_smithing_template", fn() => Items::SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("slimeball", fn() => Items::SLIMEBALL());
|
$result->register("slimeball", fn() => Items::SLIMEBALL());
|
||||||
$result->register("snowball", fn() => Items::SNOWBALL());
|
$result->register("snowball", fn() => Items::SNOWBALL());
|
||||||
$result->register("speckled_melon", fn() => Items::GLISTERING_MELON());
|
$result->register("speckled_melon", fn() => Items::GLISTERING_MELON());
|
||||||
$result->register("spider_eye", fn() => Items::SPIDER_EYE());
|
$result->register("spider_eye", fn() => Items::SPIDER_EYE());
|
||||||
|
$result->register("spire_armor_trim_smithing_template", fn() => Items::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("splash_potion", fn() => Items::SPLASH_POTION());
|
$result->register("splash_potion", fn() => Items::SPLASH_POTION());
|
||||||
$result->register("spruce_boat", fn() => Items::SPRUCE_BOAT());
|
$result->register("spruce_boat", fn() => Items::SPRUCE_BOAT());
|
||||||
$result->register("spyglass", fn() => Items::SPYGLASS());
|
$result->register("spyglass", fn() => Items::SPYGLASS());
|
||||||
@ -1475,13 +1487,18 @@ final class StringToItemParser extends StringToTParser{
|
|||||||
$result->register("sweet_berries", fn() => Items::SWEET_BERRIES());
|
$result->register("sweet_berries", fn() => Items::SWEET_BERRIES());
|
||||||
$result->register("tonic", fn() => Items::MEDICINE()->setType(MedicineType::TONIC));
|
$result->register("tonic", fn() => Items::MEDICINE()->setType(MedicineType::TONIC));
|
||||||
$result->register("torchflower_seeds", fn() => Items::TORCHFLOWER_SEEDS());
|
$result->register("torchflower_seeds", fn() => Items::TORCHFLOWER_SEEDS());
|
||||||
|
$result->register("tide_armor_trim_smithing_template", fn() => Items::TIDE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("totem", fn() => Items::TOTEM());
|
$result->register("totem", fn() => Items::TOTEM());
|
||||||
$result->register("turtle_helmet", fn() => Items::TURTLE_HELMET());
|
$result->register("turtle_helmet", fn() => Items::TURTLE_HELMET());
|
||||||
|
$result->register("vex_armor_trim_smithing_template", fn() => Items::VEX_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("turtle_shell_piece", fn() => Items::SCUTE());
|
$result->register("turtle_shell_piece", fn() => Items::SCUTE());
|
||||||
$result->register("villager_spawn_egg", fn() => Items::VILLAGER_SPAWN_EGG());
|
$result->register("villager_spawn_egg", fn() => Items::VILLAGER_SPAWN_EGG());
|
||||||
|
$result->register("ward_armor_trim_smithing_template", fn() => Items::WARD_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("water_bucket", fn() => Items::WATER_BUCKET());
|
$result->register("water_bucket", fn() => Items::WATER_BUCKET());
|
||||||
|
$result->register("wayfinder_armor_trim_smithing_template", fn() => Items::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("wheat", fn() => Items::WHEAT());
|
$result->register("wheat", fn() => Items::WHEAT());
|
||||||
$result->register("wheat_seeds", fn() => Items::WHEAT_SEEDS());
|
$result->register("wheat_seeds", fn() => Items::WHEAT_SEEDS());
|
||||||
|
$result->register("wild_armor_trim_smithing_template", fn() => Items::WILD_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||||
$result->register("wooden_axe", fn() => Items::WOODEN_AXE());
|
$result->register("wooden_axe", fn() => Items::WOODEN_AXE());
|
||||||
$result->register("wooden_hoe", fn() => Items::WOODEN_HOE());
|
$result->register("wooden_hoe", fn() => Items::WOODEN_HOE());
|
||||||
$result->register("wooden_pickaxe", fn() => Items::WOODEN_PICKAXE());
|
$result->register("wooden_pickaxe", fn() => Items::WOODEN_PICKAXE());
|
||||||
|
@ -121,6 +121,7 @@ use function strtolower;
|
|||||||
* @method static Clock CLOCK()
|
* @method static Clock CLOCK()
|
||||||
* @method static Clownfish CLOWNFISH()
|
* @method static Clownfish CLOWNFISH()
|
||||||
* @method static Coal COAL()
|
* @method static Coal COAL()
|
||||||
|
* @method static Item COAST_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static CocoaBeans COCOA_BEANS()
|
* @method static CocoaBeans COCOA_BEANS()
|
||||||
* @method static Compass COMPASS()
|
* @method static Compass COMPASS()
|
||||||
* @method static CookedChicken COOKED_CHICKEN()
|
* @method static CookedChicken COOKED_CHICKEN()
|
||||||
@ -148,6 +149,7 @@ use function strtolower;
|
|||||||
* @method static Item DISC_FRAGMENT_5()
|
* @method static Item DISC_FRAGMENT_5()
|
||||||
* @method static Item DRAGON_BREATH()
|
* @method static Item DRAGON_BREATH()
|
||||||
* @method static DriedKelp DRIED_KELP()
|
* @method static DriedKelp DRIED_KELP()
|
||||||
|
* @method static Item DUNE_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static Dye DYE()
|
* @method static Dye DYE()
|
||||||
* @method static Item ECHO_SHARD()
|
* @method static Item ECHO_SHARD()
|
||||||
* @method static Egg EGG()
|
* @method static Egg EGG()
|
||||||
@ -156,6 +158,7 @@ use function strtolower;
|
|||||||
* @method static GoldenAppleEnchanted ENCHANTED_GOLDEN_APPLE()
|
* @method static GoldenAppleEnchanted ENCHANTED_GOLDEN_APPLE()
|
||||||
* @method static EnderPearl ENDER_PEARL()
|
* @method static EnderPearl ENDER_PEARL()
|
||||||
* @method static ExperienceBottle EXPERIENCE_BOTTLE()
|
* @method static ExperienceBottle EXPERIENCE_BOTTLE()
|
||||||
|
* @method static Item EYE_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static Item FEATHER()
|
* @method static Item FEATHER()
|
||||||
* @method static Item FERMENTED_SPIDER_EYE()
|
* @method static Item FERMENTED_SPIDER_EYE()
|
||||||
* @method static FireCharge FIRE_CHARGE()
|
* @method static FireCharge FIRE_CHARGE()
|
||||||
@ -185,6 +188,7 @@ use function strtolower;
|
|||||||
* @method static Item HEART_OF_THE_SEA()
|
* @method static Item HEART_OF_THE_SEA()
|
||||||
* @method static Item HONEYCOMB()
|
* @method static Item HONEYCOMB()
|
||||||
* @method static HoneyBottle HONEY_BOTTLE()
|
* @method static HoneyBottle HONEY_BOTTLE()
|
||||||
|
* @method static Item HOST_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static Item INK_SAC()
|
* @method static Item INK_SAC()
|
||||||
* @method static Axe IRON_AXE()
|
* @method static Axe IRON_AXE()
|
||||||
* @method static Armor IRON_BOOTS()
|
* @method static Armor IRON_BOOTS()
|
||||||
@ -227,6 +231,7 @@ use function strtolower;
|
|||||||
* @method static Item NETHERITE_SCRAP()
|
* @method static Item NETHERITE_SCRAP()
|
||||||
* @method static Shovel NETHERITE_SHOVEL()
|
* @method static Shovel NETHERITE_SHOVEL()
|
||||||
* @method static Sword NETHERITE_SWORD()
|
* @method static Sword NETHERITE_SWORD()
|
||||||
|
* @method static Item NETHERITE_UPGRADE_SMITHING_TEMPLATE()
|
||||||
* @method static Item NETHER_BRICK()
|
* @method static Item NETHER_BRICK()
|
||||||
* @method static Item NETHER_QUARTZ()
|
* @method static Item NETHER_QUARTZ()
|
||||||
* @method static Item NETHER_STAR()
|
* @method static Item NETHER_STAR()
|
||||||
@ -235,6 +240,7 @@ use function strtolower;
|
|||||||
* @method static PaintingItem PAINTING()
|
* @method static PaintingItem PAINTING()
|
||||||
* @method static Item PAPER()
|
* @method static Item PAPER()
|
||||||
* @method static Item PHANTOM_MEMBRANE()
|
* @method static Item PHANTOM_MEMBRANE()
|
||||||
|
* @method static PitcherPod PITCHER_POD()
|
||||||
* @method static PoisonousPotato POISONOUS_POTATO()
|
* @method static PoisonousPotato POISONOUS_POTATO()
|
||||||
* @method static Item POPPED_CHORUS_FRUIT()
|
* @method static Item POPPED_CHORUS_FRUIT()
|
||||||
* @method static Potato POTATO()
|
* @method static Potato POTATO()
|
||||||
@ -247,6 +253,7 @@ use function strtolower;
|
|||||||
* @method static Item RABBIT_FOOT()
|
* @method static Item RABBIT_FOOT()
|
||||||
* @method static Item RABBIT_HIDE()
|
* @method static Item RABBIT_HIDE()
|
||||||
* @method static RabbitStew RABBIT_STEW()
|
* @method static RabbitStew RABBIT_STEW()
|
||||||
|
* @method static Item RAISER_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static RawBeef RAW_BEEF()
|
* @method static RawBeef RAW_BEEF()
|
||||||
* @method static RawChicken RAW_CHICKEN()
|
* @method static RawChicken RAW_CHICKEN()
|
||||||
* @method static Item RAW_COPPER()
|
* @method static Item RAW_COPPER()
|
||||||
@ -273,13 +280,19 @@ use function strtolower;
|
|||||||
* @method static Record RECORD_WAIT()
|
* @method static Record RECORD_WAIT()
|
||||||
* @method static Record RECORD_WARD()
|
* @method static Record RECORD_WARD()
|
||||||
* @method static Redstone REDSTONE_DUST()
|
* @method static Redstone REDSTONE_DUST()
|
||||||
|
* @method static Item RIB_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static RottenFlesh ROTTEN_FLESH()
|
* @method static RottenFlesh ROTTEN_FLESH()
|
||||||
* @method static Item SCUTE()
|
* @method static Item SCUTE()
|
||||||
|
* @method static Item SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
|
* @method static Item SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static Shears SHEARS()
|
* @method static Shears SHEARS()
|
||||||
* @method static Item SHULKER_SHELL()
|
* @method static Item SHULKER_SHELL()
|
||||||
|
* @method static Item SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static Item SLIMEBALL()
|
* @method static Item SLIMEBALL()
|
||||||
|
* @method static Item SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static Snowball SNOWBALL()
|
* @method static Snowball SNOWBALL()
|
||||||
* @method static SpiderEye SPIDER_EYE()
|
* @method static SpiderEye SPIDER_EYE()
|
||||||
|
* @method static Item SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static SplashPotion SPLASH_POTION()
|
* @method static SplashPotion SPLASH_POTION()
|
||||||
* @method static Boat SPRUCE_BOAT()
|
* @method static Boat SPRUCE_BOAT()
|
||||||
* @method static ItemBlockWallOrFloor SPRUCE_SIGN()
|
* @method static ItemBlockWallOrFloor SPRUCE_SIGN()
|
||||||
@ -296,14 +309,19 @@ use function strtolower;
|
|||||||
* @method static Item SUGAR()
|
* @method static Item SUGAR()
|
||||||
* @method static SuspiciousStew SUSPICIOUS_STEW()
|
* @method static SuspiciousStew SUSPICIOUS_STEW()
|
||||||
* @method static SweetBerries SWEET_BERRIES()
|
* @method static SweetBerries SWEET_BERRIES()
|
||||||
|
* @method static Item TIDE_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static TorchflowerSeeds TORCHFLOWER_SEEDS()
|
* @method static TorchflowerSeeds TORCHFLOWER_SEEDS()
|
||||||
* @method static Totem TOTEM()
|
* @method static Totem TOTEM()
|
||||||
* @method static TurtleHelmet TURTLE_HELMET()
|
* @method static TurtleHelmet TURTLE_HELMET()
|
||||||
|
* @method static Item VEX_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static SpawnEgg VILLAGER_SPAWN_EGG()
|
* @method static SpawnEgg VILLAGER_SPAWN_EGG()
|
||||||
|
* @method static Item WARD_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static ItemBlockWallOrFloor WARPED_SIGN()
|
* @method static ItemBlockWallOrFloor WARPED_SIGN()
|
||||||
* @method static LiquidBucket WATER_BUCKET()
|
* @method static LiquidBucket WATER_BUCKET()
|
||||||
|
* @method static Item WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static Item WHEAT()
|
* @method static Item WHEAT()
|
||||||
* @method static WheatSeeds WHEAT_SEEDS()
|
* @method static WheatSeeds WHEAT_SEEDS()
|
||||||
|
* @method static Item WILD_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||||
* @method static Axe WOODEN_AXE()
|
* @method static Axe WOODEN_AXE()
|
||||||
* @method static Hoe WOODEN_HOE()
|
* @method static Hoe WOODEN_HOE()
|
||||||
* @method static Pickaxe WOODEN_PICKAXE()
|
* @method static Pickaxe WOODEN_PICKAXE()
|
||||||
@ -339,6 +357,7 @@ final class VanillaItems{
|
|||||||
self::registerArmorItems();
|
self::registerArmorItems();
|
||||||
self::registerSpawnEggs();
|
self::registerSpawnEggs();
|
||||||
self::registerTierToolItems();
|
self::registerTierToolItems();
|
||||||
|
self::registerSmithingTemplates();
|
||||||
|
|
||||||
self::register("air", Blocks::AIR()->asItem()->setCount(0));
|
self::register("air", Blocks::AIR()->asItem()->setCount(0));
|
||||||
|
|
||||||
@ -485,6 +504,7 @@ final class VanillaItems{
|
|||||||
self::register("painting", new PaintingItem(new IID(Ids::PAINTING), "Painting"));
|
self::register("painting", new PaintingItem(new IID(Ids::PAINTING), "Painting"));
|
||||||
self::register("paper", new Item(new IID(Ids::PAPER), "Paper"));
|
self::register("paper", new Item(new IID(Ids::PAPER), "Paper"));
|
||||||
self::register("phantom_membrane", new Item(new IID(Ids::PHANTOM_MEMBRANE), "Phantom Membrane"));
|
self::register("phantom_membrane", new Item(new IID(Ids::PHANTOM_MEMBRANE), "Phantom Membrane"));
|
||||||
|
self::register("pitcher_pod", new PitcherPod(new IID(Ids::PITCHER_POD), "Pitcher Pod"));
|
||||||
self::register("poisonous_potato", new PoisonousPotato(new IID(Ids::POISONOUS_POTATO), "Poisonous Potato"));
|
self::register("poisonous_potato", new PoisonousPotato(new IID(Ids::POISONOUS_POTATO), "Poisonous Potato"));
|
||||||
self::register("popped_chorus_fruit", new Item(new IID(Ids::POPPED_CHORUS_FRUIT), "Popped Chorus Fruit"));
|
self::register("popped_chorus_fruit", new Item(new IID(Ids::POPPED_CHORUS_FRUIT), "Popped Chorus Fruit"));
|
||||||
self::register("potato", new Potato(new IID(Ids::POTATO), "Potato"));
|
self::register("potato", new Potato(new IID(Ids::POTATO), "Potato"));
|
||||||
@ -644,4 +664,24 @@ final class VanillaItems{
|
|||||||
self::register("netherite_leggings", new Armor(new IID(Ids::NETHERITE_LEGGINGS), "Netherite Leggings", new ArmorTypeInfo(6, 556, ArmorInventory::SLOT_LEGS, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::LEGGINGS]));
|
self::register("netherite_leggings", new Armor(new IID(Ids::NETHERITE_LEGGINGS), "Netherite Leggings", new ArmorTypeInfo(6, 556, ArmorInventory::SLOT_LEGS, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::LEGGINGS]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function registerSmithingTemplates() : void{
|
||||||
|
self::register("netherite_upgrade_smithing_template", new Item(new IID(Ids::NETHERITE_UPGRADE_SMITHING_TEMPLATE), "Netherite Upgrade Smithing Template"));
|
||||||
|
self::register("coast_armor_trim_smithing_template", new Item(new IID(Ids::COAST_ARMOR_TRIM_SMITHING_TEMPLATE), "Coast Armor Trim Smithing Template"));
|
||||||
|
self::register("dune_armor_trim_smithing_template", new Item(new IID(Ids::DUNE_ARMOR_TRIM_SMITHING_TEMPLATE), "Dune Armor Trim Smithing Template"));
|
||||||
|
self::register("eye_armor_trim_smithing_template", new Item(new IID(Ids::EYE_ARMOR_TRIM_SMITHING_TEMPLATE), "Eye Armor Trim Smithing Template"));
|
||||||
|
self::register("host_armor_trim_smithing_template", new Item(new IID(Ids::HOST_ARMOR_TRIM_SMITHING_TEMPLATE), "Host Armor Trim Smithing Template"));
|
||||||
|
self::register("raiser_armor_trim_smithing_template", new Item(new IID(Ids::RAISER_ARMOR_TRIM_SMITHING_TEMPLATE), "Raiser Armor Trim Smithing Template"));
|
||||||
|
self::register("rib_armor_trim_smithing_template", new Item(new IID(Ids::RIB_ARMOR_TRIM_SMITHING_TEMPLATE), "Rib Armor Trim Smithing Template"));
|
||||||
|
self::register("sentry_armor_trim_smithing_template", new Item(new IID(Ids::SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE), "Sentry Armor Trim Smithing Template"));
|
||||||
|
self::register("shaper_armor_trim_smithing_template", new Item(new IID(Ids::SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE), "Shaper Armor Trim Smithing Template"));
|
||||||
|
self::register("silence_armor_trim_smithing_template", new Item(new IID(Ids::SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE), "Silence Armor Trim Smithing Template"));
|
||||||
|
self::register("snout_armor_trim_smithing_template", new Item(new IID(Ids::SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE), "Snout Armor Trim Smithing Template"));
|
||||||
|
self::register("spire_armor_trim_smithing_template", new Item(new IID(Ids::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE), "Spire Armor Trim Smithing Template"));
|
||||||
|
self::register("tide_armor_trim_smithing_template", new Item(new IID(Ids::TIDE_ARMOR_TRIM_SMITHING_TEMPLATE), "Tide Armor Trim Smithing Template"));
|
||||||
|
self::register("vex_armor_trim_smithing_template", new Item(new IID(Ids::VEX_ARMOR_TRIM_SMITHING_TEMPLATE), "Vex Armor Trim Smithing Template"));
|
||||||
|
self::register("ward_armor_trim_smithing_template", new Item(new IID(Ids::WARD_ARMOR_TRIM_SMITHING_TEMPLATE), "Ward Armor Trim Smithing Template"));
|
||||||
|
self::register("wayfinder_armor_trim_smithing_template", new Item(new IID(Ids::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE), "Wayfinder Armor Trim Smithing Template"));
|
||||||
|
self::register("wild_armor_trim_smithing_template", new Item(new IID(Ids::WILD_ARMOR_TRIM_SMITHING_TEMPLATE), "Wild Armor Trim Smithing Template"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,7 @@ use function count;
|
|||||||
use function get_class;
|
use function get_class;
|
||||||
use function implode;
|
use function implode;
|
||||||
use function in_array;
|
use function in_array;
|
||||||
|
use function is_string;
|
||||||
use function json_encode;
|
use function json_encode;
|
||||||
use function random_bytes;
|
use function random_bytes;
|
||||||
use function str_split;
|
use function str_split;
|
||||||
@ -158,8 +159,8 @@ class NetworkSession{
|
|||||||
private array $sendBuffer = [];
|
private array $sendBuffer = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \SplQueue|CompressBatchPromise[]
|
* @var \SplQueue|CompressBatchPromise[]|string[]
|
||||||
* @phpstan-var \SplQueue<CompressBatchPromise>
|
* @phpstan-var \SplQueue<CompressBatchPromise|string>
|
||||||
*/
|
*/
|
||||||
private \SplQueue $compressedQueue;
|
private \SplQueue $compressedQueue;
|
||||||
private bool $forceAsyncCompression = true;
|
private bool $forceAsyncCompression = true;
|
||||||
@ -235,8 +236,10 @@ class NetworkSession{
|
|||||||
$this->onPlayerCreated(...),
|
$this->onPlayerCreated(...),
|
||||||
function() : void{
|
function() : void{
|
||||||
//TODO: this should never actually occur... right?
|
//TODO: this should never actually occur... right?
|
||||||
$this->logger->error("Failed to create player");
|
$this->disconnectWithError(
|
||||||
$this->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_error_internal());
|
reason: "Failed to create player",
|
||||||
|
disconnectScreenMessage: KnownTranslationFactory::pocketmine_disconnect_error_internal()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -525,13 +528,12 @@ class NetworkSession{
|
|||||||
PacketBatch::encodeRaw($stream, $this->sendBuffer);
|
PacketBatch::encodeRaw($stream, $this->sendBuffer);
|
||||||
|
|
||||||
if($this->enableCompression){
|
if($this->enableCompression){
|
||||||
$promise = $this->server->prepareBatch($stream->getBuffer(), $this->compressor, $syncMode, Timings::$playerNetworkSendCompressSessionBuffer);
|
$batch = $this->server->prepareBatch($stream->getBuffer(), $this->compressor, $syncMode, Timings::$playerNetworkSendCompressSessionBuffer);
|
||||||
}else{
|
}else{
|
||||||
$promise = new CompressBatchPromise();
|
$batch = $stream->getBuffer();
|
||||||
$promise->resolve($stream->getBuffer());
|
|
||||||
}
|
}
|
||||||
$this->sendBuffer = [];
|
$this->sendBuffer = [];
|
||||||
$this->queueCompressedNoBufferFlush($promise, $immediate);
|
$this->queueCompressedNoBufferFlush($batch, $immediate);
|
||||||
}finally{
|
}finally{
|
||||||
Timings::$playerNetworkSend->stopTiming();
|
Timings::$playerNetworkSend->stopTiming();
|
||||||
}
|
}
|
||||||
@ -550,7 +552,7 @@ class NetworkSession{
|
|||||||
|
|
||||||
public function getTypeConverter() : TypeConverter{ return $this->typeConverter; }
|
public function getTypeConverter() : TypeConverter{ return $this->typeConverter; }
|
||||||
|
|
||||||
public function queueCompressed(CompressBatchPromise $payload, bool $immediate = false) : void{
|
public function queueCompressed(CompressBatchPromise|string $payload, bool $immediate = false) : void{
|
||||||
Timings::$playerNetworkSend->startTiming();
|
Timings::$playerNetworkSend->startTiming();
|
||||||
try{
|
try{
|
||||||
$this->flushSendBuffer($immediate); //Maintain ordering if possible
|
$this->flushSendBuffer($immediate); //Maintain ordering if possible
|
||||||
@ -560,38 +562,51 @@ class NetworkSession{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function queueCompressedNoBufferFlush(CompressBatchPromise $payload, bool $immediate = false) : void{
|
private function queueCompressedNoBufferFlush(CompressBatchPromise|string $batch, bool $immediate = false) : void{
|
||||||
Timings::$playerNetworkSend->startTiming();
|
Timings::$playerNetworkSend->startTiming();
|
||||||
try{
|
try{
|
||||||
|
if(is_string($batch)){
|
||||||
if($immediate){
|
if($immediate){
|
||||||
//Skips all queues
|
//Skips all queues
|
||||||
$this->sendEncoded($payload->getResult(), true);
|
$this->sendEncoded($batch, true);
|
||||||
}else{
|
}else{
|
||||||
$this->compressedQueue->enqueue($payload);
|
$this->compressedQueue->enqueue($batch);
|
||||||
$payload->onResolve(function(CompressBatchPromise $payload) : void{
|
$this->flushCompressedQueue();
|
||||||
if($this->connected && $this->compressedQueue->bottom() === $payload){
|
|
||||||
Timings::$playerNetworkSend->startTiming();
|
|
||||||
try{
|
|
||||||
$this->compressedQueue->dequeue(); //result unused
|
|
||||||
$this->sendEncoded($payload->getResult());
|
|
||||||
|
|
||||||
while(!$this->compressedQueue->isEmpty()){
|
|
||||||
/** @var CompressBatchPromise $current */
|
|
||||||
$current = $this->compressedQueue->bottom();
|
|
||||||
if($current->hasResult()){
|
|
||||||
$this->compressedQueue->dequeue();
|
|
||||||
|
|
||||||
$this->sendEncoded($current->getResult());
|
|
||||||
}else{
|
|
||||||
//can't send any more queued until this one is ready
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}elseif($immediate){
|
||||||
|
//Skips all queues
|
||||||
|
$this->sendEncoded($batch->getResult(), true);
|
||||||
|
}else{
|
||||||
|
$this->compressedQueue->enqueue($batch);
|
||||||
|
$batch->onResolve(function() : void{
|
||||||
|
if($this->connected){
|
||||||
|
$this->flushCompressedQueue();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}finally{
|
}finally{
|
||||||
Timings::$playerNetworkSend->stopTiming();
|
Timings::$playerNetworkSend->stopTiming();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
private function flushCompressedQueue() : void{
|
||||||
|
Timings::$playerNetworkSend->startTiming();
|
||||||
|
try{
|
||||||
|
while(!$this->compressedQueue->isEmpty()){
|
||||||
|
/** @var CompressBatchPromise|string $current */
|
||||||
|
$current = $this->compressedQueue->bottom();
|
||||||
|
if(is_string($current)){
|
||||||
|
$this->compressedQueue->dequeue();
|
||||||
|
$this->sendEncoded($current);
|
||||||
|
|
||||||
|
}elseif($current->hasResult()){
|
||||||
|
$this->compressedQueue->dequeue();
|
||||||
|
$this->sendEncoded($current->getResult());
|
||||||
|
|
||||||
|
}else{
|
||||||
|
//can't send any more queued until this one is ready
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}finally{
|
}finally{
|
||||||
Timings::$playerNetworkSend->stopTiming();
|
Timings::$playerNetworkSend->stopTiming();
|
||||||
@ -662,8 +677,13 @@ class NetworkSession{
|
|||||||
}, $reason);
|
}, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function disconnectWithError(Translatable|string $reason) : void{
|
public function disconnectWithError(Translatable|string $reason, Translatable|string|null $disconnectScreenMessage = null) : void{
|
||||||
$this->disconnect(KnownTranslationFactory::pocketmine_disconnect_error($reason, implode("-", str_split(bin2hex(random_bytes(6)), 4))));
|
$errorId = implode("-", str_split(bin2hex(random_bytes(6)), 4));
|
||||||
|
|
||||||
|
$this->disconnect(
|
||||||
|
reason: KnownTranslationFactory::pocketmine_disconnect_error($reason, $errorId)->prefix(TextFormat::RED),
|
||||||
|
disconnectScreenMessage: KnownTranslationFactory::pocketmine_disconnect_error($disconnectScreenMessage ?? $reason, $errorId),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function disconnectIncompatibleProtocol(int $protocolVersion) : void{
|
public function disconnectIncompatibleProtocol(int $protocolVersion) : void{
|
||||||
@ -722,7 +742,10 @@ class NetworkSession{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($error !== null){
|
if($error !== null){
|
||||||
$this->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_invalidSession($error));
|
$this->disconnectWithError(
|
||||||
|
reason: KnownTranslationFactory::pocketmine_disconnect_invalidSession($error),
|
||||||
|
disconnectScreenMessage: KnownTranslationFactory::pocketmine_disconnect_error_authentication()
|
||||||
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1118,12 +1141,12 @@ class NetworkSession{
|
|||||||
*/
|
*/
|
||||||
public function syncPlayerList(array $players) : void{
|
public function syncPlayerList(array $players) : void{
|
||||||
$this->sendDataPacket(PlayerListPacket::add(array_map(function(Player $player) : PlayerListEntry{
|
$this->sendDataPacket(PlayerListPacket::add(array_map(function(Player $player) : PlayerListEntry{
|
||||||
return PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), TypeConverter::getInstance()->getSkinAdapter()->toSkinData($player->getSkin()), $player->getXuid());
|
return PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $this->typeConverter->getSkinAdapter()->toSkinData($player->getSkin()), $player->getXuid());
|
||||||
}, $players)));
|
}, $players)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onPlayerAdded(Player $p) : void{
|
public function onPlayerAdded(Player $p) : void{
|
||||||
$this->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($p->getUniqueId(), $p->getId(), $p->getDisplayName(), TypeConverter::getInstance()->getSkinAdapter()->toSkinData($p->getSkin()), $p->getXuid())]));
|
$this->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($p->getUniqueId(), $p->getId(), $p->getDisplayName(), $this->typeConverter->getSkinAdapter()->toSkinData($p->getSkin()), $p->getXuid())]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onPlayerRemoved(Player $p) : void{
|
public function onPlayerRemoved(Player $p) : void{
|
||||||
|
@ -88,9 +88,9 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
|
|||||||
PacketBatch::encodeRaw($stream, $packetBuffers);
|
PacketBatch::encodeRaw($stream, $packetBuffers);
|
||||||
$batchBuffer = $stream->getBuffer();
|
$batchBuffer = $stream->getBuffer();
|
||||||
|
|
||||||
$promise = $this->server->prepareBatch($batchBuffer, $compressor, timings: Timings::$playerNetworkSendCompressBroadcast);
|
$batch = $this->server->prepareBatch($batchBuffer, $compressor, timings: Timings::$playerNetworkSendCompressBroadcast);
|
||||||
foreach($compressorTargets as $target){
|
foreach($compressorTargets as $target){
|
||||||
$target->queueCompressed($promise);
|
$target->queueCompressed($batch);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
foreach($compressorTargets as $target){
|
foreach($compressorTargets as $target){
|
||||||
|
25
src/network/mcpe/cache/ChunkCache.php
vendored
25
src/network/mcpe/cache/ChunkCache.php
vendored
@ -136,32 +136,19 @@ class ChunkCache implements ChunkListener{
|
|||||||
return $existing !== null;
|
return $existing !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Restarts an async request for an unresolved chunk.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
*/
|
|
||||||
private function restartPendingRequest(int $chunkX, int $chunkZ) : void{
|
|
||||||
$chunkHash = World::chunkHash($chunkX, $chunkZ);
|
|
||||||
$existing = $this->caches[$chunkHash] ?? null;
|
|
||||||
if($existing === null || $existing->hasResult()){
|
|
||||||
throw new \InvalidArgumentException("Restart can only be applied to unresolved promises");
|
|
||||||
}
|
|
||||||
$existing->cancel();
|
|
||||||
unset($this->caches[$chunkHash]);
|
|
||||||
|
|
||||||
$this->request($chunkX, $chunkZ)->onResolve(...$existing->getResolveCallbacks());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
private function destroyOrRestart(int $chunkX, int $chunkZ) : void{
|
private function destroyOrRestart(int $chunkX, int $chunkZ) : void{
|
||||||
$cache = $this->caches[World::chunkHash($chunkX, $chunkZ)] ?? null;
|
$chunkPosHash = World::chunkHash($chunkX, $chunkZ);
|
||||||
|
$cache = $this->caches[$chunkPosHash] ?? null;
|
||||||
if($cache !== null){
|
if($cache !== null){
|
||||||
if(!$cache->hasResult()){
|
if(!$cache->hasResult()){
|
||||||
//some requesters are waiting for this chunk, so their request needs to be fulfilled
|
//some requesters are waiting for this chunk, so their request needs to be fulfilled
|
||||||
$this->restartPendingRequest($chunkX, $chunkZ);
|
$cache->cancel();
|
||||||
|
unset($this->caches[$chunkPosHash]);
|
||||||
|
|
||||||
|
$this->request($chunkX, $chunkZ)->onResolve(...$cache->getResolveCallbacks());
|
||||||
}else{
|
}else{
|
||||||
//dump the cache, it'll be regenerated the next time it's requested
|
//dump the cache, it'll be regenerated the next time it's requested
|
||||||
$this->destroy($chunkX, $chunkZ);
|
$this->destroy($chunkX, $chunkZ);
|
||||||
|
2
src/network/mcpe/cache/CraftingDataCache.php
vendored
2
src/network/mcpe/cache/CraftingDataCache.php
vendored
@ -160,7 +160,7 @@ final class CraftingDataCache{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$potionContainerChangeRecipes = [];
|
$potionContainerChangeRecipes = [];
|
||||||
$itemTypeDictionary = TypeConverter::getInstance()->getItemTypeDictionary();
|
$itemTypeDictionary = $converter->getItemTypeDictionary();
|
||||||
foreach($manager->getPotionContainerChangeRecipes() as $recipe){
|
foreach($manager->getPotionContainerChangeRecipes() as $recipe){
|
||||||
$input = $itemTypeDictionary->fromStringId($recipe->getInputItemId());
|
$input = $itemTypeDictionary->fromStringId($recipe->getInputItemId());
|
||||||
$ingredient = $converter->coreRecipeIngredientToNet($recipe->getIngredient())->getDescriptor();
|
$ingredient = $converter->coreRecipeIngredientToNet($recipe->getIngredient())->getDescriptor();
|
||||||
|
@ -73,8 +73,10 @@ class LoginPacketHandler extends PacketHandler{
|
|||||||
try{
|
try{
|
||||||
$skin = $this->session->getTypeConverter()->getSkinAdapter()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData));
|
$skin = $this->session->getTypeConverter()->getSkinAdapter()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData));
|
||||||
}catch(\InvalidArgumentException | InvalidSkinException $e){
|
}catch(\InvalidArgumentException | InvalidSkinException $e){
|
||||||
$this->session->getLogger()->debug("Invalid skin: " . $e->getMessage());
|
$this->session->disconnectWithError(
|
||||||
$this->session->disconnectWithError(KnownTranslationFactory::disconnectionScreen_invalidSkin());
|
reason: "Invalid skin: " . $e->getMessage(),
|
||||||
|
disconnectScreenMessage: KnownTranslationFactory::disconnectionScreen_invalidSkin()
|
||||||
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -85,8 +85,10 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function disconnectWithError(string $error) : void{
|
private function disconnectWithError(string $error) : void{
|
||||||
$this->session->getLogger()->error("Error downloading resource packs: " . $error);
|
$this->session->disconnectWithError(
|
||||||
$this->session->disconnectWithError(KnownTranslationFactory::disconnectionScreen_resourcePack());
|
reason: "Error downloading resource packs: " . $error,
|
||||||
|
disconnectScreenMessage: KnownTranslationFactory::disconnectionScreen_resourcePack()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
|
public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
|
||||||
|
@ -219,11 +219,14 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
|||||||
$session->handleEncoded($buf);
|
$session->handleEncoded($buf);
|
||||||
}catch(PacketHandlingException $e){
|
}catch(PacketHandlingException $e){
|
||||||
$logger = $session->getLogger();
|
$logger = $session->getLogger();
|
||||||
$logger->error("Bad packet: " . $e->getMessage());
|
|
||||||
|
|
||||||
|
$session->disconnectWithError(
|
||||||
|
reason: "Bad packet: " . $e->getMessage(),
|
||||||
|
disconnectScreenMessage: KnownTranslationFactory::pocketmine_disconnect_error_badPacket()
|
||||||
|
);
|
||||||
//intentionally doesn't use logException, we don't want spammy packet error traces to appear in release mode
|
//intentionally doesn't use logException, we don't want spammy packet error traces to appear in release mode
|
||||||
$logger->debug(implode("\n", Utils::printableExceptionInfo($e)));
|
$logger->debug(implode("\n", Utils::printableExceptionInfo($e)));
|
||||||
$session->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_error_badPacket());
|
|
||||||
$this->interface->blockAddress($address, 5);
|
$this->interface->blockAddress($address, 5);
|
||||||
}catch(\Throwable $e){
|
}catch(\Throwable $e){
|
||||||
//record the name of the player who caused the crash, to make it easier to find the reproducing steps
|
//record the name of the player who caused the crash, to make it easier to find the reproducing steps
|
||||||
|
@ -813,13 +813,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
$this->usedChunks[$index] = UsedChunkStatus::REQUESTED_GENERATION;
|
$this->usedChunks[$index] = UsedChunkStatus::REQUESTED_GENERATION;
|
||||||
$this->activeChunkGenerationRequests[$index] = true;
|
$this->activeChunkGenerationRequests[$index] = true;
|
||||||
unset($this->loadQueue[$index]);
|
unset($this->loadQueue[$index]);
|
||||||
$this->getWorld()->registerChunkLoader($this->chunkLoader, $X, $Z, true);
|
$world->registerChunkLoader($this->chunkLoader, $X, $Z, true);
|
||||||
$this->getWorld()->registerChunkListener($this, $X, $Z);
|
$world->registerChunkListener($this, $X, $Z);
|
||||||
if(isset($this->tickingChunks[$index])){
|
if(isset($this->tickingChunks[$index])){
|
||||||
$this->getWorld()->registerTickingChunk($this->chunkTicker, $X, $Z);
|
$world->registerTickingChunk($this->chunkTicker, $X, $Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getWorld()->requestChunkPopulation($X, $Z, $this->chunkLoader)->onCompletion(
|
$world->requestChunkPopulation($X, $Z, $this->chunkLoader)->onCompletion(
|
||||||
function() use ($X, $Z, $index, $world) : void{
|
function() use ($X, $Z, $index, $world) : void{
|
||||||
if(!$this->isConnected() || !isset($this->usedChunks[$index]) || $world !== $this->getWorld()){
|
if(!$this->isConnected() || !isset($this->usedChunks[$index]) || $world !== $this->getWorld()){
|
||||||
return;
|
return;
|
||||||
|
@ -70,7 +70,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
|
|||||||
|
|
||||||
$this->configFile = Path::join($this->dataFolder, "config.yml");
|
$this->configFile = Path::join($this->dataFolder, "config.yml");
|
||||||
|
|
||||||
$prefix = $this->getDescription()->getPrefix();
|
$prefix = $this->description->getPrefix();
|
||||||
$this->logger = new PluginLogger($server->getLogger(), $prefix !== "" ? $prefix : $this->getName());
|
$this->logger = new PluginLogger($server->getLogger(), $prefix !== "" ? $prefix : $this->getName());
|
||||||
$this->scheduler = new TaskScheduler($this->getFullName());
|
$this->scheduler = new TaskScheduler($this->getFullName());
|
||||||
|
|
||||||
@ -145,9 +145,9 @@ abstract class PluginBase implements Plugin, CommandExecutor{
|
|||||||
private function registerYamlCommands() : void{
|
private function registerYamlCommands() : void{
|
||||||
$pluginCmds = [];
|
$pluginCmds = [];
|
||||||
|
|
||||||
foreach(Utils::stringifyKeys($this->getDescription()->getCommands()) as $key => $data){
|
foreach(Utils::stringifyKeys($this->description->getCommands()) as $key => $data){
|
||||||
if(str_contains($key, ":")){
|
if(str_contains($key, ":")){
|
||||||
$this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_commandError($key, $this->getDescription()->getFullName(), ":")));
|
$this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_commandError($key, $this->description->getFullName(), ":")));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
|
|||||||
$aliasList = [];
|
$aliasList = [];
|
||||||
foreach($data->getAliases() as $alias){
|
foreach($data->getAliases() as $alias){
|
||||||
if(str_contains($alias, ":")){
|
if(str_contains($alias, ":")){
|
||||||
$this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_aliasError($alias, $this->getDescription()->getFullName(), ":")));
|
$this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_aliasError($alias, $this->description->getFullName(), ":")));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$aliasList[] = $alias;
|
$aliasList[] = $alias;
|
||||||
@ -181,7 +181,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(count($pluginCmds) > 0){
|
if(count($pluginCmds) > 0){
|
||||||
$this->server->getCommandMap()->registerAll($this->getDescription()->getName(), $pluginCmds);
|
$this->server->getCommandMap()->registerAll($this->description->getName(), $pluginCmds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,9 +190,9 @@ abstract class PluginBase implements Plugin, CommandExecutor{
|
|||||||
* @phpstan-return (Command&PluginOwned)|null
|
* @phpstan-return (Command&PluginOwned)|null
|
||||||
*/
|
*/
|
||||||
public function getCommand(string $name){
|
public function getCommand(string $name){
|
||||||
$command = $this->getServer()->getPluginCommand($name);
|
$command = $this->server->getPluginCommand($name);
|
||||||
if($command === null || $command->getOwningPlugin() !== $this){
|
if($command === null || $command->getOwningPlugin() !== $this){
|
||||||
$command = $this->getServer()->getPluginCommand(strtolower($this->description->getName()) . ":" . $name);
|
$command = $this->server->getPluginCommand(strtolower($this->description->getName()) . ":" . $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($command instanceof PluginOwned && $command->getOwningPlugin() === $this){
|
if($command instanceof PluginOwned && $command->getOwningPlugin() === $this){
|
||||||
|
@ -35,6 +35,7 @@ use function get_class;
|
|||||||
use function str_starts_with;
|
use function str_starts_with;
|
||||||
|
|
||||||
abstract class Timings{
|
abstract class Timings{
|
||||||
|
public const GROUP_MINECRAFT = "Minecraft";
|
||||||
public const GROUP_BREAKDOWN = "Minecraft - Breakdown";
|
public const GROUP_BREAKDOWN = "Minecraft - Breakdown";
|
||||||
|
|
||||||
private static bool $initialized = false;
|
private static bool $initialized = false;
|
||||||
@ -134,8 +135,8 @@ abstract class Timings{
|
|||||||
self::$initialized = true;
|
self::$initialized = true;
|
||||||
|
|
||||||
self::$fullTick = new TimingsHandler("Full Server Tick");
|
self::$fullTick = new TimingsHandler("Full Server Tick");
|
||||||
self::$serverTick = new TimingsHandler("Server Tick Update Cycle", self::$fullTick, group: self::GROUP_BREAKDOWN);
|
self::$serverTick = new TimingsHandler("Server Tick Update Cycle", self::$fullTick);
|
||||||
self::$serverInterrupts = new TimingsHandler("Server Mid-Tick Processing", self::$fullTick, group: self::GROUP_BREAKDOWN);
|
self::$serverInterrupts = new TimingsHandler("Server Mid-Tick Processing", self::$fullTick);
|
||||||
self::$memoryManager = new TimingsHandler("Memory Manager");
|
self::$memoryManager = new TimingsHandler("Memory Manager");
|
||||||
self::$garbageCollector = new TimingsHandler("Garbage Collector", self::$memoryManager);
|
self::$garbageCollector = new TimingsHandler("Garbage Collector", self::$memoryManager);
|
||||||
self::$titleTick = new TimingsHandler("Console Title Tick");
|
self::$titleTick = new TimingsHandler("Console Title Tick");
|
||||||
@ -143,51 +144,51 @@ abstract class Timings{
|
|||||||
self::$connection = new TimingsHandler("Connection Handler");
|
self::$connection = new TimingsHandler("Connection Handler");
|
||||||
|
|
||||||
self::$playerNetworkSend = new TimingsHandler("Player Network Send", self::$connection);
|
self::$playerNetworkSend = new TimingsHandler("Player Network Send", self::$connection);
|
||||||
self::$playerNetworkSendCompress = new TimingsHandler("Player Network Send - Compression", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
self::$playerNetworkSendCompress = new TimingsHandler("Player Network Send - Compression", self::$playerNetworkSend);
|
||||||
self::$playerNetworkSendCompressBroadcast = new TimingsHandler("Player Network Send - Compression (Broadcast)", self::$playerNetworkSendCompress, group: self::GROUP_BREAKDOWN);
|
self::$playerNetworkSendCompressBroadcast = new TimingsHandler("Player Network Send - Compression (Broadcast)", self::$playerNetworkSendCompress);
|
||||||
self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler("Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress, group: self::GROUP_BREAKDOWN);
|
self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler("Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress);
|
||||||
self::$playerNetworkSendEncrypt = new TimingsHandler("Player Network Send - Encryption", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
self::$playerNetworkSendEncrypt = new TimingsHandler("Player Network Send - Encryption", self::$playerNetworkSend);
|
||||||
self::$playerNetworkSendInventorySync = new TimingsHandler("Player Network Send - Inventory Sync", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
self::$playerNetworkSendInventorySync = new TimingsHandler("Player Network Send - Inventory Sync", self::$playerNetworkSend);
|
||||||
self::$playerNetworkSendPreSpawnGameData = new TimingsHandler("Player Network Send - Pre-Spawn Game Data", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
self::$playerNetworkSendPreSpawnGameData = new TimingsHandler("Player Network Send - Pre-Spawn Game Data", self::$playerNetworkSend);
|
||||||
|
|
||||||
self::$playerNetworkReceive = new TimingsHandler("Player Network Receive", self::$connection);
|
self::$playerNetworkReceive = new TimingsHandler("Player Network Receive", self::$connection);
|
||||||
self::$playerNetworkReceiveDecompress = new TimingsHandler("Player Network Receive - Decompression", self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN);
|
self::$playerNetworkReceiveDecompress = new TimingsHandler("Player Network Receive - Decompression", self::$playerNetworkReceive);
|
||||||
self::$playerNetworkReceiveDecrypt = new TimingsHandler("Player Network Receive - Decryption", self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN);
|
self::$playerNetworkReceiveDecrypt = new TimingsHandler("Player Network Receive - Decryption", self::$playerNetworkReceive);
|
||||||
|
|
||||||
self::$broadcastPackets = new TimingsHandler("Broadcast Packets", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
self::$broadcastPackets = new TimingsHandler("Broadcast Packets", self::$playerNetworkSend);
|
||||||
|
|
||||||
self::$playerMove = new TimingsHandler("Player Movement");
|
self::$playerMove = new TimingsHandler("Player Movement");
|
||||||
self::$playerChunkOrder = new TimingsHandler("Player Order Chunks");
|
self::$playerChunkOrder = new TimingsHandler("Player Order Chunks");
|
||||||
self::$playerChunkSend = new TimingsHandler("Player Network Send - Chunks", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
self::$playerChunkSend = new TimingsHandler("Player Network Send - Chunks", self::$playerNetworkSend);
|
||||||
self::$scheduler = new TimingsHandler("Scheduler");
|
self::$scheduler = new TimingsHandler("Scheduler");
|
||||||
self::$serverCommand = new TimingsHandler("Server Command");
|
self::$serverCommand = new TimingsHandler("Server Command");
|
||||||
self::$permissibleCalculation = new TimingsHandler("Permissible Calculation");
|
self::$permissibleCalculation = new TimingsHandler("Permissible Calculation");
|
||||||
self::$permissibleCalculationDiff = new TimingsHandler("Permissible Calculation - Diff", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN);
|
self::$permissibleCalculationDiff = new TimingsHandler("Permissible Calculation - Diff", self::$permissibleCalculation);
|
||||||
self::$permissibleCalculationCallback = new TimingsHandler("Permissible Calculation - Callbacks", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN);
|
self::$permissibleCalculationCallback = new TimingsHandler("Permissible Calculation - Callbacks", self::$permissibleCalculation);
|
||||||
|
|
||||||
self::$syncPlayerDataLoad = new TimingsHandler("Player Data Load");
|
self::$syncPlayerDataLoad = new TimingsHandler("Player Data Load");
|
||||||
self::$syncPlayerDataSave = new TimingsHandler("Player Data Save");
|
self::$syncPlayerDataSave = new TimingsHandler("Player Data Save");
|
||||||
|
|
||||||
self::$entityMove = new TimingsHandler("Entity Movement", group: self::GROUP_BREAKDOWN);
|
self::$entityMove = new TimingsHandler("Entity Movement");
|
||||||
self::$entityMoveCollision = new TimingsHandler("Entity Movement - Collision Checks", self::$entityMove, group: self::GROUP_BREAKDOWN);
|
self::$entityMoveCollision = new TimingsHandler("Entity Movement - Collision Checks", self::$entityMove);
|
||||||
|
|
||||||
self::$projectileMove = new TimingsHandler("Projectile Movement", self::$entityMove, group: self::GROUP_BREAKDOWN);
|
self::$projectileMove = new TimingsHandler("Projectile Movement", self::$entityMove);
|
||||||
self::$projectileMoveRayTrace = new TimingsHandler("Projectile Movement - Ray Tracing", self::$projectileMove, group: self::GROUP_BREAKDOWN);
|
self::$projectileMoveRayTrace = new TimingsHandler("Projectile Movement - Ray Tracing", self::$projectileMove);
|
||||||
|
|
||||||
self::$playerCheckNearEntities = new TimingsHandler("checkNearEntities", group: self::GROUP_BREAKDOWN);
|
self::$playerCheckNearEntities = new TimingsHandler("checkNearEntities");
|
||||||
self::$entityBaseTick = new TimingsHandler("Entity Base Tick", group: self::GROUP_BREAKDOWN);
|
self::$entityBaseTick = new TimingsHandler("Entity Base Tick");
|
||||||
self::$livingEntityBaseTick = new TimingsHandler("Entity Base Tick - Living", group: self::GROUP_BREAKDOWN);
|
self::$livingEntityBaseTick = new TimingsHandler("Entity Base Tick - Living");
|
||||||
self::$itemEntityBaseTick = new TimingsHandler("Entity Base Tick - ItemEntity", group: self::GROUP_BREAKDOWN);
|
self::$itemEntityBaseTick = new TimingsHandler("Entity Base Tick - ItemEntity");
|
||||||
|
|
||||||
self::$schedulerSync = new TimingsHandler("Scheduler - Sync Tasks", group: self::GROUP_BREAKDOWN);
|
self::$schedulerSync = new TimingsHandler("Scheduler - Sync Tasks");
|
||||||
|
|
||||||
self::$schedulerAsync = new TimingsHandler("Scheduler - Async Tasks", group: self::GROUP_BREAKDOWN);
|
self::$schedulerAsync = new TimingsHandler("Scheduler - Async Tasks");
|
||||||
self::$asyncTaskProgressUpdateParent = new TimingsHandler("Async Tasks - Progress Updates", self::$schedulerAsync, group: self::GROUP_BREAKDOWN);
|
self::$asyncTaskProgressUpdateParent = new TimingsHandler("Async Tasks - Progress Updates", self::$schedulerAsync);
|
||||||
self::$asyncTaskCompletionParent = new TimingsHandler("Async Tasks - Completion Handlers", self::$schedulerAsync, group: self::GROUP_BREAKDOWN);
|
self::$asyncTaskCompletionParent = new TimingsHandler("Async Tasks - Completion Handlers", self::$schedulerAsync);
|
||||||
self::$asyncTaskErrorParent = new TimingsHandler("Async Tasks - Error Handlers", self::$schedulerAsync, group: self::GROUP_BREAKDOWN);
|
self::$asyncTaskErrorParent = new TimingsHandler("Async Tasks - Error Handlers", self::$schedulerAsync);
|
||||||
|
|
||||||
self::$playerCommand = new TimingsHandler("Player Command", group: self::GROUP_BREAKDOWN);
|
self::$playerCommand = new TimingsHandler("Player Command");
|
||||||
self::$craftingDataCacheRebuild = new TimingsHandler("Build CraftingDataPacket Cache", group: self::GROUP_BREAKDOWN);
|
self::$craftingDataCacheRebuild = new TimingsHandler("Build CraftingDataPacket Cache");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +230,7 @@ abstract class Timings{
|
|||||||
}else{
|
}else{
|
||||||
$displayName = self::shortenCoreClassName($entity::class, "pocketmine\\entity\\");
|
$displayName = self::shortenCoreClassName($entity::class, "pocketmine\\entity\\");
|
||||||
}
|
}
|
||||||
self::$entityTypeTimingMap[$entity::class] = new TimingsHandler("Entity Tick - " . $displayName, group: self::GROUP_BREAKDOWN);
|
self::$entityTypeTimingMap[$entity::class] = new TimingsHandler("Entity Tick - " . $displayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$entityTypeTimingMap[$entity::class];
|
return self::$entityTypeTimingMap[$entity::class];
|
||||||
@ -239,8 +240,7 @@ abstract class Timings{
|
|||||||
self::init();
|
self::init();
|
||||||
if(!isset(self::$tileEntityTypeTimingMap[$tile::class])){
|
if(!isset(self::$tileEntityTypeTimingMap[$tile::class])){
|
||||||
self::$tileEntityTypeTimingMap[$tile::class] = new TimingsHandler(
|
self::$tileEntityTypeTimingMap[$tile::class] = new TimingsHandler(
|
||||||
"Block Entity Tick - " . self::shortenCoreClassName($tile::class, "pocketmine\\block\\tile\\"),
|
"Block Entity Tick - " . self::shortenCoreClassName($tile::class, "pocketmine\\block\\tile\\")
|
||||||
group: self::GROUP_BREAKDOWN
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +250,7 @@ abstract class Timings{
|
|||||||
public static function getReceiveDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
public static function getReceiveDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
||||||
self::init();
|
self::init();
|
||||||
if(!isset(self::$packetReceiveTimingMap[$pk::class])){
|
if(!isset(self::$packetReceiveTimingMap[$pk::class])){
|
||||||
self::$packetReceiveTimingMap[$pk::class] = new TimingsHandler("Receive - " . $pk->getName(), self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN);
|
self::$packetReceiveTimingMap[$pk::class] = new TimingsHandler("Receive - " . $pk->getName(), self::$playerNetworkReceive);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$packetReceiveTimingMap[$pk::class];
|
return self::$packetReceiveTimingMap[$pk::class];
|
||||||
@ -259,31 +259,28 @@ abstract class Timings{
|
|||||||
public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
||||||
return self::$packetDecodeTimingMap[$pk::class] ??= new TimingsHandler(
|
return self::$packetDecodeTimingMap[$pk::class] ??= new TimingsHandler(
|
||||||
"Decode - " . $pk->getName(),
|
"Decode - " . $pk->getName(),
|
||||||
self::getReceiveDataPacketTimings($pk),
|
self::getReceiveDataPacketTimings($pk)
|
||||||
group: self::GROUP_BREAKDOWN
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
||||||
return self::$packetHandleTimingMap[$pk::class] ??= new TimingsHandler(
|
return self::$packetHandleTimingMap[$pk::class] ??= new TimingsHandler(
|
||||||
"Handler - " . $pk->getName(),
|
"Handler - " . $pk->getName(),
|
||||||
self::getReceiveDataPacketTimings($pk),
|
self::getReceiveDataPacketTimings($pk)
|
||||||
group: self::GROUP_BREAKDOWN
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
||||||
return self::$packetEncodeTimingMap[$pk::class] ??= new TimingsHandler(
|
return self::$packetEncodeTimingMap[$pk::class] ??= new TimingsHandler(
|
||||||
"Encode - " . $pk->getName(),
|
"Encode - " . $pk->getName(),
|
||||||
self::getSendDataPacketTimings($pk),
|
self::getSendDataPacketTimings($pk)
|
||||||
group: self::GROUP_BREAKDOWN
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
||||||
self::init();
|
self::init();
|
||||||
if(!isset(self::$packetSendTimingMap[$pk::class])){
|
if(!isset(self::$packetSendTimingMap[$pk::class])){
|
||||||
self::$packetSendTimingMap[$pk::class] = new TimingsHandler("Send - " . $pk->getName(), self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
self::$packetSendTimingMap[$pk::class] = new TimingsHandler("Send - " . $pk->getName(), self::$playerNetworkSend);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$packetSendTimingMap[$pk::class];
|
return self::$packetSendTimingMap[$pk::class];
|
||||||
@ -292,7 +289,7 @@ abstract class Timings{
|
|||||||
public static function getCommandDispatchTimings(string $commandName) : TimingsHandler{
|
public static function getCommandDispatchTimings(string $commandName) : TimingsHandler{
|
||||||
self::init();
|
self::init();
|
||||||
|
|
||||||
return self::$commandTimingMap[$commandName] ??= new TimingsHandler("Command - " . $commandName, group: self::GROUP_BREAKDOWN);
|
return self::$commandTimingMap[$commandName] ??= new TimingsHandler("Command - " . $commandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getEventTimings(Event $event) : TimingsHandler{
|
public static function getEventTimings(Event $event) : TimingsHandler{
|
||||||
@ -316,7 +313,7 @@ abstract class Timings{
|
|||||||
return self::$eventHandlers[$event][$handlerName];
|
return self::$eventHandlers[$event][$handlerName];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAsyncTaskProgressUpdateTimings(AsyncTask $task, string $group = self::GROUP_BREAKDOWN) : TimingsHandler{
|
public static function getAsyncTaskProgressUpdateTimings(AsyncTask $task, string $group = self::GROUP_MINECRAFT) : TimingsHandler{
|
||||||
$taskClass = $task::class;
|
$taskClass = $task::class;
|
||||||
if(!isset(self::$asyncTaskProgressUpdate[$taskClass])){
|
if(!isset(self::$asyncTaskProgressUpdate[$taskClass])){
|
||||||
self::init();
|
self::init();
|
||||||
@ -330,7 +327,7 @@ abstract class Timings{
|
|||||||
return self::$asyncTaskProgressUpdate[$taskClass];
|
return self::$asyncTaskProgressUpdate[$taskClass];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAsyncTaskCompletionTimings(AsyncTask $task, string $group = self::GROUP_BREAKDOWN) : TimingsHandler{
|
public static function getAsyncTaskCompletionTimings(AsyncTask $task, string $group = self::GROUP_MINECRAFT) : TimingsHandler{
|
||||||
$taskClass = $task::class;
|
$taskClass = $task::class;
|
||||||
if(!isset(self::$asyncTaskCompletion[$taskClass])){
|
if(!isset(self::$asyncTaskCompletion[$taskClass])){
|
||||||
self::init();
|
self::init();
|
||||||
@ -344,7 +341,7 @@ abstract class Timings{
|
|||||||
return self::$asyncTaskCompletion[$taskClass];
|
return self::$asyncTaskCompletion[$taskClass];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAsyncTaskErrorTimings(AsyncTask $task, string $group = self::GROUP_BREAKDOWN) : TimingsHandler{
|
public static function getAsyncTaskErrorTimings(AsyncTask $task, string $group = self::GROUP_MINECRAFT) : TimingsHandler{
|
||||||
$taskClass = $task::class;
|
$taskClass = $task::class;
|
||||||
if(!isset(self::$asyncTaskError[$taskClass])){
|
if(!isset(self::$asyncTaskError[$taskClass])){
|
||||||
self::init();
|
self::init();
|
||||||
|
@ -120,7 +120,7 @@ class TimingsHandler{
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private string $name,
|
private string $name,
|
||||||
private ?TimingsHandler $parent = null,
|
private ?TimingsHandler $parent = null,
|
||||||
private string $group = "Minecraft"
|
private string $group = Timings::GROUP_MINECRAFT
|
||||||
){}
|
){}
|
||||||
|
|
||||||
public function getName() : string{ return $this->name; }
|
public function getName() : string{ return $this->name; }
|
||||||
|
@ -1670,16 +1670,19 @@ class World implements ChunkManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the highest available level of any type of light at the given coordinates, adjusted for the current
|
* Returns the highest level of any type of light at the given coordinates, adjusted for the current weather and
|
||||||
* weather and time of day.
|
* time of day.
|
||||||
*/
|
*/
|
||||||
public function getFullLight(Vector3 $pos) : int{
|
public function getFullLight(Vector3 $pos) : int{
|
||||||
return $this->getFullLightAt($pos->x, $pos->y, $pos->z);
|
$floorX = $pos->getFloorX();
|
||||||
|
$floorY = $pos->getFloorY();
|
||||||
|
$floorZ = $pos->getFloorZ();
|
||||||
|
return $this->getFullLightAt($floorX, $floorY, $floorZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the highest available level of any type of light at the given coordinates, adjusted for the current
|
* Returns the highest level of any type of light at the given coordinates, adjusted for the current weather and
|
||||||
* weather and time of day.
|
* time of day.
|
||||||
*/
|
*/
|
||||||
public function getFullLightAt(int $x, int $y, int $z) : int{
|
public function getFullLightAt(int $x, int $y, int $z) : int{
|
||||||
$skyLight = $this->getRealBlockSkyLightAt($x, $y, $z);
|
$skyLight = $this->getRealBlockSkyLightAt($x, $y, $z);
|
||||||
@ -1691,18 +1694,43 @@ class World implements ChunkManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the highest available level of any type of light at, or adjacent to, the given coordinates, adjusted for
|
* Returns the highest level of any type of light at, or adjacent to, the given coordinates, adjusted for the
|
||||||
* the current weather and time of day.
|
* current weather and time of day.
|
||||||
*/
|
*/
|
||||||
public function getHighestAdjacentFullLightAt(int $x, int $y, int $z) : int{
|
public function getHighestAdjacentFullLightAt(int $x, int $y, int $z) : int{
|
||||||
return $this->getHighestAdjacentLight($x, $y, $z, $this->getFullLightAt(...));
|
return $this->getHighestAdjacentLight($x, $y, $z, $this->getFullLightAt(...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the highest potential level of any type of light at the target coordinates.
|
||||||
|
* This is not affected by weather or time of day.
|
||||||
|
*/
|
||||||
|
public function getPotentialLight(Vector3 $pos) : int{
|
||||||
|
$floorX = $pos->getFloorX();
|
||||||
|
$floorY = $pos->getFloorY();
|
||||||
|
$floorZ = $pos->getFloorZ();
|
||||||
|
return $this->getPotentialLightAt($floorX, $floorY, $floorZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the highest potential level of any type of light at the target coordinates.
|
||||||
|
* This is not affected by weather or time of day.
|
||||||
|
*/
|
||||||
|
public function getPotentialLightAt(int $x, int $y, int $z) : int{
|
||||||
|
return max($this->getPotentialBlockSkyLightAt($x, $y, $z), $this->getBlockLightAt($x, $y, $z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the highest potential level of any type of light at, or adjacent to, the given coordinates.
|
||||||
|
* This is not affected by weather or time of day.
|
||||||
|
*/
|
||||||
|
public function getHighestAdjacentPotentialLightAt(int $x, int $y, int $z) : int{
|
||||||
|
return $this->getHighestAdjacentLight($x, $y, $z, $this->getPotentialLightAt(...));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the highest potential level of sky light at the target coordinates, regardless of the time of day or
|
* Returns the highest potential level of sky light at the target coordinates, regardless of the time of day or
|
||||||
* weather conditions.
|
* weather conditions.
|
||||||
* You usually don't want to use this for vanilla gameplay logic; prefer the real sky light instead.
|
|
||||||
* @see World::getRealBlockSkyLightAt()
|
|
||||||
*
|
*
|
||||||
* @return int 0-15
|
* @return int 0-15
|
||||||
*/
|
*/
|
||||||
@ -2599,7 +2627,7 @@ class World implements ChunkManager{
|
|||||||
|
|
||||||
public function isChunkPopulated(int $x, int $z) : bool{
|
public function isChunkPopulated(int $x, int $z) : bool{
|
||||||
$chunk = $this->loadChunk($x, $z);
|
$chunk = $this->loadChunk($x, $z);
|
||||||
return $chunk !== null ? $chunk->isPopulated() : false;
|
return $chunk !== null && $chunk->isPopulated();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\world;
|
namespace pocketmine\world;
|
||||||
|
|
||||||
use pocketmine\timings\Timings;
|
|
||||||
use pocketmine\timings\TimingsHandler;
|
use pocketmine\timings\TimingsHandler;
|
||||||
|
|
||||||
class WorldTimings{
|
class WorldTimings{
|
||||||
@ -66,7 +65,7 @@ class WorldTimings{
|
|||||||
private static function newTimer(string $worldName, string $timerName) : TimingsHandler{
|
private static function newTimer(string $worldName, string $timerName) : TimingsHandler{
|
||||||
$aggregator = self::$aggregators[$timerName] ??= new TimingsHandler("Worlds - $timerName"); //displayed in Minecraft primary table
|
$aggregator = self::$aggregators[$timerName] ??= new TimingsHandler("Worlds - $timerName"); //displayed in Minecraft primary table
|
||||||
|
|
||||||
return new TimingsHandler("$worldName - $timerName", $aggregator, Timings::GROUP_BREAKDOWN);
|
return new TimingsHandler("$worldName - $timerName", $aggregator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct(World $world){
|
public function __construct(World $world){
|
||||||
|
@ -425,6 +425,21 @@ parameters:
|
|||||||
count: 3
|
count: 3
|
||||||
path: ../../../src/block/tile/Spawnable.php
|
path: ../../../src/block/tile/Spawnable.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getPotentialLightAt\\(\\) expects int, float\\|int given\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/block/utils/CropGrowthHelper.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getPotentialLightAt\\(\\) expects int, float\\|int given\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/block/utils/CropGrowthHelper.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getPotentialLightAt\\(\\) expects int, float\\|int given\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/block/utils/CropGrowthHelper.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\world\\\\World\\|null\\.$#"
|
message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\world\\\\World\\|null\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@ -910,11 +925,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/world/World.php
|
path: ../../../src/world/World.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/world/World.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#"
|
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@ -940,11 +950,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/world/World.php
|
path: ../../../src/world/World.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/world/World.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#"
|
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@ -970,11 +975,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/world/World.php
|
path: ../../../src/world/World.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/world/World.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#"
|
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user