mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-05 19:37:17 +00:00
Merge branch 'next-minor' into stable
This commit is contained in:
commit
f495ba1d0b
@ -1,7 +1,6 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.2
|
||||
- 7.3
|
||||
|
||||
before_script:
|
||||
|
@ -2,7 +2,7 @@
|
||||
## Pre-requisites
|
||||
- A bash shell (git bash is sufficient for Windows)
|
||||
- [`git`](https://git-scm.com) available in your shell
|
||||
- PHP 7.2 or newer available in your shell
|
||||
- PHP 7.3 or newer available in your shell
|
||||
- [`composer`](https://getcomposer.org) available in your shell
|
||||
|
||||
## Custom PHP binaries
|
||||
|
111
changelogs/3.13.md
Normal file
111
changelogs/3.13.md
Normal file
@ -0,0 +1,111 @@
|
||||
**For Minecraft: Bedrock Edition 1.14.60**
|
||||
|
||||
This is a feature release, containing various minor API additions, deprecations and a few minor features.
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 3.13.0
|
||||
## Core
|
||||
- PHP 7.3.0 or newer is now required.
|
||||
- Player movement processing has been revamped. It's now more tolerant of network lag and doesn't have as many problems with falling.
|
||||
|
||||
## User Interface
|
||||
- `/time` now supports additional aliases `noon`, `sunset`, `midnight` and `sunrise`.
|
||||
- Removed warnings when a plugin registers a handler for a deprecated event. Since this warning is developer-focused, and too specific to be useful, it just caused annoyance and confusion to users who didn't know what it meant.
|
||||
|
||||
## API
|
||||
### General
|
||||
- It's now possible to require a specific operating system using the `os` directive in `plugin.yml`. More information about this directive can be found in the [developer documentation](https://github.com/pmmp/DeveloperDocs).
|
||||
|
||||
### Player
|
||||
- `Player->resetItemCooldown()` now accepts a second parameter, allowing plugins to provide a custom duration.
|
||||
- The following methods have been deprecated and have recommended replacements:
|
||||
- `Player->addTitle()` -> `Player->sendTitle()`
|
||||
- `Player->addSubTitle()` -> `Player->sendSubTitle()`
|
||||
- `Player->addActionBarMessage()` -> `Player->sendActionBarMessage()`
|
||||
|
||||
### Event
|
||||
- The following methods have been deprecated:
|
||||
- `EntityDespawnEvent->getType()`
|
||||
- `EntityDespawnEvent->getPosition()`
|
||||
- `EntityDespawnEvent->isCreature()`
|
||||
- `EntityDespawnEvent->isHuman()`
|
||||
- `EntityDespawnEvent->isProjectile()`
|
||||
- `EntityDespawnEvent->isVehicle()`
|
||||
- `EntityDespawnEvent->isItem()`
|
||||
- `EntitySpawnEvent->getType()`
|
||||
- `EntitySpawnEvent->getPosition()`
|
||||
- `EntitySpawnEvent->isCreature()`
|
||||
- `EntitySpawnEvent->isHuman()`
|
||||
- `EntitySpawnEvent->isProjectile()`
|
||||
- `EntitySpawnEvent->isVehicle()`
|
||||
- `EntitySpawnEvent->isItem()`
|
||||
- Added the following API methods:
|
||||
- `EntityDeathEvent->getXpDropAmount()`
|
||||
- `EntityDeathEvent->setXpDropAmount()`
|
||||
- `PlayerDeathEvent::__construct()` now accepts a fourth (optional) parameter `int $xp`.
|
||||
- `EntityDeathEvent::__construct()` now accepts a third (optional) parameter `int $xp`.
|
||||
|
||||
### Inventory
|
||||
- The following classes have been deprecated:
|
||||
- `Recipe`
|
||||
- The following methods have been deprecated:
|
||||
- `CraftingManager->registerRecipe()`
|
||||
- `Recipe->registerToCraftingManager()` (and all its implementations)
|
||||
|
||||
### Item
|
||||
- New `Enchantment` type ID constants have been added.
|
||||
- `ItemFactory::fromStringSingle()` has been added. This works exactly the same as `ItemFactory::fromString()`, but it has a return type of `Item` instead of `Item|Item[]` (more static analysis friendly).
|
||||
|
||||
### Level
|
||||
- Added the following API methods:
|
||||
- `Position->getLevelNonNull()`: this is the same as `Position->getLevel()`, but throws an `AssumptionFailedError` if the level is null or invalid (more static analysis friendly).
|
||||
- `Level->getTimeOfDay()`
|
||||
- The following constants have been changed:
|
||||
- `Level::TIME_DAY` now has a value of `1000`
|
||||
- `Level::TIME_NIGHT` now has a value of `13000`
|
||||
- Added the following constants:
|
||||
- `Level::TIME_MIDNIGHT`
|
||||
- `Level::TIME_NOON`
|
||||
- The following types of particles now accept optional `Color` parameters in the constructor:
|
||||
- `EnchantParticle`
|
||||
- `InstantEnchantParticle`
|
||||
|
||||
### Network
|
||||
- Added the following API methods:
|
||||
- `RakLibInterface->setPacketLimit()`
|
||||
|
||||
### Scheduler
|
||||
AsyncTask thread-local storage has been improved, making it simpler and easier to use.
|
||||
- `AsyncTask->fetchLocal()` no longer deletes stored thread-local data. Instead, the storage behaves more like properties, and gets deleted when the AsyncTask object goes out of scope.
|
||||
- `AsyncTask->peekLocal()` has been `@deprecated` (use `fetchLocal()` instead).
|
||||
- Notices are no longer emitted if an async task doesn't fetch its locally stored data.
|
||||
- The following methods have been deprecated:
|
||||
- `AsyncTask->getFromThreadStore()` (use its worker's corresponding method)
|
||||
- `AsyncTask->saveToThreadStore()` (use its worker's corresponding method)
|
||||
- `AsyncTask->removeFromThreadStore()` (use its worker's corresponding method)
|
||||
|
||||
### Utils
|
||||
- The following functions have been deprecated and have recommended replacements:
|
||||
- `Utils::getMemoryUsage()` -> split into `Process::getMemoryUsage()` and `Process::getAdvancedMemoryUsage()` (not 1:1 replacement!!)
|
||||
- `Utils::getRealMemoryUsage()` -> `Process::getRealMemoryUsage()`
|
||||
- `Utils::getThreadCount()` -> `Process::getThreadCount()`
|
||||
- `Utils::kill()` -> `Process::kill()`
|
||||
- `Utils::execute()` -> `Process::execute()`
|
||||
- Added the following constants:
|
||||
- `Utils::OS_WINDOWS`
|
||||
- `Utils::OS_IOS`
|
||||
- `Utils::OS_MACOS`
|
||||
- `Utils::OS_ANDROID`
|
||||
- `Utils::OS_LINUX`
|
||||
- `Utils::OS_BSD`
|
||||
- `Utils::OS_UNKNOWN`
|
||||
- Added the following API methods:
|
||||
- `Config->getPath()`
|
||||
- `Utils::recursiveUnlink()`
|
||||
- `Terminal::write()`
|
||||
- `Terminal::writeLine()`
|
@ -5,7 +5,7 @@
|
||||
"homepage": "https://pmmp.io",
|
||||
"license": "LGPL-3.0",
|
||||
"require": {
|
||||
"php": ">=7.2.0",
|
||||
"php": ">=7.3.0",
|
||||
"php-64bit": "*",
|
||||
"ext-bcmath": "*",
|
||||
"ext-curl": "*",
|
||||
@ -34,7 +34,8 @@
|
||||
"pocketmine/log": "^0.2.0",
|
||||
"pocketmine/log-pthreads": "^0.1.0",
|
||||
"pocketmine/callback-validator": "^1.0.1",
|
||||
"adhocore/json-comment": "^0.1.0"
|
||||
"adhocore/json-comment": "^0.1.0",
|
||||
"ocramius/package-versions": "^1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^0.12.25",
|
||||
|
55
composer.lock
generated
55
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "59c415a2cb668990b4a456b4bd106881",
|
||||
"content-hash": "270aa35b0c4f554754b656129c5e8343",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -50,6 +50,57 @@
|
||||
],
|
||||
"time": "2020-01-03T13:51:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ocramius/package-versions",
|
||||
"version": "1.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Ocramius/PackageVersions.git",
|
||||
"reference": "1d32342b8c1eb27353c8887c366147b4c2da673c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c",
|
||||
"reference": "1d32342b8c1eb27353c8887c366147b4c2da673c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.0.0",
|
||||
"php": "^7.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "^1.8.6",
|
||||
"doctrine/coding-standard": "^6.0.0",
|
||||
"ext-zip": "*",
|
||||
"infection/infection": "^0.13.4",
|
||||
"phpunit/phpunit": "^8.2.5",
|
||||
"vimeo/psalm": "^3.4.9"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "PackageVersions\\Installer",
|
||||
"branch-alias": {
|
||||
"dev-master": "1.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PackageVersions\\": "src/PackageVersions"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
|
||||
"time": "2019-07-17T15:49:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
"version": "0.1.11",
|
||||
@ -2091,7 +2142,7 @@
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=7.2.0",
|
||||
"php": ">=7.3.0",
|
||||
"php-64bit": "*",
|
||||
"ext-bcmath": "*",
|
||||
"ext-curl": "*",
|
||||
|
@ -23,13 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use PackageVersions\Versions;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\plugin\PluginBase;
|
||||
use pocketmine\plugin\PluginLoadOrder;
|
||||
use pocketmine\plugin\PluginManager;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
use raklib\RakLib;
|
||||
use function base64_encode;
|
||||
use function date;
|
||||
use function error_get_last;
|
||||
@ -88,7 +88,7 @@ class CrashDump{
|
||||
* having their content changed, version format changing, etc.
|
||||
* It is not necessary to increase this when adding new fields.
|
||||
*/
|
||||
private const FORMAT_VERSION = 2;
|
||||
private const FORMAT_VERSION = 3;
|
||||
|
||||
private const PLUGIN_INVOLVEMENT_NONE = "none";
|
||||
private const PLUGIN_INVOLVEMENT_DIRECT = "direct";
|
||||
@ -117,10 +117,11 @@ class CrashDump{
|
||||
mkdir($this->server->getDataPath() . "crashdumps");
|
||||
}
|
||||
$this->path = $this->server->getDataPath() . "crashdumps/" . date("D_M_j-H.i.s-T_Y", $this->time) . ".log";
|
||||
$this->fp = @fopen($this->path, "wb");
|
||||
if(!is_resource($this->fp)){
|
||||
$fp = @fopen($this->path, "wb");
|
||||
if(!is_resource($fp)){
|
||||
throw new \RuntimeException("Could not create Crash Dump");
|
||||
}
|
||||
$this->fp = $fp;
|
||||
$this->data["format_version"] = self::FORMAT_VERSION;
|
||||
$this->data["time"] = $this->time;
|
||||
$this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", $this->time));
|
||||
@ -228,7 +229,10 @@ class CrashDump{
|
||||
if(isset($lastExceptionError)){
|
||||
$error = $lastExceptionError;
|
||||
}else{
|
||||
$error = (array) error_get_last();
|
||||
$error = error_get_last();
|
||||
if($error === null){
|
||||
throw new \RuntimeException("Crash error information missing - did something use exit()?");
|
||||
}
|
||||
$error["trace"] = Utils::currentTrace(3); //Skipping CrashDump->baseCrash, CrashDump->construct, Server->crashDump
|
||||
$errorConversion = [
|
||||
E_ERROR => "E_ERROR",
|
||||
@ -288,9 +292,11 @@ class CrashDump{
|
||||
|
||||
if($this->server->getProperty("auto-report.send-code", true) !== false and file_exists($error["fullFile"])){
|
||||
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
|
||||
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){
|
||||
$this->addLine("[" . ($l + 1) . "] " . $file[$l]);
|
||||
$this->data["code"][$l + 1] = $file[$l];
|
||||
if($file !== false){
|
||||
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){
|
||||
$this->addLine("[" . ($l + 1) . "] " . $file[$l]);
|
||||
$this->data["code"][$l + 1] = $file[$l];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,18 +345,22 @@ class CrashDump{
|
||||
$this->data["general"]["is_dev"] = \pocketmine\IS_DEVELOPMENT_BUILD;
|
||||
$this->data["general"]["protocol"] = ProtocolInfo::CURRENT_PROTOCOL;
|
||||
$this->data["general"]["git"] = \pocketmine\GIT_COMMIT;
|
||||
$this->data["general"]["raklib"] = RakLib::VERSION;
|
||||
$this->data["general"]["uname"] = php_uname("a");
|
||||
$this->data["general"]["php"] = phpversion();
|
||||
$this->data["general"]["zend"] = zend_version();
|
||||
$this->data["general"]["php_os"] = PHP_OS;
|
||||
$this->data["general"]["os"] = Utils::getOS();
|
||||
$this->data["general"]["composer_libraries"] = Versions::VERSIONS;
|
||||
$this->addLine($this->server->getName() . " version: " . $version->getFullVersion(true) . " [Protocol " . ProtocolInfo::CURRENT_PROTOCOL . "]");
|
||||
$this->addLine("Git commit: " . \pocketmine\GIT_COMMIT);
|
||||
$this->addLine("uname -a: " . php_uname("a"));
|
||||
$this->addLine("PHP Version: " . phpversion());
|
||||
$this->addLine("Zend version: " . zend_version());
|
||||
$this->addLine("OS : " . PHP_OS . ", " . Utils::getOS());
|
||||
$this->addLine("Composer libraries: ");
|
||||
foreach(Versions::VERSIONS as $library => $libraryVersion){
|
||||
$this->addLine("- $library $libraryVersion");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,6 +27,8 @@ use pocketmine\event\server\LowMemoryEvent;
|
||||
use pocketmine\scheduler\DumpWorkerMemoryTask;
|
||||
use pocketmine\scheduler\GarbageCollectionTask;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\Utils;
|
||||
use function arsort;
|
||||
use function count;
|
||||
@ -225,7 +227,7 @@ class MemoryManager{
|
||||
|
||||
if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){
|
||||
$this->checkTicker = 0;
|
||||
$memory = Utils::getMemoryUsage(true);
|
||||
$memory = Process::getAdvancedMemoryUsage();
|
||||
$trigger = false;
|
||||
if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){
|
||||
$trigger = 0;
|
||||
@ -304,6 +306,7 @@ class MemoryManager{
|
||||
*/
|
||||
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger){
|
||||
$hardLimit = ini_get('memory_limit');
|
||||
if($hardLimit === false) throw new AssumptionFailedError("memory_limit INI directive should always exist");
|
||||
ini_set('memory_limit', '-1');
|
||||
gc_disable();
|
||||
|
||||
@ -403,8 +406,8 @@ class MemoryManager{
|
||||
"properties" => []
|
||||
];
|
||||
|
||||
if($reflection->getParentClass()){
|
||||
$info["parent"] = $reflection->getParentClass()->getName();
|
||||
if(($parent = $reflection->getParentClass()) !== false){
|
||||
$info["parent"] = $parent->getName();
|
||||
}
|
||||
|
||||
if(count($reflection->getInterfaceNames()) > 0){
|
||||
|
@ -217,6 +217,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
public const SPECTATOR = 3;
|
||||
public const VIEW = Player::SPECTATOR;
|
||||
|
||||
private const MOVES_PER_TICK = 2;
|
||||
private const MOVE_BACKLOG_SIZE = 100 * self::MOVES_PER_TICK; //100 ticks backlog (5 seconds)
|
||||
|
||||
private const RESOURCE_PACK_CHUNK_SIZE = 128 * 1024; //128KB
|
||||
|
||||
/**
|
||||
@ -331,10 +334,13 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
/** @var bool[] map: raw UUID (string) => bool */
|
||||
protected $hiddenPlayers = [];
|
||||
|
||||
/** @var float */
|
||||
protected $moveRateLimit = 10 * self::MOVES_PER_TICK;
|
||||
/** @var float|null */
|
||||
protected $lastMovementProcess = null;
|
||||
/** @var Vector3|null */
|
||||
protected $newPosition;
|
||||
/** @var bool */
|
||||
protected $isTeleporting = false;
|
||||
protected $forceMoveSync = null;
|
||||
|
||||
/** @var int */
|
||||
protected $inAirTicks = 0;
|
||||
/** @var float */
|
||||
@ -524,7 +530,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
public function spawnTo(Player $player) : void{
|
||||
if($this->spawned and $player->spawned and $this->isAlive() and $player->isAlive() and $player->getLevel() === $this->level and $player->canSee($this) and !$this->isSpectator()){
|
||||
if($this->spawned and $player->spawned and $this->isAlive() and $player->isAlive() and $player->getLevelNonNull() === $this->level and $player->canSee($this) and !$this->isSpectator()){
|
||||
parent::spawnTo($player);
|
||||
}
|
||||
}
|
||||
@ -867,8 +873,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$this->lastPingMeasure = $pingMS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function getNextPosition() : Position{
|
||||
return $this->newPosition !== null ? Position::fromObject($this->newPosition, $this->level) : $this->getPosition();
|
||||
return $this->getPosition();
|
||||
}
|
||||
|
||||
public function getInAirTicks() : int{
|
||||
@ -909,8 +918,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
/**
|
||||
* Resets the player's cooldown time for the given item back to the maximum.
|
||||
*/
|
||||
public function resetItemCooldown(Item $item) : void{
|
||||
$ticks = $item->getCooldownTicks();
|
||||
public function resetItemCooldown(Item $item, ?int $ticks = null) : void{
|
||||
$ticks = $ticks ?? $item->getCooldownTicks();
|
||||
if($ticks > 0){
|
||||
$this->usedItemsCooldown[$item->getId()] = $this->server->getTick() + $ticks;
|
||||
}
|
||||
@ -1214,7 +1223,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
if(!($pos instanceof Position)){
|
||||
$level = $this->level;
|
||||
}else{
|
||||
$level = $pos->getLevel();
|
||||
$level = $pos->getLevelNonNull();
|
||||
}
|
||||
$this->spawnPosition = new Position($pos->x, $pos->y, $pos->z, $level);
|
||||
$pk = new SetSpawnPositionPacket();
|
||||
@ -1530,23 +1539,19 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function processMovement(int $tickDiff){
|
||||
if(!$this->isAlive() or !$this->spawned or $this->newPosition === null or $this->isSleeping()){
|
||||
protected function handleMovement(Vector3 $newPos) : void{
|
||||
$this->moveRateLimit--;
|
||||
if($this->moveRateLimit < 0){
|
||||
return;
|
||||
}
|
||||
|
||||
assert($this->x !== null and $this->y !== null and $this->z !== null);
|
||||
assert($this->newPosition->x !== null and $this->newPosition->y !== null and $this->newPosition->z !== null);
|
||||
|
||||
$newPos = $this->newPosition;
|
||||
$distanceSquared = $newPos->distanceSquared($this);
|
||||
$oldPos = $this->asLocation();
|
||||
$distanceSquared = $newPos->distanceSquared($oldPos);
|
||||
|
||||
$revert = false;
|
||||
|
||||
if(($distanceSquared / ($tickDiff ** 2)) > 100){
|
||||
if($distanceSquared > 100){
|
||||
//TODO: this is probably too big if we process every movement
|
||||
/* !!! BEWARE YE WHO ENTER HERE !!!
|
||||
*
|
||||
* This is NOT an anti-cheat check. It is a safety check.
|
||||
@ -1558,7 +1563,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
* asking for help if you suffer the consequences of messing with this.
|
||||
*/
|
||||
$this->server->getLogger()->debug($this->getName() . " moved too fast, reverting movement");
|
||||
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition);
|
||||
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $newPos);
|
||||
$revert = true;
|
||||
}elseif(!$this->level->isInLoadedTerrain($newPos) or !$this->level->isChunkGenerated($newPos->getFloorX() >> 4, $newPos->getFloorZ() >> 4)){
|
||||
$revert = true;
|
||||
@ -1572,7 +1577,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$this->move($dx, $dy, $dz);
|
||||
|
||||
$diff = $this->distanceSquared($newPos) / $tickDiff ** 2;
|
||||
$diff = $this->distanceSquared($newPos);
|
||||
|
||||
if($this->isSurvival() and $diff > 0.0625){
|
||||
$ev = new PlayerIllegalMoveEvent($this, $newPos, new Vector3($this->lastX, $this->lastY, $this->lastZ));
|
||||
@ -1583,7 +1588,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
if(!$ev->isCancelled()){
|
||||
$revert = true;
|
||||
$this->server->getLogger()->debug($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidMove", [$this->getName()]));
|
||||
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition);
|
||||
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $newPos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1592,13 +1597,28 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
if($revert){
|
||||
$this->revertMovement($oldPos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires movement events and synchronizes player movement, every tick.
|
||||
*/
|
||||
protected function processMostRecentMovements() : void{
|
||||
$now = microtime(true);
|
||||
$multiplier = $this->lastMovementProcess !== null ? ($now - $this->lastMovementProcess) * 20 : 1;
|
||||
$exceededRateLimit = $this->moveRateLimit < 0;
|
||||
$this->moveRateLimit = min(self::MOVE_BACKLOG_SIZE, max(0, $this->moveRateLimit) + self::MOVES_PER_TICK * $multiplier);
|
||||
$this->lastMovementProcess = $now;
|
||||
|
||||
$from = new Location($this->lastX, $this->lastY, $this->lastZ, $this->lastYaw, $this->lastPitch, $this->level);
|
||||
$to = $this->getLocation();
|
||||
|
||||
$delta = (($this->lastX - $to->x) ** 2) + (($this->lastY - $to->y) ** 2) + (($this->lastZ - $to->z) ** 2);
|
||||
$deltaAngle = abs($this->lastYaw - $to->yaw) + abs($this->lastPitch - $to->pitch);
|
||||
|
||||
if(!$revert and ($delta > 0.0001 or $deltaAngle > 1.0)){
|
||||
if($delta > 0.0001 or $deltaAngle > 1.0){
|
||||
$this->lastX = $to->x;
|
||||
$this->lastY = $to->y;
|
||||
$this->lastZ = $to->z;
|
||||
@ -1610,41 +1630,47 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$ev->call();
|
||||
|
||||
if(!($revert = $ev->isCancelled())){ //Yes, this is intended
|
||||
if($to->distanceSquared($ev->getTo()) > 0.01){ //If plugins modify the destination
|
||||
$this->teleport($ev->getTo());
|
||||
}else{
|
||||
$this->broadcastMovement();
|
||||
|
||||
$distance = sqrt((($from->x - $to->x) ** 2) + (($from->z - $to->z) ** 2));
|
||||
//TODO: check swimming (adds 0.015 exhaustion in MCPE)
|
||||
if($this->isSprinting()){
|
||||
$this->exhaust(0.1 * $distance, PlayerExhaustEvent::CAUSE_SPRINTING);
|
||||
}else{
|
||||
$this->exhaust(0.01 * $distance, PlayerExhaustEvent::CAUSE_WALKING);
|
||||
}
|
||||
}
|
||||
if($ev->isCancelled()){
|
||||
$this->revertMovement($from);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if($revert){
|
||||
if($to->distanceSquared($ev->getTo()) > 0.01){ //If plugins modify the destination
|
||||
$this->teleport($ev->getTo());
|
||||
return;
|
||||
}
|
||||
|
||||
$this->lastX = $from->x;
|
||||
$this->lastY = $from->y;
|
||||
$this->lastZ = $from->z;
|
||||
$this->broadcastMovement();
|
||||
|
||||
$this->lastYaw = $from->yaw;
|
||||
$this->lastPitch = $from->pitch;
|
||||
$distance = sqrt((($from->x - $to->x) ** 2) + (($from->z - $to->z) ** 2));
|
||||
//TODO: check swimming (adds 0.015 exhaustion in MCPE)
|
||||
if($this->isSprinting()){
|
||||
$this->exhaust(0.1 * $distance, PlayerExhaustEvent::CAUSE_SPRINTING);
|
||||
}else{
|
||||
$this->exhaust(0.01 * $distance, PlayerExhaustEvent::CAUSE_WALKING);
|
||||
}
|
||||
|
||||
$this->setPosition($from);
|
||||
$this->sendPosition($from, $from->yaw, $from->pitch, MovePlayerPacket::MODE_RESET);
|
||||
}else{
|
||||
if($distanceSquared != 0 and $this->nextChunkOrderRun > 20){
|
||||
if($this->nextChunkOrderRun > 20){
|
||||
$this->nextChunkOrderRun = 20;
|
||||
}
|
||||
}
|
||||
|
||||
$this->newPosition = null;
|
||||
if($exceededRateLimit){ //client and server positions will be out of sync if this happens
|
||||
$this->server->getLogger()->debug("Player " . $this->getName() . " exceeded movement rate limit, forcing to last accepted position");
|
||||
$this->sendPosition($this, $this->yaw, $this->pitch, MovePlayerPacket::MODE_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
protected function revertMovement(Location $from) : void{
|
||||
$this->lastX = $from->x;
|
||||
$this->lastY = $from->y;
|
||||
$this->lastZ = $from->z;
|
||||
|
||||
$this->lastYaw = $from->yaw;
|
||||
$this->lastPitch = $from->pitch;
|
||||
|
||||
$this->setPosition($from);
|
||||
$this->sendPosition($from, $from->yaw, $from->pitch, MovePlayerPacket::MODE_RESET);
|
||||
}
|
||||
|
||||
public function fall(float $fallDistance) : void{
|
||||
@ -1716,7 +1742,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$this->timings->startTiming();
|
||||
|
||||
if($this->spawned){
|
||||
$this->processMovement($tickDiff);
|
||||
$this->processMostRecentMovements();
|
||||
$this->motion->x = $this->motion->y = $this->motion->z = 0; //TODO: HACK! (Fixes player knockback being messed up)
|
||||
if($this->onGround){
|
||||
$this->inAirTicks = 0;
|
||||
@ -1876,12 +1902,25 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$animations = [];
|
||||
foreach($packet->clientData["AnimatedImageData"] as $animation){
|
||||
$animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], base64_decode($animation["Image"], true)), $animation["Type"], $animation["Frames"]);
|
||||
$animations[] = new SkinAnimation(
|
||||
new SkinImage(
|
||||
$animation["ImageHeight"],
|
||||
$animation["ImageWidth"],
|
||||
base64_decode($animation["Image"], true)),
|
||||
$animation["Type"],
|
||||
$animation["Frames"]
|
||||
);
|
||||
}
|
||||
|
||||
$personaPieces = [];
|
||||
foreach($packet->clientData["PersonaPieces"] as $piece){
|
||||
$personaPieces[] = new PersonaSkinPiece($piece["PieceId"], $piece["PieceType"], $piece["PackId"], $piece["IsDefault"], $piece["ProductId"]);
|
||||
$personaPieces[] = new PersonaSkinPiece(
|
||||
$piece["PieceId"],
|
||||
$piece["PieceType"],
|
||||
$piece["PackId"],
|
||||
$piece["IsDefault"],
|
||||
$piece["ProductId"]
|
||||
);
|
||||
}
|
||||
|
||||
$pieceTintColors = [];
|
||||
@ -1892,9 +1931,17 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$skinData = new SkinData(
|
||||
$packet->clientData["SkinId"],
|
||||
base64_decode($packet->clientData["SkinResourcePatch"] ?? "", true),
|
||||
new SkinImage($packet->clientData["SkinImageHeight"], $packet->clientData["SkinImageWidth"], base64_decode($packet->clientData["SkinData"], true)),
|
||||
new SkinImage(
|
||||
$packet->clientData["SkinImageHeight"],
|
||||
$packet->clientData["SkinImageWidth"],
|
||||
base64_decode($packet->clientData["SkinData"], true)
|
||||
),
|
||||
$animations,
|
||||
new SkinImage($packet->clientData["CapeImageHeight"], $packet->clientData["CapeImageWidth"], base64_decode($packet->clientData["CapeData"] ?? "", true)),
|
||||
new SkinImage(
|
||||
$packet->clientData["CapeImageHeight"],
|
||||
$packet->clientData["CapeImageWidth"],
|
||||
base64_decode($packet->clientData["CapeData"] ?? "", true)
|
||||
),
|
||||
base64_decode($packet->clientData["SkinGeometryData"] ?? "", true),
|
||||
base64_decode($packet->clientData["SkinAnimationData"] ?? "", true),
|
||||
$packet->clientData["PremiumSkin"] ?? false,
|
||||
@ -2251,8 +2298,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
public function handleMovePlayer(MovePlayerPacket $packet) : bool{
|
||||
$newPos = $packet->position->round(4)->subtract(0, $this->baseOffset, 0);
|
||||
|
||||
if($this->isTeleporting and $newPos->distanceSquared($this) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
|
||||
$this->sendPosition($this, null, null, MovePlayerPacket::MODE_RESET);
|
||||
if($this->forceMoveSync !== null and $newPos->distanceSquared($this->forceMoveSync) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
|
||||
$this->server->getLogger()->debug("Got outdated pre-teleport movement from " . $this->getName() . ", received " . $newPos . ", expected " . $this->asVector3());
|
||||
//Still getting movements from before teleport, ignore them
|
||||
}elseif((!$this->isAlive() or !$this->spawned) and $newPos->distanceSquared($this) > 0.01){
|
||||
@ -2260,9 +2306,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$this->server->getLogger()->debug("Reverted movement of " . $this->getName() . " due to not alive or not spawned, received " . $newPos . ", locked at " . $this->asVector3());
|
||||
}else{
|
||||
// Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock
|
||||
if($this->isTeleporting){
|
||||
$this->isTeleporting = false;
|
||||
}
|
||||
$this->forceMoveSync = null;
|
||||
|
||||
$packet->yaw = fmod($packet->yaw, 360);
|
||||
$packet->pitch = fmod($packet->pitch, 360);
|
||||
@ -2272,7 +2316,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
$this->setRotation($packet->yaw, $packet->pitch);
|
||||
$this->newPosition = $newPos;
|
||||
$this->handleMovement($newPos);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2280,7 +2324,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
public function handleLevelSoundEvent(LevelSoundEventPacket $packet) : bool{
|
||||
//TODO: add events so plugins can change this
|
||||
$this->getLevel()->broadcastPacketToViewers($this, $packet);
|
||||
$this->getLevelNonNull()->broadcastPacketToViewers($this, $packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2737,7 +2781,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$item = $block->getPickedItem();
|
||||
if($packet->addUserData){
|
||||
$tile = $this->getLevel()->getTile($block);
|
||||
$tile = $this->getLevelNonNull()->getTile($block);
|
||||
if($tile instanceof Tile){
|
||||
$nbt = $tile->getCleanedNBT();
|
||||
if($nbt instanceof CompoundTag){
|
||||
@ -3269,7 +3313,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a title text to the user's screen, with an optional subtitle.
|
||||
* @deprecated
|
||||
* @see Player::sendTitle()
|
||||
*
|
||||
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
|
||||
* @param int $stay Duration in ticks to stay on screen for
|
||||
@ -3278,28 +3323,55 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
* @return void
|
||||
*/
|
||||
public function addTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1){
|
||||
$this->sendTitle($title, $subtitle, $fadeIn, $stay, $fadeOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a title text to the user's screen, with an optional subtitle.
|
||||
*
|
||||
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
|
||||
* @param int $stay Duration in ticks to stay on screen for
|
||||
* @param int $fadeOut Duration in ticks for fade-out.
|
||||
*/
|
||||
public function sendTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1) : void{
|
||||
$this->setTitleDuration($fadeIn, $stay, $fadeOut);
|
||||
if($subtitle !== ""){
|
||||
$this->addSubTitle($subtitle);
|
||||
$this->sendSubTitle($subtitle);
|
||||
}
|
||||
$this->sendTitleText($title, SetTitlePacket::TYPE_SET_TITLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subtitle message, without sending a title.
|
||||
* @deprecated
|
||||
* @see Player::sendSubTitle()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addSubTitle(string $subtitle){
|
||||
$this->sendSubTitle($subtitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subtitle message, without sending a title.
|
||||
*/
|
||||
public function sendSubTitle(string $subtitle) : void{
|
||||
$this->sendTitleText($subtitle, SetTitlePacket::TYPE_SET_SUBTITLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds small text to the user's screen.
|
||||
* @deprecated
|
||||
* @see Player::sendActionBarMessage()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addActionBarMessage(string $message){
|
||||
$this->sendActionBarMessage($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds small text to the user's screen.
|
||||
*/
|
||||
public function sendActionBarMessage(string $message) : void{
|
||||
$this->sendTitleText($message, SetTitlePacket::TYPE_SET_ACTIONBAR_MESSAGE);
|
||||
}
|
||||
|
||||
@ -3598,7 +3670,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
if($this->hasValidSpawnPosition()){
|
||||
$this->namedtag->setString("SpawnLevel", $this->spawnPosition->getLevel()->getFolderName());
|
||||
$this->namedtag->setString("SpawnLevel", $this->spawnPosition->getLevelNonNull()->getFolderName());
|
||||
$this->namedtag->setInt("SpawnX", $this->spawnPosition->getFloorX());
|
||||
$this->namedtag->setInt("SpawnY", $this->spawnPosition->getFloorY());
|
||||
$this->namedtag->setInt("SpawnZ", $this->spawnPosition->getFloorZ());
|
||||
@ -3642,7 +3714,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
//main inventory and drops the rest on the ground.
|
||||
$this->doCloseInventory();
|
||||
|
||||
$ev = new PlayerDeathEvent($this, $this->getDrops());
|
||||
$ev = new PlayerDeathEvent($this, $this->getDrops(), null, $this->getXpDropAmount());
|
||||
$ev->call();
|
||||
|
||||
if(!$ev->getKeepInventory()){
|
||||
@ -3659,8 +3731,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: allow this number to be manipulated during PlayerDeathEvent
|
||||
$this->level->dropExperience($this, $this->getXpDropAmount());
|
||||
$this->level->dropExperience($this, $ev->getXpDropAmount());
|
||||
$this->setXpAndProgress(0, 0);
|
||||
|
||||
if($ev->getDeathMessage() != ""){
|
||||
@ -3682,7 +3753,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$ev = new PlayerRespawnEvent($this, $this->getSpawn());
|
||||
$ev->call();
|
||||
|
||||
$realSpawn = Position::fromObject($ev->getRespawnPosition()->add(0.5, 0, 0.5), $ev->getRespawnPosition()->getLevel());
|
||||
$realSpawn = Position::fromObject($ev->getRespawnPosition()->add(0.5, 0, 0.5), $ev->getRespawnPosition()->getLevelNonNull());
|
||||
$this->teleport($realSpawn);
|
||||
|
||||
$this->setSprinting(false);
|
||||
@ -3766,12 +3837,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$pk->onGround = $this->onGround;
|
||||
|
||||
if($targets !== null){
|
||||
if(in_array($this, $targets, true)){
|
||||
$this->forceMoveSync = $pos->asVector3();
|
||||
}
|
||||
$this->server->broadcastPacket($targets, $pk);
|
||||
}else{
|
||||
$this->forceMoveSync = $pos->asVector3();
|
||||
$this->dataPacket($pk);
|
||||
}
|
||||
|
||||
$this->newPosition = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3789,11 +3862,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$this->resetFallDistance();
|
||||
$this->nextChunkOrderRun = 0;
|
||||
$this->newPosition = null;
|
||||
$this->stopSleep();
|
||||
|
||||
$this->isTeleporting = true;
|
||||
|
||||
//TODO: workaround for player last pos not getting updated
|
||||
//Entity::updateMovement() normally handles this, but it's overridden with an empty function in Player
|
||||
$this->resetLastMovements();
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine {
|
||||
|
||||
use pocketmine\utils\Git;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\ServerKiller;
|
||||
use pocketmine\utils\Terminal;
|
||||
use pocketmine\utils\Timezone;
|
||||
@ -34,7 +35,7 @@ namespace pocketmine {
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
const MIN_PHP_VERSION = "7.2.0";
|
||||
const MIN_PHP_VERSION = "7.3.0";
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
@ -279,7 +280,7 @@ namespace pocketmine {
|
||||
|
||||
if(ThreadManager::getInstance()->stopAll() > 0){
|
||||
$logger->debug("Some threads could not be stopped, performing a force-kill");
|
||||
Utils::kill(getmypid());
|
||||
Process::kill(getmypid());
|
||||
}
|
||||
}while(false);
|
||||
|
||||
|
@ -102,6 +102,7 @@ use pocketmine\updater\AutoUpdater;
|
||||
use pocketmine\utils\Config;
|
||||
use pocketmine\utils\Internet;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\Terminal;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
@ -1665,7 +1666,7 @@ class Server{
|
||||
}
|
||||
|
||||
foreach($recipients as $recipient){
|
||||
$recipient->addTitle($title, $subtitle, $fadeIn, $stay, $fadeOut);
|
||||
$recipient->sendTitle($title, $subtitle, $fadeIn, $stay, $fadeOut);
|
||||
}
|
||||
|
||||
return count($recipients);
|
||||
@ -1935,7 +1936,7 @@ class Server{
|
||||
}catch(\Throwable $e){
|
||||
$this->logger->logException($e);
|
||||
$this->logger->emergency("Crashed while crashing, killing process");
|
||||
@Utils::kill(getmypid());
|
||||
@Process::kill(getmypid());
|
||||
}
|
||||
|
||||
}
|
||||
@ -2128,7 +2129,7 @@ class Server{
|
||||
echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL;
|
||||
sleep($spacing);
|
||||
}
|
||||
@Utils::kill(getmypid());
|
||||
@Process::kill(getmypid());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -2329,10 +2330,10 @@ class Server{
|
||||
|
||||
private function titleTick() : void{
|
||||
Timings::$titleTickTimer->startTiming();
|
||||
$d = Utils::getRealMemoryUsage();
|
||||
$d = Process::getRealMemoryUsage();
|
||||
|
||||
$u = Utils::getMemoryUsage(true);
|
||||
$usage = sprintf("%g/%g/%g/%g MB @ %d threads", round(($u[0] / 1024) / 1024, 2), round(($d[0] / 1024) / 1024, 2), round(($u[1] / 1024) / 1024, 2), round(($u[2] / 1024) / 1024, 2), Utils::getThreadCount());
|
||||
$u = Process::getAdvancedMemoryUsage();
|
||||
$usage = sprintf("%g/%g/%g/%g MB @ %d threads", round(($u[0] / 1024) / 1024, 2), round(($d[0] / 1024) / 1024, 2), round(($u[1] / 1024) / 1024, 2), round(($u[2] / 1024) / 1024, 2), Process::getThreadCount());
|
||||
|
||||
echo "\x1b]0;" . $this->getName() . " " .
|
||||
$this->getPocketMineVersion() .
|
||||
|
@ -110,6 +110,6 @@ class Anvil extends Fallable{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$direction = ($player !== null ? $player->getDirection() : 0) & 0x03;
|
||||
$this->meta = $this->getVariant() | $direction;
|
||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ abstract class BaseRail extends Flowable{
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
if(!$blockReplace->getSide(Vector3::SIDE_DOWN)->isTransparent() and $this->getLevel()->setBlock($blockReplace, $this, true, true)){
|
||||
if(!$blockReplace->getSide(Vector3::SIDE_DOWN)->isTransparent() and $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true)){
|
||||
$this->tryReconnect();
|
||||
return true;
|
||||
}
|
||||
@ -279,7 +279,7 @@ abstract class BaseRail extends Flowable{
|
||||
isset(self::ASCENDING_SIDES[$this->meta & 0x07]) and
|
||||
$this->getSide(self::ASCENDING_SIDES[$this->meta & 0x07])->isTransparent()
|
||||
)){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ class Bed extends Transparent{
|
||||
$this->meta &= ~self::BITFLAG_OCCUPIED;
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($this, $this, false, false);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, false, false);
|
||||
|
||||
if(($other = $this->getOtherHalf()) !== null and $other->isOccupied() !== $occupied){
|
||||
$other->setOccupied($occupied);
|
||||
@ -137,7 +137,7 @@ class Bed extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
$time = $this->getLevel()->getTime() % Level::TIME_FULL;
|
||||
$time = $this->getLevelNonNull()->getTimeOfDay();
|
||||
|
||||
$isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE);
|
||||
|
||||
@ -168,11 +168,11 @@ class Bed extends Transparent{
|
||||
$meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03;
|
||||
$next = $this->getSide(self::getOtherHalfSide($meta));
|
||||
if($next->canBeReplaced() and !$next->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
||||
$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
||||
$this->getLevelNonNull()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
||||
|
||||
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player));
|
||||
Tile::createTile(Tile::BED, $this->getLevelNonNull(), TileBed::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::BED, $this->getLevelNonNull(), TileBed::createNBT($next, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -194,7 +194,7 @@ class Bed extends Transparent{
|
||||
}
|
||||
|
||||
private function getItem() : Item{
|
||||
$tile = $this->getLevel()->getTile($this);
|
||||
$tile = $this->getLevelNonNull()->getTile($this);
|
||||
if($tile instanceof TileBed){
|
||||
return ItemFactory::get($this->getItemId(), $tile->getColor());
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
*/
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
return $this->getLevel()->setBlock($this, $this, true, true);
|
||||
return $this->getLevelNonNull()->setBlock($this, $this, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,7 +204,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
* Do the actions needed so the block is broken with the Item
|
||||
*/
|
||||
public function onBreak(Item $item, Player $player = null) : bool{
|
||||
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
return $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -479,7 +479,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
*/
|
||||
public function getSide(int $side, int $step = 1){
|
||||
if($this->isValid()){
|
||||
return $this->getLevel()->getBlock(Vector3::getSide($side, $step));
|
||||
return $this->getLevelNonNull()->getBlock(Vector3::getSide($side, $step));
|
||||
}
|
||||
|
||||
return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
|
||||
|
@ -55,7 +55,7 @@ class BoneBlock extends Solid{
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
|
@ -68,18 +68,18 @@ class BurningFurnace extends Solid{
|
||||
3 => 3
|
||||
];
|
||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::FURNACE, $this->getLevelNonNull(), TileFurnace::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$furnace = $this->getLevel()->getTile($this);
|
||||
$furnace = $this->getLevelNonNull()->getTile($this);
|
||||
if(!($furnace instanceof TileFurnace)){
|
||||
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
|
||||
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevelNonNull(), TileFurnace::createNBT($this));
|
||||
if(!($furnace instanceof TileFurnace)){
|
||||
return true;
|
||||
}
|
||||
|
@ -72,12 +72,12 @@ class Cactus extends Transparent{
|
||||
public function onNearbyBlockChange() : void{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() !== self::SAND and $down->getId() !== self::CACTUS){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}else{
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b->isSolid()){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -92,23 +92,23 @@ class Cactus extends Transparent{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
|
||||
if($this->meta === 0x0f){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
$b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
if($b->getId() === self::AIR){
|
||||
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS));
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
break;
|
||||
}
|
||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||
$this->getLevelNonNull()->setBlock($b, $ev->getNewState(), true);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->meta = 0;
|
||||
$this->getLevel()->setBlock($this, $this);
|
||||
$this->getLevelNonNull()->setBlock($this, $this);
|
||||
}else{
|
||||
++$this->meta;
|
||||
$this->getLevel()->setBlock($this, $this);
|
||||
$this->getLevelNonNull()->setBlock($this, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -121,7 +121,7 @@ class Cactus extends Transparent{
|
||||
$block2 = $this->getSide(Vector3::SIDE_WEST);
|
||||
$block3 = $this->getSide(Vector3::SIDE_EAST);
|
||||
if(!$block0->isSolid() and !$block1->isSolid() and !$block2->isSolid() and !$block3->isSolid()){
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ class Cake extends Transparent implements FoodSource{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() !== self::AIR){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -76,7 +76,7 @@ class Cake extends Transparent implements FoodSource{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ class Carpet extends Flowable{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() !== self::AIR){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -74,7 +74,7 @@ class Carpet extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ class Chest extends Transparent{
|
||||
}
|
||||
$c = $this->getSide($side);
|
||||
if($c->getId() === $this->id and $c->getDamage() === $this->meta){
|
||||
$tile = $this->getLevel()->getTile($c);
|
||||
$tile = $this->getLevelNonNull()->getTile($c);
|
||||
if($tile instanceof TileChest and !$tile->isPaired()){
|
||||
$chest = $tile;
|
||||
break;
|
||||
@ -89,8 +89,8 @@ class Chest extends Transparent{
|
||||
}
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player));
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
$tile = Tile::createTile(Tile::CHEST, $this->getLevelNonNull(), TileChest::createNBT($this, $face, $item, $player));
|
||||
|
||||
if($chest instanceof TileChest and $tile instanceof TileChest){
|
||||
$chest->pairWith($tile);
|
||||
@ -103,12 +103,12 @@ class Chest extends Transparent{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
|
||||
$t = $this->getLevel()->getTile($this);
|
||||
$t = $this->getLevelNonNull()->getTile($this);
|
||||
$chest = null;
|
||||
if($t instanceof TileChest){
|
||||
$chest = $t;
|
||||
}else{
|
||||
$chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this));
|
||||
$chest = Tile::createTile(Tile::CHEST, $this->getLevelNonNull(), TileChest::createNBT($this));
|
||||
if(!($chest instanceof TileChest)){
|
||||
return true;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ abstract class Crops extends Flowable{
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
if($blockReplace->getSide(Vector3::SIDE_DOWN)->getId() === Block::FARMLAND){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -52,7 +52,7 @@ abstract class Crops extends Flowable{
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true, true);
|
||||
}
|
||||
|
||||
$item->pop();
|
||||
@ -65,7 +65,7 @@ abstract class Crops extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::FARMLAND){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ abstract class Crops extends Flowable{
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class Dandelion extends Flowable{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -52,7 +52,7 @@ class Dandelion extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ class DeadBush extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,9 +54,9 @@ class Dirt extends Solid{
|
||||
if($item instanceof Hoe){
|
||||
$item->applyDamage(1);
|
||||
if($this->meta === 1){
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -201,9 +201,9 @@ abstract class Door extends Transparent{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), false);
|
||||
if($this->getSide(Vector3::SIDE_UP) instanceof Door){
|
||||
$this->getLevel()->setBlock($this->getSide(Vector3::SIDE_UP), BlockFactory::get(Block::AIR), false);
|
||||
$this->getLevelNonNull()->setBlock($this->getSide(Vector3::SIDE_UP), BlockFactory::get(Block::AIR), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -230,8 +230,8 @@ abstract class Door extends Transparent{
|
||||
}
|
||||
|
||||
$this->setDamage($player->getDirection() & 0x03);
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true); //Bottom
|
||||
$this->getLevel()->setBlock($blockUp, BlockFactory::get($this->getId(), $metaUp), true); //Top
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); //Bottom
|
||||
$this->getLevelNonNull()->setBlock($blockUp, BlockFactory::get($this->getId(), $metaUp), true); //Top
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,8 @@ class DoublePlant extends Flowable{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$id = $blockReplace->getSide(Vector3::SIDE_DOWN)->getId();
|
||||
if(($id === Block::GRASS or $id === Block::DIRT) and $blockReplace->getSide(Vector3::SIDE_UP)->canBeReplaced()){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, false, false);
|
||||
$this->getLevel()->setBlock($blockReplace->getSide(Vector3::SIDE_UP), BlockFactory::get($this->id, $this->meta | self::BITFLAG_TOP), false, false);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, false, false);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace->getSide(Vector3::SIDE_UP), BlockFactory::get($this->id, $this->meta | self::BITFLAG_TOP), false, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -85,7 +85,7 @@ class DoublePlant extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->isValidHalfPlant() or (($this->meta & self::BITFLAG_TOP) === 0 and $this->getSide(Vector3::SIDE_DOWN)->isTransparent())){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,9 +40,9 @@ class EnchantingTable extends Transparent{
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevelNonNull(), TileEnchantTable::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -69,8 +69,8 @@ class EnderChest extends Chest{
|
||||
|
||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this, $face, $item, $player));
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
Tile::createTile(Tile::ENDER_CHEST, $this->getLevelNonNull(), TileEnderChest::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -78,12 +78,12 @@ class EnderChest extends Chest{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
|
||||
$t = $this->getLevel()->getTile($this);
|
||||
$t = $this->getLevelNonNull()->getTile($this);
|
||||
$enderChest = null;
|
||||
if($t instanceof TileEnderChest){
|
||||
$enderChest = $t;
|
||||
}else{
|
||||
$enderChest = Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this));
|
||||
$enderChest = Tile::createTile(Tile::ENDER_CHEST, $this->getLevelNonNull(), TileEnderChest::createNBT($this));
|
||||
if(!($enderChest instanceof TileEnderChest)){
|
||||
return true;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ abstract class Fallable extends Solid{
|
||||
$nbt->setInt("TileID", $this->getId());
|
||||
$nbt->setByte("Data", $this->getDamage());
|
||||
|
||||
$fall = Entity::createEntity("FallingSand", $this->getLevel(), $nbt);
|
||||
$fall = Entity::createEntity("FallingSand", $this->getLevelNonNull(), $nbt);
|
||||
|
||||
if($fall !== null){
|
||||
$fall->spawnToAll();
|
||||
|
@ -69,7 +69,7 @@ class FenceGate extends Transparent{
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$this->meta = ($player instanceof Player ? ($player->getDirection() - 1) & 0x03 : 0);
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -85,7 +85,7 @@ class FenceGate extends Transparent{
|
||||
$this->meta |= (($player->getDirection() - 1) & 0x02);
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||
$this->level->addSound(new DoorSound($this));
|
||||
return true;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ class Fire extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->getSide(Vector3::SIDE_DOWN)->isSolid() and !$this->hasAdjacentFlammableBlocks()){
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
}else{
|
||||
$this->level->scheduleDelayedBlockUpdate($this, mt_rand(30, 40));
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class Flower extends Flowable{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -72,7 +72,7 @@ class Flower extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,19 +62,19 @@ class FlowerPot extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player));
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
Tile::createTile(Tile::FLOWER_POT, $this->getLevelNonNull(), TileFlowerPot::createNBT($this, $face, $item, $player));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
$pot = $this->getLevel()->getTile($this);
|
||||
$pot = $this->getLevelNonNull()->getTile($this);
|
||||
if(!($pot instanceof TileFlowerPot)){
|
||||
return false;
|
||||
}
|
||||
@ -83,7 +83,7 @@ class FlowerPot extends Flowable{
|
||||
}
|
||||
|
||||
$this->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item.
|
||||
$this->getLevel()->setBlock($this, $this, true, false);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true, false);
|
||||
$pot->setItem($item->pop());
|
||||
|
||||
return true;
|
||||
@ -96,7 +96,7 @@ class FlowerPot extends Flowable{
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
$items = parent::getDropsForCompatibleTool($item);
|
||||
|
||||
$tile = $this->getLevel()->getTile($this);
|
||||
$tile = $this->getLevelNonNull()->getTile($this);
|
||||
if($tile instanceof TileFlowerPot){
|
||||
$item = $tile->getItem();
|
||||
if($item->getId() !== Item::AIR){
|
||||
|
@ -53,7 +53,7 @@ class GlazedTerracotta extends Solid{
|
||||
$this->meta = $faces[(~($player->getDirection() - 1)) & 0x03];
|
||||
}
|
||||
|
||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
|
@ -53,6 +53,6 @@ class GlowingRedstoneOre extends RedstoneOre{
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false);
|
||||
}
|
||||
}
|
||||
|
@ -100,17 +100,17 @@ class Grass extends Solid{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){
|
||||
$item->pop();
|
||||
TallGrassObject::growGrass($this->getLevel(), $this, new Random(mt_rand()), 8, 2);
|
||||
TallGrassObject::growGrass($this->getLevelNonNull(), $this, new Random(mt_rand()), 8, 2);
|
||||
|
||||
return true;
|
||||
}elseif($item instanceof Hoe){
|
||||
$item->applyDamage(1);
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND));
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::FARMLAND));
|
||||
|
||||
return true;
|
||||
}elseif($item instanceof Shovel and $this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR){
|
||||
$item->applyDamage(1);
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::GRASS_PATH));
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::GRASS_PATH));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class HayBale extends Solid{
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ class Ice extends Transparent{
|
||||
|
||||
public function onBreak(Item $item, Player $player = null) : bool{
|
||||
if(($player === null or $player->isSurvival()) and !$item->hasEnchantment(Enchantment::SILK_TOUCH)){
|
||||
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::WATER), true);
|
||||
return $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::WATER), true);
|
||||
}
|
||||
return parent::onBreak($item, $player);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class ItemFrame extends Flowable{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
$tile = $this->level->getTile($this);
|
||||
if(!($tile instanceof TileItemFrame)){
|
||||
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this));
|
||||
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevelNonNull(), TileItemFrame::createNBT($this));
|
||||
if(!($tile instanceof TileItemFrame)){
|
||||
return true;
|
||||
}
|
||||
@ -88,7 +88,7 @@ class ItemFrame extends Flowable{
|
||||
$this->meta = $faces[$face];
|
||||
$this->level->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::ITEM_FRAME, $this->getLevelNonNull(), TileItemFrame::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -100,7 +100,7 @@ class Ladder extends Transparent{
|
||||
];
|
||||
if(isset($faces[$face])){
|
||||
$this->meta = $faces[$face];
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -115,8 +115,8 @@ class Lava extends Liquid{
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true, false);
|
||||
$this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||
$ret = $this->getLevelNonNull()->setBlock($this, $this, true, false);
|
||||
$this->getLevelNonNull()->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class Leaves extends Transparent{
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(($this->meta & 0b00001100) === 0){
|
||||
$this->meta |= 0x08;
|
||||
$this->getLevel()->setBlock($this, $this, true, false);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,16 +155,16 @@ class Leaves extends Transparent{
|
||||
$ev = new LeavesDecayEvent($this);
|
||||
$ev->call();
|
||||
if($ev->isCancelled() or $this->findLog($this, $visited, 0)){
|
||||
$this->getLevel()->setBlock($this, $this, false, false);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, false, false);
|
||||
}else{
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$this->meta |= 0x04;
|
||||
return $this->getLevel()->setBlock($this, $this, true);
|
||||
return $this->getLevelNonNull()->setBlock($this, $this, true);
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
|
@ -49,7 +49,7 @@ class MelonStem extends Crops{
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true);
|
||||
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true);
|
||||
}
|
||||
}else{
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
@ -64,7 +64,7 @@ class MelonStem extends Crops{
|
||||
$ev = new BlockGrowEvent($side, BlockFactory::get(Block::MELON_BLOCK));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($side, $ev->getNewState(), true);
|
||||
$this->getLevelNonNull()->setBlock($side, $ev->getNewState(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,13 +64,13 @@ class Mycelium extends Solid{
|
||||
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||
$y = mt_rand($this->y - 2, $this->y + 2);
|
||||
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||
$block = $this->getLevel()->getBlockAt($x, $y, $z);
|
||||
$block = $this->getLevelNonNull()->getBlockAt($x, $y, $z);
|
||||
if($block->getId() === Block::DIRT){
|
||||
if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
|
||||
$ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($block, $ev->getNewState());
|
||||
$this->getLevelNonNull()->setBlock($block, $ev->getNewState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class NetherWartPlant extends Flowable{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === Block::SOUL_SAND){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, false, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, false, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -56,7 +56,7 @@ class NetherWartPlant extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::SOUL_SAND){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ class NetherWartPlant extends Flowable{
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), false, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class Pumpkin extends Solid{
|
||||
if($player instanceof Player){
|
||||
$this->meta = ((int) $player->getDirection() + 1) % 4;
|
||||
}
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ class PumpkinStem extends Crops{
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true);
|
||||
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true);
|
||||
}
|
||||
}else{
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
@ -64,7 +64,7 @@ class PumpkinStem extends Crops{
|
||||
$ev = new BlockGrowEvent($side, BlockFactory::get(Block::PUMPKIN));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($side, $ev->getNewState(), true);
|
||||
$this->getLevelNonNull()->setBlock($side, $ev->getNewState(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ class Quartz extends Solid{
|
||||
if($this->getVariant() !== self::NORMAL){
|
||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||
}
|
||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
|
@ -45,14 +45,14 @@ class RedMushroom extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if(!$down->isTransparent()){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -47,16 +47,16 @@ class RedstoneOre extends Solid{
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
return $this->getLevel()->setBlock($this, $this, true, false);
|
||||
return $this->getLevelNonNull()->setBlock($this, $this, true, false);
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
||||
return false; //this shouldn't prevent block placement
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
|
@ -59,7 +59,7 @@ class Sapling extends Flowable{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::FARMLAND){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -70,7 +70,7 @@ class Sapling extends Flowable{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
//TODO: change log type
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||
Tree::growTree($this->getLevelNonNull(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||
|
||||
$item->pop();
|
||||
|
||||
@ -82,7 +82,7 @@ class Sapling extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,10 +93,10 @@ class Sapling extends Flowable{
|
||||
public function onRandomTick() : void{
|
||||
if($this->level->getFullLightAt($this->x, $this->y, $this->z) >= 8 and mt_rand(1, 7) === 1){
|
||||
if(($this->meta & 0x08) === 0x08){
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||
Tree::growTree($this->getLevelNonNull(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||
}else{
|
||||
$this->meta |= 0x08;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,13 +62,13 @@ class SignPost extends Transparent{
|
||||
|
||||
if($face === Vector3::SIDE_UP){
|
||||
$this->meta = $player !== null ? (floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f) : 0;
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||
}else{
|
||||
$this->meta = $face;
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::SIGN, $this->getLevel(), TileSign::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::SIGN, $this->getLevelNonNull(), TileSign::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -78,7 +78,7 @@ class SignPost extends Transparent{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,8 +65,8 @@ class Skull extends Flowable{
|
||||
}
|
||||
|
||||
$this->meta = $face;
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
Tile::createTile(Tile::SKULL, $this->getLevel(), TileSkull::createNBT($this, $face, $item, $player));
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||
Tile::createTile(Tile::SKULL, $this->getLevelNonNull(), TileSkull::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -56,11 +56,11 @@ abstract class Slab extends Transparent{
|
||||
$this->meta &= 0x07;
|
||||
if($face === Vector3::SIDE_DOWN){
|
||||
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0x08 and $blockClicked->getVariant() === $this->getVariant()){
|
||||
$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
$this->getLevelNonNull()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}else{
|
||||
@ -68,18 +68,18 @@ abstract class Slab extends Transparent{
|
||||
}
|
||||
}elseif($face === Vector3::SIDE_UP){
|
||||
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0 and $blockClicked->getVariant() === $this->getVariant()){
|
||||
$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
$this->getLevelNonNull()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
}else{ //TODO: collision
|
||||
if($blockReplace->getId() === $this->id){
|
||||
if($blockReplace->getVariant() === $this->getVariant()){
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -95,7 +95,7 @@ abstract class Slab extends Transparent{
|
||||
if($blockReplace->getId() === $this->id and $blockClicked->getVariant() !== $this->getVariant()){
|
||||
return false;
|
||||
}
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ class SnowLayer extends Flowable{
|
||||
$this->setDamage($blockReplace->getDamage() + 1);
|
||||
}
|
||||
if($this->canBeSupportedBy($blockReplace->getSide(Vector3::SIDE_DOWN))){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -76,7 +76,7 @@ class SnowLayer extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedBy($this->getSide(Vector3::SIDE_DOWN))){
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ class SnowLayer extends Flowable{
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if($this->level->getBlockLightAt($this->x, $this->y, $this->z) >= 12){
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ abstract class Stair extends Transparent{
|
||||
if(($clickVector->y > 0.5 and $face !== Vector3::SIDE_UP) or $face === Vector3::SIDE_DOWN){
|
||||
$this->meta |= 0x04; //Upside-down stairs
|
||||
}
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -62,13 +62,13 @@ class StandingBanner extends Transparent{
|
||||
if($face !== Vector3::SIDE_DOWN){
|
||||
if($face === Vector3::SIDE_UP and $player !== null){
|
||||
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||
}else{
|
||||
$this->meta = $face;
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $this->meta), true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $this->meta), true);
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::BANNER, $this->getLevel(), TileBanner::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::BANNER, $this->getLevelNonNull(), TileBanner::createNBT($this, $face, $item, $player));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ class StandingBanner extends Transparent{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,20 +46,20 @@ class Sugarcane extends Flowable{
|
||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
$b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
if($b->getId() === self::AIR){
|
||||
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK));
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
break;
|
||||
}
|
||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||
$this->getLevelNonNull()->setBlock($b, $ev->getNewState(), true);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->meta = 0;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||
}
|
||||
|
||||
$item->pop();
|
||||
@ -73,7 +73,7 @@ class Sugarcane extends Flowable{
|
||||
public function onNearbyBlockChange() : void{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->isTransparent() and $down->getId() !== self::SUGARCANE_BLOCK){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,17 +85,17 @@ class Sugarcane extends Flowable{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
||||
if($this->meta === 0x0F){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
$b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
if($b->getId() === self::AIR){
|
||||
$this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||
$this->getLevelNonNull()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->meta = 0;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||
}else{
|
||||
++$this->meta;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,7 +103,7 @@ class Sugarcane extends Flowable{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === self::SUGARCANE_BLOCK){
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||
|
||||
return true;
|
||||
}elseif($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::SAND){
|
||||
@ -112,7 +112,7 @@ class Sugarcane extends Flowable{
|
||||
$block2 = $down->getSide(Vector3::SIDE_WEST);
|
||||
$block3 = $down->getSide(Vector3::SIDE_EAST);
|
||||
if(($block0 instanceof Water) or ($block1 instanceof Water) or ($block2 instanceof Water) or ($block3 instanceof Water)){
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -78,13 +78,13 @@ class TNT extends Solid{
|
||||
* @return void
|
||||
*/
|
||||
public function ignite(int $fuse = 80){
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
|
||||
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
|
||||
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
|
||||
$nbt->setShort("Fuse", $fuse);
|
||||
|
||||
$tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), $nbt);
|
||||
$tnt = Entity::createEntity("PrimedTNT", $this->getLevelNonNull(), $nbt);
|
||||
|
||||
if($tnt !== null){
|
||||
$tnt->spawnToAll();
|
||||
|
@ -53,7 +53,7 @@ class TallGrass extends Flowable{
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN)->getId();
|
||||
if($down === self::GRASS or $down === self::DIRT){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -63,7 +63,7 @@ class TallGrass extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ //Replace with common break method
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ class Torch extends Flowable{
|
||||
$face = $faces[$meta] ?? Vector3::SIDE_DOWN;
|
||||
|
||||
if($this->getSide($face)->isTransparent() and !($face === Vector3::SIDE_DOWN and ($below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL))){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,12 +73,12 @@ class Torch extends Flowable{
|
||||
Vector3::SIDE_EAST => 1
|
||||
];
|
||||
$this->meta = $faces[$face];
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}elseif(!$below->isTransparent() or $below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL){
|
||||
$this->meta = 0;
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ class Trapdoor extends Transparent{
|
||||
if(($clickVector->y > 0.5 and $face !== self::SIDE_UP) or $face === self::SIDE_DOWN){
|
||||
$this->meta |= self::MASK_UPPER; //top half of block
|
||||
}
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -146,7 +146,7 @@ class Trapdoor extends Transparent{
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
$this->meta ^= self::MASK_OPENED;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||
$this->level->addSound(new DoorSound($this));
|
||||
return true;
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ class Vine extends Flowable{
|
||||
$this->meta |= $blockReplace->meta;
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ class WallBanner extends StandingBanner{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class WallSign extends SignPost{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,8 +73,8 @@ class Water extends Liquid{
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true, false);
|
||||
$this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||
$ret = $this->getLevelNonNull()->setBlock($this, $this, true, false);
|
||||
$this->getLevelNonNull()->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class WaterLily extends Flowable{
|
||||
if($blockClicked instanceof Water){
|
||||
$up = $blockClicked->getSide(Vector3::SIDE_UP);
|
||||
if($up->getId() === Block::AIR){
|
||||
$this->getLevel()->setBlock($up, $this, true, true);
|
||||
$this->getLevelNonNull()->setBlock($up, $this, true, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -69,7 +69,7 @@ class WaterLily extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!($this->getSide(Vector3::SIDE_DOWN) instanceof Water)){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ class Wood extends Solid{
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
|
@ -68,7 +68,7 @@ class CommandReader extends Thread{
|
||||
|
||||
$opts = getopt("", ["disable-readline", "enable-readline"]);
|
||||
|
||||
if(extension_loaded("readline") and (Utils::getOS() === "win" ? isset($opts["enable-readline"]) : !isset($opts["disable-readline"])) and !$this->isPipe(STDIN)){
|
||||
if(extension_loaded("readline") and (Utils::getOS() === Utils::OS_WINDOWS ? isset($opts["enable-readline"]) : !isset($opts["disable-readline"])) and !$this->isPipe(STDIN)){
|
||||
$this->type = self::TYPE_READLINE;
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class GiveCommand extends VanillaCommand{
|
||||
}
|
||||
|
||||
try{
|
||||
$item = ItemFactory::fromString($args[1]);
|
||||
$item = ItemFactory::fromStringSingle($args[1]);
|
||||
}catch(\InvalidArgumentException $e){
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.give.item.notFound", [$args[1]]));
|
||||
return true;
|
||||
|
@ -92,7 +92,7 @@ class ParticleCommand extends VanillaCommand{
|
||||
}
|
||||
|
||||
if($sender instanceof Player){
|
||||
$level = $sender->getLevel();
|
||||
$level = $sender->getLevelNonNull();
|
||||
$pos = new Vector3(
|
||||
$this->getRelativeDouble($sender->getX(), $sender, $args[1]),
|
||||
$this->getRelativeDouble($sender->getY(), $sender, $args[2], 0, Level::Y_MAX),
|
||||
|
@ -44,7 +44,7 @@ class SeedCommand extends VanillaCommand{
|
||||
}
|
||||
|
||||
if($sender instanceof Player){
|
||||
$seed = $sender->getLevel()->getSeed();
|
||||
$seed = $sender->getLevelNonNull()->getSeed();
|
||||
}else{
|
||||
$seed = $sender->getServer()->getDefaultLevel()->getSeed();
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class SetWorldSpawnCommand extends VanillaCommand{
|
||||
|
||||
if(count($args) === 0){
|
||||
if($sender instanceof Player){
|
||||
$level = $sender->getLevel();
|
||||
$level = $sender->getLevelNonNull();
|
||||
$pos = (new Vector3($sender->x, $sender->y, $sender->z))->round();
|
||||
}else{
|
||||
$sender->sendMessage(TextFormat::RED . "You can only perform this command as a player");
|
||||
|
@ -71,7 +71,7 @@ class SpawnpointCommand extends VanillaCommand{
|
||||
|
||||
if(count($args) === 4){
|
||||
if($target->isValid()){
|
||||
$level = $target->getLevel();
|
||||
$level = $target->getLevelNonNull();
|
||||
$pos = $sender instanceof Player ? $sender->getPosition() : $level->getSpawnLocation();
|
||||
$x = $this->getRelativeDouble($pos->x, $sender, $args[1]);
|
||||
$y = $this->getRelativeDouble($pos->y, $sender, $args[2], 0, Level::Y_MAX);
|
||||
@ -84,7 +84,7 @@ class SpawnpointCommand extends VanillaCommand{
|
||||
}
|
||||
}elseif(count($args) <= 1){
|
||||
if($sender instanceof Player){
|
||||
$pos = new Position($sender->getFloorX(), $sender->getFloorY(), $sender->getFloorZ(), $sender->getLevel());
|
||||
$pos = new Position($sender->getFloorX(), $sender->getFloorY(), $sender->getFloorZ(), $sender->getLevelNonNull());
|
||||
$target->setSpawn($pos);
|
||||
|
||||
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.spawnpoint.success", [$target->getName(), round($pos->x, 2), round($pos->y, 2), round($pos->z, 2)]));
|
||||
|
@ -24,8 +24,8 @@ declare(strict_types=1);
|
||||
namespace pocketmine\command\defaults;
|
||||
|
||||
use pocketmine\command\CommandSender;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
use function count;
|
||||
use function floor;
|
||||
use function microtime;
|
||||
@ -48,8 +48,8 @@ class StatusCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
|
||||
$rUsage = Utils::getRealMemoryUsage();
|
||||
$mUsage = Utils::getMemoryUsage(true);
|
||||
$rUsage = Process::getRealMemoryUsage();
|
||||
$mUsage = Process::getAdvancedMemoryUsage();
|
||||
|
||||
$server = $sender->getServer();
|
||||
$sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Server status" . TextFormat::GREEN . " ----");
|
||||
@ -94,7 +94,7 @@ class StatusCommand extends VanillaCommand{
|
||||
$sender->sendMessage(TextFormat::GOLD . "Network upload: " . TextFormat::RED . round($server->getNetwork()->getUpload() / 1024, 2) . " kB/s");
|
||||
$sender->sendMessage(TextFormat::GOLD . "Network download: " . TextFormat::RED . round($server->getNetwork()->getDownload() / 1024, 2) . " kB/s");
|
||||
|
||||
$sender->sendMessage(TextFormat::GOLD . "Thread count: " . TextFormat::RED . Utils::getThreadCount());
|
||||
$sender->sendMessage(TextFormat::GOLD . "Thread count: " . TextFormat::RED . Process::getThreadCount());
|
||||
|
||||
$sender->sendMessage(TextFormat::GOLD . "Main thread memory: " . TextFormat::RED . number_format(round(($mUsage[0] / 1024) / 1024, 2), 2) . " MB.");
|
||||
$sender->sendMessage(TextFormat::GOLD . "Total memory: " . TextFormat::RED . number_format(round(($mUsage[1] / 1024) / 1024, 2), 2) . " MB.");
|
||||
|
@ -77,7 +77,7 @@ class TimeCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
if($sender instanceof Player){
|
||||
$level = $sender->getLevel();
|
||||
$level = $sender->getLevelNonNull();
|
||||
}else{
|
||||
$level = $sender->getServer()->getDefaultLevel();
|
||||
}
|
||||
@ -96,12 +96,28 @@ class TimeCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
|
||||
if($args[1] === "day"){
|
||||
$value = Level::TIME_DAY;
|
||||
}elseif($args[1] === "night"){
|
||||
$value = Level::TIME_NIGHT;
|
||||
}else{
|
||||
$value = $this->getInteger($sender, $args[1], 0);
|
||||
switch($args[1]){
|
||||
case "day":
|
||||
$value = Level::TIME_DAY;
|
||||
break;
|
||||
case "noon":
|
||||
$value = Level::TIME_NOON;
|
||||
break;
|
||||
case "sunset":
|
||||
$value = Level::TIME_SUNSET;
|
||||
break;
|
||||
case "night":
|
||||
$value = Level::TIME_NIGHT;
|
||||
break;
|
||||
case "midnight":
|
||||
$value = Level::TIME_MIDNIGHT;
|
||||
break;
|
||||
case "sunrise":
|
||||
$value = Level::TIME_SUNRISE;
|
||||
break;
|
||||
default:
|
||||
$value = $this->getInteger($sender, $args[1], 0);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($sender->getServer()->getLevels() as $level){
|
||||
|
@ -68,21 +68,21 @@ class TitleCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player->addTitle(implode(" ", array_slice($args, 2)));
|
||||
$player->sendTitle(implode(" ", array_slice($args, 2)));
|
||||
break;
|
||||
case "subtitle":
|
||||
if(count($args) < 3){
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player->addSubTitle(implode(" ", array_slice($args, 2)));
|
||||
$player->sendSubTitle(implode(" ", array_slice($args, 2)));
|
||||
break;
|
||||
case "actionbar":
|
||||
if(count($args) < 3){
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player->addActionBarMessage(implode(" ", array_slice($args, 2)));
|
||||
$player->sendActionBarMessage(implode(" ", array_slice($args, 2)));
|
||||
break;
|
||||
case "times":
|
||||
if(count($args) < 5){
|
||||
|
@ -1750,7 +1750,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
}
|
||||
|
||||
if($pos instanceof Position and $pos->level !== null and $pos->level !== $this->level){
|
||||
if(!$this->switchLevel($pos->getLevel())){
|
||||
if(!$this->switchLevel($pos->getLevelNonNull())){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1856,7 +1856,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
$pitch = $pitch ?? $pos->pitch;
|
||||
}
|
||||
$from = Position::fromObject($this, $this->level);
|
||||
$to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->level);
|
||||
$to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevelNonNull() : $this->level);
|
||||
$ev = new EntityTeleportEvent($this, $from, $to);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
@ -1921,7 +1921,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
protected function sendSpawnPacket(Player $player) : void{
|
||||
$pk = new AddActorPacket();
|
||||
$pk->entityRuntimeId = $this->getId();
|
||||
$pk->type = static::NETWORK_ID;
|
||||
$pk->type = AddActorPacket::LEGACY_ID_MAP_BC[static::NETWORK_ID];
|
||||
$pk->position = $this->asVector3();
|
||||
$pk->motion = $this->getMotion();
|
||||
$pk->yaw = $this->yaw;
|
||||
|
@ -191,7 +191,7 @@ abstract class Living extends Entity implements Damageable{
|
||||
public function hasLineOfSight(Entity $entity) : bool{
|
||||
//TODO: head height
|
||||
return true;
|
||||
//return $this->getLevel()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null;
|
||||
//return $this->getLevelNonNull()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -608,15 +608,14 @@ abstract class Living extends Entity implements Damageable{
|
||||
}
|
||||
|
||||
protected function onDeath() : void{
|
||||
$ev = new EntityDeathEvent($this, $this->getDrops());
|
||||
$ev = new EntityDeathEvent($this, $this->getDrops(), $this->getXpDropAmount());
|
||||
$ev->call();
|
||||
foreach($ev->getDrops() as $item){
|
||||
$this->getLevel()->dropItem($this, $item);
|
||||
$this->getLevelNonNull()->dropItem($this, $item);
|
||||
}
|
||||
|
||||
//TODO: check death conditions (must have been damaged by player < 5 seconds from death)
|
||||
//TODO: allow this number to be manipulated during EntityDeathEvent
|
||||
$this->level->dropExperience($this, $this->getXpDropAmount());
|
||||
$this->level->dropExperience($this, $ev->getXpDropAmount());
|
||||
}
|
||||
|
||||
protected function onDeathUpdate(int $tickDiff) : bool{
|
||||
|
@ -98,7 +98,7 @@ class FallingBlock extends Entity{
|
||||
$hasUpdate = parent::entityBaseTick($tickDiff);
|
||||
|
||||
if(!$this->isFlaggedForDespawn()){
|
||||
$pos = Position::fromObject($this->add(-$this->width / 2, $this->height, -$this->width / 2)->floor(), $this->getLevel());
|
||||
$pos = Position::fromObject($this->add(-$this->width / 2, $this->height, -$this->width / 2)->floor(), $this->getLevelNonNull());
|
||||
|
||||
$this->block->position($pos);
|
||||
|
||||
@ -113,12 +113,12 @@ class FallingBlock extends Entity{
|
||||
$block = $this->level->getBlock($pos);
|
||||
if(!$block->canBeReplaced() or ($this->onGround and abs($this->y - $this->getFloorY()) > 0.001)){
|
||||
//FIXME: anvils are supposed to destroy torches
|
||||
$this->getLevel()->dropItem($this, ItemFactory::get($this->getBlock(), $this->getDamage()));
|
||||
$this->getLevelNonNull()->dropItem($this, ItemFactory::get($this->getBlock(), $this->getDamage()));
|
||||
}else{
|
||||
$ev = new EntityBlockChangeEvent($this, $block, $blockTarget ?? $this->block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($pos, $ev->getTo(), true);
|
||||
$this->getLevelNonNull()->setBlock($pos, $ev->getTo(), true);
|
||||
}
|
||||
}
|
||||
$hasUpdate = true;
|
||||
|
@ -44,6 +44,6 @@ class EntityDamageByChildEntityEvent extends EntityDamageByEntityEvent{
|
||||
* Returns the entity which caused the damage, or null if the entity has been killed or closed.
|
||||
*/
|
||||
public function getChild() : ?Entity{
|
||||
return $this->getEntity()->getLevel()->getServer()->findEntity($this->childEntityEid);
|
||||
return $this->getEntity()->getLevelNonNull()->getServer()->findEntity($this->childEntityEid);
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class EntityDamageByEntityEvent extends EntityDamageEvent{
|
||||
* Returns the attacking entity, or null if the attacker has been killed or closed.
|
||||
*/
|
||||
public function getDamager() : ?Entity{
|
||||
return $this->getEntity()->getLevel()->getServer()->findEntity($this->damagerEntityId);
|
||||
return $this->getEntity()->getLevelNonNull()->getServer()->findEntity($this->damagerEntityId);
|
||||
}
|
||||
|
||||
public function getKnockBack() : float{
|
||||
|
@ -29,13 +29,16 @@ use pocketmine\item\Item;
|
||||
class EntityDeathEvent extends EntityEvent{
|
||||
/** @var Item[] */
|
||||
private $drops = [];
|
||||
/** @var int */
|
||||
private $xp;
|
||||
|
||||
/**
|
||||
* @param Item[] $drops
|
||||
*/
|
||||
public function __construct(Living $entity, array $drops = []){
|
||||
public function __construct(Living $entity, array $drops = [], int $xp = 0){
|
||||
$this->entity = $entity;
|
||||
$this->drops = $drops;
|
||||
$this->xp = $xp;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,4 +61,21 @@ class EntityDeathEvent extends EntityEvent{
|
||||
public function setDrops(array $drops) : void{
|
||||
$this->drops = $drops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how much experience is dropped due to this entity's death.
|
||||
*/
|
||||
public function getXpDropAmount() : int{
|
||||
return $this->xp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setXpDropAmount(int $xp) : void{
|
||||
if($xp < 0){
|
||||
throw new \InvalidArgumentException("XP drop amount must not be negative");
|
||||
}
|
||||
$this->xp = $xp;
|
||||
}
|
||||
}
|
||||
|
@ -42,26 +42,44 @@ class EntityDespawnEvent extends EntityEvent{
|
||||
$this->entityType = $entity::NETWORK_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function getType() : int{
|
||||
return $this->entityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isCreature() : bool{
|
||||
return $this->entity instanceof Creature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isHuman() : bool{
|
||||
return $this->entity instanceof Human;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isProjectile() : bool{
|
||||
return $this->entity instanceof Projectile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isVehicle() : bool{
|
||||
return $this->entity instanceof Vehicle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isItem() : bool{
|
||||
return $this->entity instanceof ItemEntity;
|
||||
}
|
||||
|
@ -43,30 +43,51 @@ class EntitySpawnEvent extends EntityEvent{
|
||||
$this->entityType = $entity::NETWORK_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function getPosition() : Position{
|
||||
return $this->entity->getPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function getType() : int{
|
||||
return $this->entityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isCreature() : bool{
|
||||
return $this->entity instanceof Creature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isHuman() : bool{
|
||||
return $this->entity instanceof Human;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isProjectile() : bool{
|
||||
return $this->entity instanceof Projectile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isVehicle() : bool{
|
||||
return $this->entity instanceof Vehicle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isItem() : bool{
|
||||
return $this->entity instanceof ItemEntity;
|
||||
}
|
||||
|
@ -47,8 +47,8 @@ class PlayerDeathEvent extends EntityDeathEvent{
|
||||
* @param Item[] $drops
|
||||
* @param string|TextContainer|null $deathMessage Null will cause the default vanilla message to be used
|
||||
*/
|
||||
public function __construct(Player $entity, array $drops, $deathMessage = null){
|
||||
parent::__construct($entity, $drops);
|
||||
public function __construct(Player $entity, array $drops, $deathMessage = null, int $xp = 0){
|
||||
parent::__construct($entity, $drops, $xp);
|
||||
$this->deathMessage = $deathMessage ?? self::deriveMessage($entity->getDisplayName(), $entity->getLastDamageCause());
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event\server;
|
||||
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\Process;
|
||||
|
||||
/**
|
||||
* Called when the server is in a low-memory state as defined by the properties
|
||||
@ -75,6 +75,7 @@ class LowMemoryEvent extends ServerEvent{
|
||||
* Amount of memory already freed
|
||||
*/
|
||||
public function getMemoryFreed() : int{
|
||||
return $this->getMemory() - ($this->isGlobal() ? Utils::getMemoryUsage(true)[1] : Utils::getMemoryUsage(true)[0]);
|
||||
$usage = Process::getAdvancedMemoryUsage();
|
||||
return $this->getMemory() - ($this->isGlobal() ? $usage[1] : $usage[0]);
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ class ChestInventory extends ContainerInventory{
|
||||
if(count($this->getViewers()) === 1 and $this->getHolder()->isValid()){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->broadcastBlockEventPacket(true);
|
||||
$this->getHolder()->getLevel()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
||||
$this->getHolder()->getLevelNonNull()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ class ChestInventory extends ContainerInventory{
|
||||
if(count($this->getViewers()) === 1 and $this->getHolder()->isValid()){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->broadcastBlockEventPacket(false);
|
||||
$this->getHolder()->getLevel()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
||||
$this->getHolder()->getLevelNonNull()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
||||
}
|
||||
parent::onClose($who);
|
||||
}
|
||||
@ -96,6 +96,6 @@ class ChestInventory extends ContainerInventory{
|
||||
$pk->z = (int) $holder->z;
|
||||
$pk->eventType = 1; //it's always 1 for a chest
|
||||
$pk->eventData = $isOpen ? 1 : 0;
|
||||
$holder->getLevel()->broadcastPacketToViewers($holder, $pk);
|
||||
$holder->getLevelNonNull()->broadcastPacketToViewers($holder, $pk);
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ class CraftingManager{
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
break;
|
||||
}
|
||||
$this->registerRecipe(new ShapelessRecipe(
|
||||
$this->registerShapelessRecipe(new ShapelessRecipe(
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
));
|
||||
@ -69,7 +69,7 @@ class CraftingManager{
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
break;
|
||||
}
|
||||
$this->registerRecipe(new ShapedRecipe(
|
||||
$this->registerShapedRecipe(new ShapedRecipe(
|
||||
$recipe["shape"],
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
@ -79,7 +79,7 @@ class CraftingManager{
|
||||
if($recipe["block"] !== "furnace"){ //TODO: filter others out for now to avoid breaking economics
|
||||
break;
|
||||
}
|
||||
$this->registerRecipe(new FurnaceRecipe(
|
||||
$this->registerFurnaceRecipe(new FurnaceRecipe(
|
||||
Item::jsonDeserialize($recipe["output"]),
|
||||
Item::jsonDeserialize($recipe["input"]))
|
||||
);
|
||||
@ -281,6 +281,9 @@ class CraftingManager{
|
||||
return $this->furnaceRecipes[$input->getId() . ":" . $input->getDamage()] ?? $this->furnaceRecipes[$input->getId() . ":?"] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function registerRecipe(Recipe $recipe) : void{
|
||||
$recipe->registerToCraftingManager($this);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ class EnderChestInventory extends ChestInventory{
|
||||
*/
|
||||
public function setHolderPosition(EnderChest $enderChest){
|
||||
$this->holder->setComponents($enderChest->getFloorX(), $enderChest->getFloorY(), $enderChest->getFloorZ());
|
||||
$this->holder->setLevel($enderChest->getLevel());
|
||||
$this->holder->setLevel($enderChest->getLevelNonNull());
|
||||
}
|
||||
|
||||
protected function getOpenSound() : int{
|
||||
|
@ -53,6 +53,9 @@ class FurnaceRecipe implements Recipe{
|
||||
return clone $this->output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function registerToCraftingManager(CraftingManager $manager) : void{
|
||||
$manager->registerFurnaceRecipe($this);
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ class PlayerInventory extends BaseInventory{
|
||||
$this->sendSlot($this->getHeldItemIndex(), $target);
|
||||
}
|
||||
}else{
|
||||
$this->getHolder()->getLevel()->getServer()->broadcastPacket($target, $pk);
|
||||
$this->getHolder()->getLevelNonNull()->getServer()->broadcastPacket($target, $pk);
|
||||
if(in_array($this->getHolder(), $target, true)){
|
||||
$this->sendSlot($this->getHeldItemIndex(), $this->getHolder());
|
||||
}
|
||||
|
@ -23,7 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\inventory;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
interface Recipe{
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function registerToCraftingManager(CraftingManager $manager) : void;
|
||||
}
|
||||
|
@ -176,6 +176,9 @@ class ShapedRecipe implements CraftingRecipe{
|
||||
return $this->shape;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function registerToCraftingManager(CraftingManager $manager) : void{
|
||||
$manager->registerShapedRecipe($this);
|
||||
}
|
||||
|
@ -105,6 +105,9 @@ class ShapelessRecipe implements CraftingRecipe{
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function registerToCraftingManager(CraftingManager $manager) : void{
|
||||
$manager->registerShapelessRecipe($this);
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ class Bow extends Tool{
|
||||
$p = $diff / 20;
|
||||
$baseForce = min((($p ** 2) + $p * 2) / 3, 1);
|
||||
|
||||
$entity = Entity::createEntity("Arrow", $player->getLevel(), $nbt, $player, $baseForce >= 1);
|
||||
$entity = Entity::createEntity("Arrow", $player->getLevelNonNull(), $nbt, $player, $baseForce >= 1);
|
||||
if($entity instanceof Projectile){
|
||||
$infinity = $this->hasEnchantment(Enchantment::INFINITY);
|
||||
if($entity instanceof ArrowEntity){
|
||||
@ -110,7 +110,7 @@ class Bow extends Tool{
|
||||
$ev->getProjectile()->flagForDespawn();
|
||||
}else{
|
||||
$ev->getProjectile()->spawnToAll();
|
||||
$player->getLevel()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_BOW);
|
||||
$player->getLevelNonNull()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_BOW);
|
||||
}
|
||||
}else{
|
||||
$entity->spawnToAll();
|
||||
|
@ -62,8 +62,8 @@ class Bucket extends Item implements MaybeConsumable{
|
||||
$ev = new PlayerBucketFillEvent($player, $blockReplace, $face, $this, $resultItem);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$player->getLevel()->setBlock($blockClicked, BlockFactory::get(Block::AIR), true, true);
|
||||
$player->getLevel()->broadcastLevelSoundEvent($blockClicked->add(0.5, 0.5, 0.5), $blockClicked->getBucketFillSound());
|
||||
$player->getLevelNonNull()->setBlock($blockClicked, BlockFactory::get(Block::AIR), true, true);
|
||||
$player->getLevelNonNull()->broadcastLevelSoundEvent($blockClicked->add(0.5, 0.5, 0.5), $blockClicked->getBucketFillSound());
|
||||
if($player->isSurvival()){
|
||||
if($stack->getCount() === 0){
|
||||
$player->getInventory()->setItemInHand($ev->getItem());
|
||||
@ -84,8 +84,8 @@ class Bucket extends Item implements MaybeConsumable{
|
||||
$ev = new PlayerBucketEmptyEvent($player, $blockReplace, $face, $this, ItemFactory::get(Item::BUCKET));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$player->getLevel()->setBlock($blockReplace, $resultBlock->getFlowingForm(), true, true);
|
||||
$player->getLevel()->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
|
||||
$player->getLevelNonNull()->setBlock($blockReplace, $resultBlock->getFlowingForm(), true, true);
|
||||
$player->getLevelNonNull()->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
|
||||
|
||||
if($player->isSurvival()){
|
||||
$player->getInventory()->setItemInHand($ev->getItem());
|
||||
|
@ -50,11 +50,10 @@ class ChorusFruit extends Food{
|
||||
}
|
||||
|
||||
public function onConsume(Living $consumer){
|
||||
$level = $consumer->getLevel();
|
||||
assert($level !== null);
|
||||
$level = $consumer->getLevelNonNull();
|
||||
|
||||
$minX = $consumer->getFloorX() - 8;
|
||||
$minY = min($consumer->getFloorY(), $consumer->getLevel()->getWorldHeight()) - 8;
|
||||
$minY = min($consumer->getFloorY(), $consumer->getLevelNonNull()->getWorldHeight()) - 8;
|
||||
$minZ = $consumer->getFloorZ() - 8;
|
||||
|
||||
$maxX = $minX + 16;
|
||||
|
@ -28,7 +28,6 @@ use pocketmine\block\BlockFactory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\Player;
|
||||
use function assert;
|
||||
|
||||
class FlintSteel extends Tool{
|
||||
public function __construct(int $meta = 0){
|
||||
@ -37,8 +36,7 @@ class FlintSteel extends Tool{
|
||||
|
||||
public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{
|
||||
if($blockReplace->getId() === self::AIR){
|
||||
$level = $player->getLevel();
|
||||
assert($level !== null);
|
||||
$level = $player->getLevelNonNull();
|
||||
$level->setBlock($blockReplace, BlockFactory::get(Block::FIRE), true);
|
||||
$level->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), LevelSoundEventPacket::SOUND_IGNITE);
|
||||
|
||||
|
@ -852,7 +852,7 @@ class Item implements ItemIds, \JsonSerializable{
|
||||
$item = ItemFactory::get($idTag->getValue(), $meta, $count);
|
||||
}elseif($idTag instanceof StringTag){ //PC item save format
|
||||
try{
|
||||
$item = ItemFactory::fromString($idTag->getValue());
|
||||
$item = ItemFactory::fromStringSingle($idTag->getValue());
|
||||
}catch(\InvalidArgumentException $e){
|
||||
//TODO: improve error handling
|
||||
return ItemFactory::get(Item::AIR, 0, 0);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user