Merge branch 'stable' into next-minor

This commit is contained in:
Dylan K. Taylor 2019-07-26 19:50:17 +01:00
commit bb048fb361
87 changed files with 1961 additions and 908 deletions

View File

@ -39,7 +39,11 @@ use const STDIN;
require_once dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
require_once dirname(__DIR__) . '/vendor/autoload.php';
$currentVer = new VersionString(BASE_VERSION);
if(isset($argv[1])){
$currentVer = new VersionString($argv[1]);
}else{
$currentVer = new VersionString(BASE_VERSION);
}
$nextVer = new VersionString(sprintf(
"%u.%u.%u",
$currentVer->getMajor(),
@ -47,27 +51,31 @@ $nextVer = new VersionString(sprintf(
$currentVer->getPatch() + 1
));
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev) : void{
$versionInfo = file_get_contents($versionInfoPath);
$versionInfo = preg_replace(
$pattern = '/^const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m',
'const BASE_VERSION = "' . $newVersion . '";',
$versionInfo
);
$versionInfo = preg_replace(
'/^const IS_DEVELOPMENT_BUILD = (?:true|false);$/m',
'const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false'). ';',
$versionInfo
);
file_put_contents($versionInfoPath, $versionInfo);
}
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
$versionInfo = file_get_contents($versionInfoPath);
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
file_put_contents($versionInfoPath, preg_replace(
'/^const IS_DEVELOPMENT_BUILD = true;$/m',
'const IS_DEVELOPMENT_BUILD = false;',
$versionInfo
));
echo "please add appropriate notes to the changelog and press enter...";
fgets(STDIN);
system('git add "' . dirname(__DIR__) . '/changelogs"');
system('git commit -m "Release ' . BASE_VERSION . '" --include "' . $versionInfoPath . '"');
system('git tag ' . BASE_VERSION);
file_put_contents($versionInfoPath, $mod = preg_replace(
$pattern = '/^const BASE_VERSION = "' . preg_quote(BASE_VERSION, '/') . '";$/m',
'const BASE_VERSION = "' . $nextVer->getBaseVersion() . '";',
$versionInfo
));
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
system('git tag ' . $currentVer->getBaseVersion());
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true);
system('git add "' . $versionInfoPath . '"');
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
echo "pushing changes in 10 seconds";
echo "pushing changes in 10 seconds\n";
sleep(10);
system('git push origin HEAD ' . BASE_VERSION);
system('git push origin HEAD ' . $currentVer->getBaseVersion());

View File

@ -55,3 +55,15 @@ This changelog **does not account for protocol changes**. If your plugin uses th
- Fixed sluggish playercount updating on MOTD.
- Added new MultiRecipe UUIDs.
- Added an extra field to `StartGamePacket` to resolve minor incompatibility issues on different 1.11.x patch versions.
# 3.8.6
- Fixed `Entity->isNameTagAlwaysVisible()` not working.
- Log messages are now cleaned of invalid UTF-8 sequences before emitting them.
- Fixed negative integers being considered as strings for world seeds.
- Fixed out-of-bounds access on invalid inventory data in player data saves.
- Fixed crash when custom liquids have flow decays which aren't factors of 4.
- Fixed `Entity->noDamageTicks` not working when the entity had no previous damage cause.
# 3.8.7
- Improved documentation of `Player->getDisplayName()` and `Player::isValidUserName()`.
- Fixed a bug in `SetScorePacket` decoding causing the entry list to always be empty.

54
changelogs/3.9.md Normal file
View File

@ -0,0 +1,54 @@
**For Minecraft: Bedrock Edition 1.12.0**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 3.9.0
- Added support for Minecraft: Bedrock Edition 1.12.0
- Removed compatibility with 1.11.0
## Protocol
- The following classes in the `\pocketmine\network\mcpe\protocol` namespace have been renamed:
- `AddEntityPacket` -> `AddActorPacket`
- `AddItemEntityPacket` -> `AddItemActorPacket`
- `AvailableEntityIdentifiersPacket` -> `AvailableActorIdentifiersPacket`
- `BlockEntityDataPacket` -> `BlockActorDataPacket`
- `EntityEventPacket` -> `ActorEventPacket`
- `EntityFallPacket` -> `ActorFallPacket`
- `EntityPickRequestPacket` -> `ActorPickRequestPacket`
- `MoveEntityAbsolutePacket` -> `MoveActorAbsolutePacket`
- `MoveEntityDeltaPacket` -> `MoveActorDeltaPacket`
- `RemoveEntityPacket` -> `RemoveActorPacket`
- `SetEntityDataPacket` -> `SetActorDataPacket`
- `SetEntityLinkPacket` -> `SetActorLinkPacket`
- `SetEntityMotionPacket` -> `SetActorMotionPacket`
- `TakeItemEntityPacket` -> `TakeItemActorPacket`
- The following classes in the `\pocketmine\network\mcpe\protocol` namespace have been removed:
- `FullChunkDataPacket`
- The following classes in the `\pocketmine\network\mcpe\protocol` namespace have been added:
- `AddEntityPacket` (not to be confused with the old one)
- `ClientCacheBlobStatusPacket`
- `ClientCacheMissResponsePacket`
- `ClientCacheStatusPacket`
- `LevelChunkPacket`
- `RemoveEntityPacket` (not to be confused with the old one)
- `StructureTemplateDataExportRequestPacket`
- `StructureTemplateDataExportResponsePacket`
# 3.9.1
- Fixed resource packs not working on 1.12 clients.
- Fixed some particles displaying incorrectly (some still don't render at all).
- Fixed `Entity->setFireTicks()` with a value of `0` setting the on-fire flag.
- Silenced a debug message which appeared every time a player right-clicked a block.
- Updated constants for `LevelSoundEventPacket`.
# 3.9.2
- Logger warnings for illegal player movements have been lowered to debug.
- TNT explosions now start from the center instead of the base. This fixes unexpected results when TNT is lit on top of obsidian.
- Fixed the `loadbefore` directive in `plugin.yml` sometimes being ignored.
- Fixed `Item->setCustomName()` with an empty string leaving behind an empty tag.
- Fixed incorrect positioning of bucket empty sound.
- Fixed some incorrect tag parsing in `/give` involving quoted numbers.

View File

@ -17,17 +17,17 @@
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-pthreads": "~3.2.0",
"ext-reflection": "*",
"ext-sockets": "*",
"ext-spl": "*",
"ext-yaml": ">=2.0.0",
"ext-zip": "*",
"ext-zlib": ">=1.2.11",
"pocketmine/raklib": "^0.12.0",
"pocketmine/raklib": "^0.12.5",
"pocketmine/spl": "^0.3.0",
"pocketmine/binaryutils": "^0.1.0",
"pocketmine/nbt": "^0.2.6",
"pocketmine/binaryutils": "^0.1.9",
"pocketmine/nbt": "^0.2.10",
"pocketmine/math": "^0.2.0",
"pocketmine/snooze": "^0.1.0",
"daverandom/callback-validator": "dev-master",

49
composer.lock generated
View File

@ -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": "2f5313e4ebd7b62c785cf683b27464b4",
"content-hash": "377d9e0ab5f1a9a4ef9b664706d26f5b",
"packages": [
{
"name": "adhocore/json-comment",
@ -92,16 +92,16 @@
},
{
"name": "pocketmine/binaryutils",
"version": "0.1.8",
"version": "0.1.9",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BinaryUtils.git",
"reference": "33f511715d22418c03368b49b45a6c25d6b33806"
"reference": "8b3b1160679398387cb896fd5d06018413437dfa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/33f511715d22418c03368b49b45a6c25d6b33806",
"reference": "33f511715d22418c03368b49b45a6c25d6b33806",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/8b3b1160679398387cb896fd5d06018413437dfa",
"reference": "8b3b1160679398387cb896fd5d06018413437dfa",
"shasum": ""
},
"require": {
@ -119,10 +119,10 @@
],
"description": "Classes and methods for conveniently handling binary data",
"support": {
"source": "https://github.com/pmmp/BinaryUtils/tree/0.1.8",
"source": "https://github.com/pmmp/BinaryUtils/tree/0.1.9",
"issues": "https://github.com/pmmp/BinaryUtils/issues"
},
"time": "2019-01-16T17:31:44+00:00"
"time": "2019-07-22T13:15:53+00:00"
},
{
"name": "pocketmine/math",
@ -160,23 +160,23 @@
},
{
"name": "pocketmine/nbt",
"version": "0.2.7",
"version": "0.2.10",
"source": {
"type": "git",
"url": "https://github.com/pmmp/NBT.git",
"reference": "2f176c9f2fd9b31db8bc2ada2f38990157ec8f1a"
"reference": "2db27aebe7dc89772aaa8df53361eef801f60063"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/2f176c9f2fd9b31db8bc2ada2f38990157ec8f1a",
"reference": "2f176c9f2fd9b31db8bc2ada2f38990157ec8f1a",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/2db27aebe7dc89772aaa8df53361eef801f60063",
"reference": "2db27aebe7dc89772aaa8df53361eef801f60063",
"shasum": ""
},
"require": {
"ext-zlib": "*",
"php": ">=7.2.0",
"php-64bit": "*",
"pocketmine/binaryutils": "^0.1.0"
"pocketmine/binaryutils": "^0.1.9"
},
"type": "library",
"autoload": {
@ -194,33 +194,33 @@
],
"description": "PHP library for working with Named Binary Tags",
"support": {
"source": "https://github.com/pmmp/NBT/tree/0.2.7",
"source": "https://github.com/pmmp/NBT/tree/0.2.10",
"issues": "https://github.com/pmmp/NBT/issues"
},
"time": "2019-03-29T19:39:42+00:00"
"time": "2019-07-22T15:22:23+00:00"
},
{
"name": "pocketmine/raklib",
"version": "0.12.4",
"version": "0.12.5",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
"reference": "fc1ccc8e61b9033e5372436b2e28a7a95388373f"
"reference": "874db2d3c24117db2221c1e4550380478aeea852"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/fc1ccc8e61b9033e5372436b2e28a7a95388373f",
"reference": "fc1ccc8e61b9033e5372436b2e28a7a95388373f",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/874db2d3c24117db2221c1e4550380478aeea852",
"reference": "874db2d3c24117db2221c1e4550380478aeea852",
"shasum": ""
},
"require": {
"ext-bcmath": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-pthreads": "~3.2.0",
"ext-sockets": "*",
"php": ">=7.2.0",
"php-64bit": "*",
"php-ipv6": "*",
"pocketmine/binaryutils": "^0.1.0",
"pocketmine/binaryutils": "^0.1.9",
"pocketmine/snooze": "^0.1.0",
"pocketmine/spl": "^0.3.0"
},
@ -235,10 +235,10 @@
],
"description": "A RakNet server implementation written in PHP",
"support": {
"source": "https://github.com/pmmp/RakLib/tree/0.12.4",
"source": "https://github.com/pmmp/RakLib/tree/0.12",
"issues": "https://github.com/pmmp/RakLib/issues"
},
"time": "2019-05-02T14:53:51+00:00"
"time": "2019-07-22T14:38:20+00:00"
},
{
"name": "pocketmine/snooze",
@ -302,7 +302,7 @@
],
"description": "Standard library files required by PocketMine-MP and related projects",
"support": {
"source": "https://github.com/pmmp/SPL/tree/0.3.2"
"source": "https://github.com/pmmp/SPL/tree/master"
},
"time": "2018-08-12T15:17:39+00:00"
}
@ -311,7 +311,6 @@
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"ext-pthreads": 20,
"daverandom/callback-validator": 20
},
"prefer-stable": false,
@ -329,7 +328,7 @@
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-pthreads": "~3.2.0",
"ext-reflection": "*",
"ext-sockets": "*",
"ext-spl": "*",

View File

@ -530,7 +530,7 @@ HIDE_FRIEND_COMPOUNDS = NO
# blocks will be appended to the function's detailed documentation block.
# The default value is: NO.
HIDE_IN_BODY_DOCS = NO
HIDE_IN_BODY_DOCS = YES
# The INTERNAL_DOCS tag determines if documentation that is typed after a
# \internal command is included. If the tag is set to NO then the documentation
@ -600,7 +600,7 @@ SORT_MEMBER_DOCS = YES
# this will also influence the order of the classes in the class list.
# The default value is: NO.
SORT_BRIEF_DOCS = NO
SORT_BRIEF_DOCS = YES
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
# (brief and detailed) documentation of class members so that constructors and
@ -612,7 +612,7 @@ SORT_BRIEF_DOCS = NO
# detailed member documentation.
# The default value is: NO.
SORT_MEMBERS_CTORS_1ST = NO
SORT_MEMBERS_CTORS_1ST = YES
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
# of group names into alphabetical order. If set to NO the group names will
@ -1565,7 +1565,7 @@ MATHJAX_FORMAT = HTML-CSS
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example

View File

@ -99,20 +99,20 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\PlayerNetworkSessionAdapter;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket;
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
use pocketmine\network\mcpe\protocol\AvailableEntityIdentifiersPacket;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket;
use pocketmine\network\mcpe\protocol\BlockEntityDataPacket;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
use pocketmine\network\mcpe\protocol\BookEditPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\InteractPacket;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket;
@ -211,7 +211,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public const VIEW = Player::SPECTATOR;
/**
* Checks a supplied username and checks it is valid.
* Validates the given username.
*
* @param string $name
*
@ -800,7 +800,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
/**
* Gets the "friendly" name to display of this player to use in the chat.
* Returns the "friendly" display name of this player to use in the chat.
*
* @return string
*/
@ -1596,7 +1596,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* If you must tamper with this code, be aware that this can cause very nasty results. Do not waste our time
* asking for help if you suffer the consequences of messing with this.
*/
$this->server->getLogger()->warning($this->getName() . " moved too fast, reverting movement");
$this->server->getLogger()->debug($this->getName() . " moved too fast, reverting movement");
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition);
$revert = true;
}elseif(!$this->level->isInLoadedTerrain($newPos) or !$this->level->isChunkGenerated($newPos->getFloorX() >> 4, $newPos->getFloorZ() >> 4)){
@ -1621,7 +1621,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if(!$ev->isCancelled()){
$revert = true;
$this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidMove", [$this->getName()]));
$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);
}
}
@ -2157,7 +2157,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$pk->worldName = $this->server->getMotd();
$this->dataPacket($pk);
$this->sendDataPacket(new AvailableEntityIdentifiersPacket());
$this->sendDataPacket(new AvailableActorIdentifiersPacket());
$this->sendDataPacket(new BiomeDefinitionListPacket());
$this->level->sendTime($this);
@ -2279,14 +2279,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return true;
}
public function handleEntityEvent(EntityEventPacket $packet) : bool{
public function handleEntityEvent(ActorEventPacket $packet) : bool{
if(!$this->spawned or !$this->isAlive()){
return true;
}
$this->doCloseInventory();
switch($packet->event){
case EntityEventPacket::EATING_ITEM:
case ActorEventPacket::EATING_ITEM:
if($packet->data === 0){
return false;
}
@ -2855,6 +2855,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
case PlayerActionPacket::ACTION_STOP_SWIMMING:
//TODO: handle this when it doesn't spam every damn tick (yet another spam bug!!)
break;
case PlayerActionPacket::ACTION_INTERACT_BLOCK: //ignored (for now)
break;
default:
$this->server->getLogger()->debug("Unhandled/unknown player action type " . $packet->action . " from " . $this->getName());
return false;
@ -2981,7 +2983,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return $handled;
}
public function handleBlockEntityData(BlockEntityDataPacket $packet) : bool{
public function handleBlockEntityData(BlockActorDataPacket $packet) : bool{
if(!$this->spawned or !$this->isAlive()){
return true;
}
@ -3416,7 +3418,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$pk->needsTranslation = true;
$pk->message = $this->server->getLanguage()->translateString($message, $parameters, "pocketmine.");
foreach($parameters as $i => $p){
$parameters[$i] = $this->server->getLanguage()->translateString($p, $parameters, "pocketmine.");
$parameters[$i] = $this->server->getLanguage()->translateString($p, [], "pocketmine.");
}
$pk->parameters = $parameters;
}else{

View File

@ -28,6 +28,7 @@ namespace {
namespace pocketmine {
use pocketmine\utils\Internet;
use pocketmine\utils\MainLogger;
use pocketmine\utils\Process;
use pocketmine\utils\ServerKiller;
@ -103,8 +104,8 @@ namespace pocketmine {
if(substr_count($pthreads_version, ".") < 2){
$pthreads_version = "0.$pthreads_version";
}
if(version_compare($pthreads_version, "3.1.7dev") < 0){
$messages[] = "pthreads >= 3.1.7dev is required, while you have $pthreads_version.";
if(version_compare($pthreads_version, "3.2.0") < 0){
$messages[] = "pthreads >= 3.2.0 is required, while you have $pthreads_version.";
}
}
@ -122,176 +123,180 @@ namespace pocketmine {
return $messages;
}
if(!empty($messages = check_platform_dependencies())){
echo PHP_EOL;
$binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
critical_error("Selected PHP binary ($binary) does not satisfy some requirements.");
foreach($messages as $m){
echo " - $m" . PHP_EOL;
}
critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
echo PHP_EOL;
exit(1);
}
unset($messages);
error_reporting(-1);
if(\Phar::running(true) !== ""){
define('pocketmine\PATH', \Phar::running(true) . "/");
}else{
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
}
$opts = getopt("", ["bootstrap:"]);
if(isset($opts["bootstrap"])){
$bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"];
}else{
$bootstrap = \pocketmine\PATH . 'vendor/autoload.php';
}
define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);
if(\pocketmine\COMPOSER_AUTOLOADER_PATH !== false and is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
}else{
critical_error("Composer autoloader not found at " . $bootstrap);
critical_error("Please install/update Composer dependencies or use provided builds.");
exit(1);
}
set_error_handler([Utils::class, 'errorExceptionHandler']);
/*
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
*/
$autoloader = new \BaseClassLoader();
$autoloader->register(false);
set_time_limit(0); //Who set it to 30 seconds?!?!
ini_set("allow_url_fopen", '1');
ini_set("display_errors", '1');
ini_set("display_startup_errors", '1');
ini_set("default_charset", "utf-8");
ini_set("memory_limit", '-1');
define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'src' . DIRECTORY_SEPARATOR . 'pocketmine' . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR);
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR);
define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
if(!file_exists(\pocketmine\DATA)){
mkdir(\pocketmine\DATA, 0777, true);
}
define('pocketmine\LOCK_FILE_PATH', \pocketmine\DATA . 'server.lock');
define('pocketmine\LOCK_FILE', fopen(\pocketmine\LOCK_FILE_PATH, "a+b"));
if(!flock(\pocketmine\LOCK_FILE, LOCK_EX | LOCK_NB)){
//wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the
//other server wrote its PID and released exclusive lock before we get our lock
flock(\pocketmine\LOCK_FILE, LOCK_SH);
$pid = stream_get_contents(\pocketmine\LOCK_FILE);
critical_error("Another " . \pocketmine\NAME . " instance (PID $pid) is already using this folder (" . realpath(\pocketmine\DATA) . ").");
critical_error("Please stop the other server first before running a new one.");
exit(1);
}
ftruncate(\pocketmine\LOCK_FILE, 0);
fwrite(\pocketmine\LOCK_FILE, (string) getmypid());
fflush(\pocketmine\LOCK_FILE);
flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading
//Logger has a dependency on timezone
$tzError = Timezone::init();
if(isset($opts["enable-ansi"])){
Terminal::init(true);
}elseif(isset($opts["disable-ansi"])){
Terminal::init(false);
}else{
Terminal::init();
}
$logger = new MainLogger(\pocketmine\DATA . "server.log");
$logger->registerStatic();
foreach($tzError as $e){
$logger->warning($e);
}
unset($tzError);
if(extension_loaded("xdebug")){
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running " . \pocketmine\NAME . " with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
}
if(!extension_loaded("pocketmine_chunkutils")){
$logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance.");
}
if(\Phar::running(true) === ""){
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
}
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
define('pocketmine\VERSION', $version->getFullVersion(true));
$gitHash = str_repeat("00", 20);
if(\Phar::running(true) === ""){
if(Process::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){
$gitHash = trim($out);
if(Process::execute("git diff --quiet") === 1 or Process::execute("git diff --cached --quiet") === 1){ //Locally-modified
$gitHash .= "-dirty";
function server(){
if(!empty($messages = check_platform_dependencies())){
echo PHP_EOL;
$binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
critical_error("Selected PHP binary ($binary) does not satisfy some requirements.");
foreach($messages as $m){
echo " - $m" . PHP_EOL;
}
critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
echo PHP_EOL;
exit(1);
}
}else{
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(isset($meta["git"])){
$gitHash = $meta["git"];
unset($messages);
error_reporting(-1);
if(\Phar::running(true) !== ""){
define('pocketmine\PATH', \Phar::running(true) . "/");
}else{
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
}
}
define('pocketmine\GIT_COMMIT', $gitHash);
$opts = getopt("", ["bootstrap:"]);
if(isset($opts["bootstrap"])){
$bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"];
}else{
$bootstrap = \pocketmine\PATH . 'vendor/autoload.php';
}
define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);
if(\pocketmine\COMPOSER_AUTOLOADER_PATH !== false and is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
}else{
critical_error("Composer autoloader not found at " . $bootstrap);
critical_error("Please install/update Composer dependencies or use provided builds.");
exit(1);
}
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
set_error_handler([Utils::class, 'errorExceptionHandler']);
$exitCode = 0;
do{
if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){
$installer = new SetupWizard();
if(!$installer->run()){
$exitCode = -1;
break;
/*
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
*/
$autoloader = new \BaseClassLoader();
$autoloader->register(false);
set_time_limit(0); //Who set it to 30 seconds?!?!
ini_set("allow_url_fopen", '1');
ini_set("display_errors", '1');
ini_set("display_startup_errors", '1');
ini_set("default_charset", "utf-8");
ini_set("memory_limit", '-1');
define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'src' . DIRECTORY_SEPARATOR . 'pocketmine' . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR);
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR);
define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
if(!file_exists(\pocketmine\DATA)){
mkdir(\pocketmine\DATA, 0777, true);
}
define('pocketmine\LOCK_FILE_PATH', \pocketmine\DATA . 'server.lock');
define('pocketmine\LOCK_FILE', fopen(\pocketmine\LOCK_FILE_PATH, "a+b"));
if(!flock(\pocketmine\LOCK_FILE, LOCK_EX | LOCK_NB)){
//wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the
//other server wrote its PID and released exclusive lock before we get our lock
flock(\pocketmine\LOCK_FILE, LOCK_SH);
$pid = stream_get_contents(\pocketmine\LOCK_FILE);
critical_error("Another " . \pocketmine\NAME . " instance (PID $pid) is already using this folder (" . realpath(\pocketmine\DATA) . ").");
critical_error("Please stop the other server first before running a new one.");
exit(1);
}
ftruncate(\pocketmine\LOCK_FILE, 0);
fwrite(\pocketmine\LOCK_FILE, (string) getmypid());
fflush(\pocketmine\LOCK_FILE);
flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading
//Logger has a dependency on timezone
$tzError = Timezone::init();
if(isset($opts["enable-ansi"])){
Terminal::init(true);
}elseif(isset($opts["disable-ansi"])){
Terminal::init(false);
}else{
Terminal::init();
}
$logger = new MainLogger(\pocketmine\DATA . "server.log");
$logger->registerStatic();
foreach($tzError as $e){
$logger->warning($e);
}
unset($tzError);
if(extension_loaded("xdebug")){
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running " . \pocketmine\NAME . " with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
}
if(!extension_loaded("pocketmine_chunkutils")){
$logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance.");
}
if(\Phar::running(true) === ""){
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
}
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
define('pocketmine\VERSION', $version->getFullVersion(true));
$gitHash = str_repeat("00", 20);
if(\Phar::running(true) === ""){
if(Process::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){
$gitHash = trim($out);
if(Process::execute("git diff --quiet") === 1 or Process::execute("git diff --cached --quiet") === 1){ //Locally-modified
$gitHash .= "-dirty";
}
}
}else{
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(isset($meta["git"])){
$gitHash = $meta["git"];
}
}
//TODO: move this to a Server field
define('pocketmine\START_TIME', microtime(true));
ThreadManager::init();
new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
define('pocketmine\GIT_COMMIT', $gitHash);
$logger->info("Stopping other threads");
$killer = new ServerKiller(8);
$killer->start(PTHREADS_INHERIT_NONE);
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
if(ThreadManager::getInstance()->stopAll() > 0){
if(\pocketmine\DEBUG > 1){
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
$exitCode = 0;
do{
if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){
$installer = new SetupWizard();
if(!$installer->run()){
$exitCode = -1;
break;
}
}
Process::kill(getmypid());
}
}while(false);
$logger->shutdown();
$logger->join();
//TODO: move this to a Server field
define('pocketmine\START_TIME', microtime(true));
ThreadManager::init();
new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
echo Terminal::$FORMAT_RESET . PHP_EOL;
$logger->info("Stopping other threads");
exit($exitCode);
$killer = new ServerKiller(8);
$killer->start(PTHREADS_INHERIT_NONE);
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
if(ThreadManager::getInstance()->stopAll() > 0){
if(\pocketmine\DEBUG > 1){
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
}
Process::kill(getmypid());
}
}while(false);
$logger->shutdown();
$logger->join();
echo Terminal::$FORMAT_RESET . PHP_EOL;
exit($exitCode);
}
\pocketmine\server();
}

View File

@ -22,6 +22,6 @@
namespace pocketmine;
const NAME = "PocketMine-MP";
const BASE_VERSION = "3.8.6";
const BASE_VERSION = "3.9.3";
const IS_DEVELOPMENT_BUILD = true;
const BUILD_NUMBER = 0;

View File

@ -32,6 +32,7 @@ use pocketmine\level\sound\FizzSound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use function array_fill;
use function intdiv;
use function lcg_value;
use function min;
@ -372,7 +373,7 @@ abstract class Liquid extends Transparent{
*/
private function getOptimalFlowDirections() : array{
$flowCost = array_fill(0, 4, 1000);
$maxCost = 4 / $this->getFlowDecayPerBlock();
$maxCost = intdiv(4, $this->getFlowDecayPerBlock());
for($j = 0; $j < 4; ++$j){
$x = $this->x;
$y = $this->y;

View File

@ -74,14 +74,14 @@ class FormattedCommandAlias extends Command{
$index = strpos($formatString, '$');
while($index !== false){
$start = $index;
if($index > 0 and $formatString{$start - 1} === "\\"){
if($index > 0 and $formatString[$start - 1] === "\\"){
$formatString = substr($formatString, 0, $start - 1) . substr($formatString, $start);
$index = strpos($formatString, '$', $index);
continue;
}
$required = false;
if($formatString{$index + 1} == '$'){
if($formatString[$index + 1] == '$'){
$required = true;
++$index;
@ -91,7 +91,7 @@ class FormattedCommandAlias extends Command{
$argStart = $index;
while($index < strlen($formatString) and self::inRange(ord($formatString{$index}) - 48, 0, 9)){
while($index < strlen($formatString) and self::inRange(ord($formatString[$index]) - 48, 0, 9)){
++$index;
}
@ -109,7 +109,7 @@ class FormattedCommandAlias extends Command{
$rest = false;
if($index < strlen($formatString) and $formatString{$index} === "-"){
if($index < strlen($formatString) and $formatString[$index] === "-"){
$rest = true;
++$index;
}

View File

@ -65,7 +65,7 @@ abstract class VanillaCommand extends Command{
* @return float
*/
protected function getRelativeDouble(float $original, CommandSender $sender, string $input, float $min = self::MIN_COORD, float $max = self::MAX_COORD) : float{
if($input{0} === "~"){
if($input[0] === "~"){
$value = $this->getDouble($sender, substr($input, 1));
return $original + $value;

View File

@ -62,12 +62,12 @@ use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\AddEntityPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\MoveEntityAbsolutePacket;
use pocketmine\network\mcpe\protocol\RemoveEntityPacket;
use pocketmine\network\mcpe\protocol\SetEntityDataPacket;
use pocketmine\network\mcpe\protocol\SetEntityMotionPacket;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\SetActorDataPacket;
use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
use pocketmine\Player;
use pocketmine\plugin\Plugin;
use pocketmine\Server;
@ -154,70 +154,76 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public const DATA_LEAD_HOLDER_EID = 37; //long
public const DATA_SCALE = 38; //float
public const DATA_HAS_NPC_COMPONENT = 39; //byte (???)
public const DATA_SKIN_ID = 40; //string
public const DATA_NPC_SKIN_ID = 41; //string
public const DATA_URL_TAG = 42; //string
public const DATA_MAX_AIR = 43; //short
public const DATA_MARK_VARIANT = 44; //int
public const DATA_CONTAINER_TYPE = 45; //byte (ContainerComponent)
public const DATA_CONTAINER_BASE_SIZE = 46; //int (ContainerComponent)
public const DATA_CONTAINER_EXTRA_SLOTS_PER_STRENGTH = 47; //int (used for llamas, inventory size is baseSize + thisProp * strength)
public const DATA_BLOCK_TARGET = 48; //block coords (ender crystal)
public const DATA_WITHER_INVULNERABLE_TICKS = 49; //int
public const DATA_WITHER_TARGET_1 = 50; //long
public const DATA_WITHER_TARGET_2 = 51; //long
public const DATA_WITHER_TARGET_3 = 52; //long
/* 53 (short) */
public const DATA_BOUNDING_BOX_WIDTH = 54; //float
public const DATA_BOUNDING_BOX_HEIGHT = 55; //float
public const DATA_FUSE_LENGTH = 56; //int
public const DATA_RIDER_SEAT_POSITION = 57; //vector3f
public const DATA_RIDER_ROTATION_LOCKED = 58; //byte
public const DATA_RIDER_MAX_ROTATION = 59; //float
public const DATA_RIDER_MIN_ROTATION = 60; //float
public const DATA_AREA_EFFECT_CLOUD_RADIUS = 61; //float
public const DATA_AREA_EFFECT_CLOUD_WAITING = 62; //int
public const DATA_AREA_EFFECT_CLOUD_PARTICLE_ID = 63; //int
/* 64 (int) shulker-related */
public const DATA_SHULKER_ATTACH_FACE = 65; //byte
/* 66 (short) shulker-related */
public const DATA_SHULKER_ATTACH_POS = 67; //block coords
public const DATA_TRADING_PLAYER_EID = 68; //long
public const DATA_NPC_SKIN_INDEX = 40; //string
public const DATA_NPC_ACTIONS = 41; //string (maybe JSON blob?)
public const DATA_MAX_AIR = 42; //short
public const DATA_MARK_VARIANT = 43; //int
public const DATA_CONTAINER_TYPE = 44; //byte (ContainerComponent)
public const DATA_CONTAINER_BASE_SIZE = 45; //int (ContainerComponent)
public const DATA_CONTAINER_EXTRA_SLOTS_PER_STRENGTH = 46; //int (used for llamas, inventory size is baseSize + thisProp * strength)
public const DATA_BLOCK_TARGET = 47; //block coords (ender crystal)
public const DATA_WITHER_INVULNERABLE_TICKS = 48; //int
public const DATA_WITHER_TARGET_1 = 49; //long
public const DATA_WITHER_TARGET_2 = 50; //long
public const DATA_WITHER_TARGET_3 = 51; //long
/* 52 (short) */
public const DATA_BOUNDING_BOX_WIDTH = 53; //float
public const DATA_BOUNDING_BOX_HEIGHT = 54; //float
public const DATA_FUSE_LENGTH = 55; //int
public const DATA_RIDER_SEAT_POSITION = 56; //vector3f
public const DATA_RIDER_ROTATION_LOCKED = 57; //byte
public const DATA_RIDER_MAX_ROTATION = 58; //float
public const DATA_RIDER_MIN_ROTATION = 59; //float
public const DATA_AREA_EFFECT_CLOUD_RADIUS = 60; //float
public const DATA_AREA_EFFECT_CLOUD_WAITING = 61; //int
public const DATA_AREA_EFFECT_CLOUD_PARTICLE_ID = 62; //int
/* 63 (int) shulker-related */
public const DATA_SHULKER_ATTACH_FACE = 64; //byte
/* 65 (short) shulker-related */
public const DATA_SHULKER_ATTACH_POS = 66; //block coords
public const DATA_TRADING_PLAYER_EID = 67; //long
/* 70 (byte) command-block */
public const DATA_COMMAND_BLOCK_COMMAND = 71; //string
public const DATA_COMMAND_BLOCK_LAST_OUTPUT = 72; //string
public const DATA_COMMAND_BLOCK_TRACK_OUTPUT = 73; //byte
public const DATA_CONTROLLING_RIDER_SEAT_NUMBER = 74; //byte
public const DATA_STRENGTH = 75; //int
public const DATA_MAX_STRENGTH = 76; //int
/* 77 (int) */
public const DATA_LIMITED_LIFE = 78;
public const DATA_ARMOR_STAND_POSE_INDEX = 79; //int
public const DATA_ENDER_CRYSTAL_TIME_OFFSET = 80; //int
public const DATA_ALWAYS_SHOW_NAMETAG = 81; //byte: -1 = default, 0 = only when looked at, 1 = always
public const DATA_COLOR_2 = 82; //byte
/* 83 (unknown) */
public const DATA_SCORE_TAG = 84; //string
public const DATA_BALLOON_ATTACHED_ENTITY = 85; //int64, entity unique ID of owner
public const DATA_PUFFERFISH_SIZE = 86; //byte
public const DATA_BOAT_BUBBLE_TIME = 87; //int (time in bubble column)
public const DATA_PLAYER_AGENT_EID = 88; //long
/* 89 (float) related to panda sitting
* 90 (float) related to panda sitting */
public const DATA_EAT_COUNTER = 91; //int (used by pandas)
public const DATA_FLAGS2 = 92; //long (extended data flags)
/* 93 (float) related to panda lying down
* 94 (float) related to panda lying down */
public const DATA_AREA_EFFECT_CLOUD_DURATION = 95; //int
public const DATA_AREA_EFFECT_CLOUD_SPAWN_TIME = 96; //int
public const DATA_AREA_EFFECT_CLOUD_RADIUS_PER_TICK = 97; //float, usually negative
public const DATA_AREA_EFFECT_CLOUD_RADIUS_CHANGE_ON_PICKUP = 98; //float
public const DATA_AREA_EFFECT_CLOUD_PICKUP_COUNT = 99; //int
public const DATA_INTERACTIVE_TAG = 100; //string (button text)
public const DATA_TRADE_TIER = 101; //int
public const DATA_MAX_TRADE_TIER = 102; //int
public const DATA_TRADE_XP = 103; //int
/* 69 (byte) command-block */
public const DATA_COMMAND_BLOCK_COMMAND = 70; //string
public const DATA_COMMAND_BLOCK_LAST_OUTPUT = 71; //string
public const DATA_COMMAND_BLOCK_TRACK_OUTPUT = 72; //byte
public const DATA_CONTROLLING_RIDER_SEAT_NUMBER = 73; //byte
public const DATA_STRENGTH = 74; //int
public const DATA_MAX_STRENGTH = 75; //int
/* 76 (int) */
public const DATA_LIMITED_LIFE = 77;
public const DATA_ARMOR_STAND_POSE_INDEX = 78; //int
public const DATA_ENDER_CRYSTAL_TIME_OFFSET = 79; //int
public const DATA_ALWAYS_SHOW_NAMETAG = 80; //byte: -1 = default, 0 = only when looked at, 1 = always
public const DATA_COLOR_2 = 81; //byte
/* 82 (unknown) */
public const DATA_SCORE_TAG = 83; //string
public const DATA_BALLOON_ATTACHED_ENTITY = 84; //int64, entity unique ID of owner
public const DATA_PUFFERFISH_SIZE = 85; //byte
public const DATA_BOAT_BUBBLE_TIME = 86; //int (time in bubble column)
public const DATA_PLAYER_AGENT_EID = 87; //long
/* 88 (float) related to panda sitting
* 89 (float) related to panda sitting */
public const DATA_EAT_COUNTER = 90; //int (used by pandas)
public const DATA_FLAGS2 = 91; //long (extended data flags)
/* 92 (float) related to panda lying down
* 93 (float) related to panda lying down */
public const DATA_AREA_EFFECT_CLOUD_DURATION = 94; //int
public const DATA_AREA_EFFECT_CLOUD_SPAWN_TIME = 95; //int
public const DATA_AREA_EFFECT_CLOUD_RADIUS_PER_TICK = 96; //float, usually negative
public const DATA_AREA_EFFECT_CLOUD_RADIUS_CHANGE_ON_PICKUP = 97; //float
public const DATA_AREA_EFFECT_CLOUD_PICKUP_COUNT = 98; //int
public const DATA_INTERACTIVE_TAG = 99; //string (button text)
public const DATA_TRADE_TIER = 100; //int
public const DATA_MAX_TRADE_TIER = 101; //int
public const DATA_TRADE_XP = 102; //int
public const DATA_SKIN_ID = 103; //int ???
/* 104 (int) related to wither */
public const DATA_COMMAND_BLOCK_TICK_DELAY = 105; //int
public const DATA_COMMAND_BLOCK_EXECUTE_ON_FIRST_TICK = 106; //byte
public const DATA_AMBIENT_SOUND_INTERVAL_MIN = 107; //float
public const DATA_AMBIENT_SOUND_INTERVAL_RANGE = 108; //float
public const DATA_AMBIENT_SOUND_EVENT = 109; //string
public const DATA_FLAG_ONFIRE = 0;
public const DATA_FLAG_SNEAKING = 1;
@ -662,7 +668,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
* @return bool
*/
public function isNameTagAlwaysVisible() : bool{
return $this->getGenericFlag(self::DATA_FLAG_ALWAYS_SHOW_NAMETAG);
return $this->propertyManager->getByte(self::DATA_ALWAYS_SHOW_NAMETAG) === 1;
}
@ -1137,7 +1143,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->setFireTicks($ticks);
}
$this->setGenericFlag(self::DATA_FLAG_ONFIRE, true);
$this->setGenericFlag(self::DATA_FLAG_ONFIRE, $this->isOnFire());
}
/**
@ -1235,7 +1241,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
protected function broadcastMovement(bool $teleport = false) : void{
$pk = new MoveEntityAbsolutePacket();
$pk = new MoveActorAbsolutePacket();
$pk->entityRuntimeId = $this->id;
$pk->position = $this->getOffsetPosition($this);
@ -1247,14 +1253,14 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$pk->zRot = $this->yaw;
if($teleport){
$pk->flags |= MoveEntityAbsolutePacket::FLAG_TELEPORT;
$pk->flags |= MoveActorAbsolutePacket::FLAG_TELEPORT;
}
$this->level->broadcastPacketToViewers($this, $pk);
}
protected function broadcastMotion() : void{
$pk = new SetEntityMotionPacket();
$pk = new SetActorMotionPacket();
$pk->entityRuntimeId = $this->id;
$pk->motion = $this->getMotion();
@ -2021,7 +2027,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
* @param Player $player
*/
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddEntityPacket();
$pk = new AddActorPacket();
$pk->entityRuntimeId = $this->getId();
$pk->type = static::NETWORK_ID;
$pk->position = $this->asVector3();
@ -2071,7 +2077,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public function despawnFrom(Player $player, bool $send = true) : void{
if(isset($this->hasSpawned[$player->getLoaderId()])){
if($send){
$pk = new RemoveEntityPacket();
$pk = new RemoveActorPacket();
$pk->entityUniqueId = $this->id;
$player->dataPacket($pk);
}
@ -2193,7 +2199,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$player = [$player];
}
$pk = new SetEntityDataPacket();
$pk = new SetActorDataPacket();
$pk->entityRuntimeId = $this->getId();
$pk->metadata = $data ?? $this->propertyManager->getAll();
@ -2210,7 +2216,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
public function broadcastEntityEvent(int $eventId, ?int $eventData = null, ?array $players = null) : void{
$pk = new EntityEventPacket();
$pk = new ActorEventPacket();
$pk->entityRuntimeId = $this->id;
$pk->event = $eventId;
$pk->data = $eventData ?? 0;

View File

@ -46,8 +46,8 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
@ -628,7 +628,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
//Old hotbar saving stuff, ignore it
}elseif($slot >= 100 and $slot < 104){ //Armor
$this->armorInventory->setItem($slot - 100, Item::nbtDeserialize($item));
}else{
}elseif($slot >= 9 and $slot < $this->inventory->getSize() + 9){
$this->inventory->setItem($slot - 9, Item::nbtDeserialize($item));
}
}
@ -754,7 +754,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
$this->addEffect(new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 40 * 20, 1));
$this->addEffect(new EffectInstance(Effect::getEffect(Effect::ABSORPTION), 5 * 20, 1));
$this->broadcastEntityEvent(EntityEventPacket::CONSUME_TOTEM);
$this->broadcastEntityEvent(ActorEventPacket::CONSUME_TOTEM);
$this->level->broadcastLevelEvent($this->add(0, $this->eyeHeight, 0), LevelEventPacket::EVENT_SOUND_TOTEM);
$hand = $this->inventory->getItemInHand();

View File

@ -44,7 +44,7 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\MobEffectPacket;
use pocketmine\Player;
@ -143,7 +143,7 @@ abstract class Living extends Entity implements Damageable{
parent::setHealth($amount);
$this->attributeMap->getAttribute(Attribute::HEALTH)->setValue(ceil($this->getHealth()), true);
if($this->isAlive() and !$wasAlive){
$this->broadcastEntityEvent(EntityEventPacket::RESPAWN);
$this->broadcastEntityEvent(ActorEventPacket::RESPAWN);
}
}
@ -541,7 +541,9 @@ abstract class Living extends Entity implements Damageable{
}
public function attack(EntityDamageEvent $source) : void{
if($this->attackTime > 0 or $this->noDamageTicks > 0){
if($this->noDamageTicks > 0){
$source->setCancelled();
}elseif($this->attackTime > 0){
$lastCause = $this->getLastDamageCause();
if($lastCause !== null and $lastCause->getBaseDamage() >= $source->getBaseDamage()){
$source->setCancelled();
@ -604,7 +606,7 @@ abstract class Living extends Entity implements Damageable{
}
protected function doHitAnimation() : void{
$this->broadcastEntityEvent(EntityEventPacket::HURT_ANIMATION);
$this->broadcastEntityEvent(ActorEventPacket::HURT_ANIMATION);
}
public function knockBack(Entity $attacker, float $damage, float $x, float $z, float $base = 0.4) : void{
@ -661,7 +663,7 @@ abstract class Living extends Entity implements Damageable{
}
protected function startDeathAnimation() : void{
$this->broadcastEntityEvent(EntityEventPacket::DEATH_ANIMATION);
$this->broadcastEntityEvent(ActorEventPacket::DEATH_ANIMATION);
}
protected function endDeathAnimation() : void{

View File

@ -28,7 +28,7 @@ use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use function atan2;
use function mt_rand;
use function sqrt;
@ -68,7 +68,7 @@ class Squid extends WaterAnimal{
$this->swimDirection = (new Vector3($this->x - $e->x, $this->y - $e->y, $this->z - $e->z))->normalize();
}
$this->broadcastEntityEvent(EntityEventPacket::SQUID_INK_CLOUD);
$this->broadcastEntityEvent(ActorEventPacket::SQUID_INK_CLOUD);
}
}

View File

@ -28,8 +28,8 @@ use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent;
use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\AddItemEntityPacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\Player;
use function get_class;
@ -192,7 +192,7 @@ class ItemEntity extends Entity{
}
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddItemEntityPacket();
$pk = new AddItemActorPacket();
$pk->entityRuntimeId = $this->getId();
$pk->position = $this->asVector3();
$pk->motion = $this->getMotion();
@ -229,7 +229,7 @@ class ItemEntity extends Entity{
break;
}
$pk = new TakeItemEntityPacket();
$pk = new TakeItemActorPacket();
$pk->eid = $player->getId();
$pk->target = $this->getId();
$this->server->broadcastPacket($this->getViewers(), $pk);

View File

@ -152,9 +152,11 @@ class Painting extends Entity{
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddPaintingPacket();
$pk->entityRuntimeId = $this->getId();
$pk->x = $this->blockIn->x;
$pk->y = $this->blockIn->y;
$pk->z = $this->blockIn->z;
$pk->position = new Vector3(
($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
($this->boundingBox->minY + $this->boundingBox->maxY) / 2,
($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2
);
$pk->direction = $this->direction;
$pk->title = $this->motive;

View File

@ -28,6 +28,7 @@ use pocketmine\entity\Explosive;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ExplosionPrimeEvent;
use pocketmine\level\Explosion;
use pocketmine\level\Position;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
@ -105,7 +106,7 @@ class PrimedTNT extends Entity implements Explosive{
$ev = new ExplosionPrimeEvent($this, 4);
$ev->call();
if(!$ev->isCancelled()){
$explosion = new Explosion($this, $ev->getForce(), $this);
$explosion = new Explosion(Position::fromObject($this->add(0, $this->height / 2, 0), $this->level), $ev->getForce(), $this);
if($ev->isBlockBreaking()){
$explosion->explodeA();
}

View File

@ -32,9 +32,9 @@ use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\math\RayTraceResult;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\Player;
use function mt_rand;
use function sqrt;
@ -143,7 +143,7 @@ class Arrow extends Projectile{
protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{
parent::onHitBlock($blockHit, $hitResult);
$this->broadcastEntityEvent(EntityEventPacket::ARROW_SHAKE, 7); //7 ticks
$this->broadcastEntityEvent(ActorEventPacket::ARROW_SHAKE, 7); //7 ticks
}
protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : void{
@ -193,7 +193,7 @@ class Arrow extends Projectile{
return;
}
$pk = new TakeItemEntityPacket();
$pk = new TakeItemActorPacket();
$pk->eid = $player->getId();
$pk->target = $this->getId();
$this->server->broadcastPacket($this->getViewers(), $pk);

View File

@ -79,8 +79,8 @@ class ShapedRecipe implements CraftingRecipe{
}
for($x = 0; $x < $this->width; ++$x){
if($row{$x} !== ' ' and !isset($ingredients[$row{$x}])){
throw new \InvalidArgumentException("No item specified for symbol '" . $row{$x} . "'");
if($row[$x] !== ' ' and !isset($ingredients[$row[$x]])){
throw new \InvalidArgumentException("No item specified for symbol '" . $row[$x] . "'");
}
}
}

View File

@ -85,7 +85,7 @@ class Bucket extends Item implements Consumable{
$ev->call();
if(!$ev->isCancelled()){
$player->getLevel()->setBlock($blockReplace, $resultBlock->getFlowingForm(), true, true);
$player->getLevel()->broadcastLevelSoundEvent($blockClicked->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
$player->getLevel()->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
if($player->isSurvival()){
$player->getInventory()->setItemInHand($ev->getItem());

View File

@ -467,7 +467,7 @@ class Item implements ItemIds, \JsonSerializable{
*/
public function setCustomName(string $name) : Item{
if($name === ""){
$this->clearCustomName();
return $this->clearCustomName();
}
/** @var CompoundTag $display */

View File

@ -190,7 +190,7 @@ class BaseLang{
$len = strlen($text);
for($i = 0; $i < $len; ++$i){
$c = $text{$i};
$c = $text[$i];
if($replaceString !== null){
$ord = ord($c);
if(

View File

@ -72,7 +72,7 @@ use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\AddEntityPacket;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
@ -564,7 +564,7 @@ class Level implements ChunkManager, Metadatable{
$pk = new LevelSoundEventPacket();
$pk->sound = $soundId;
$pk->extraData = $extraData;
$pk->entityType = AddEntityPacket::LEGACY_ID_MAP_BC[$entityTypeId] ?? ":";
$pk->entityType = AddActorPacket::LEGACY_ID_MAP_BC[$entityTypeId] ?? ":";
$pk->isBabyMob = $isBabyMob;
$pk->disableRelativeVolume = $disableRelativeVolume;
$pk->position = $pos->asVector3();

View File

@ -460,7 +460,7 @@ class Chunk{
* @return int 0-255
*/
public function getBiomeId(int $x, int $z) : int{
return ord($this->biomeIds{($z << 4) | $x});
return ord($this->biomeIds[($z << 4) | $x]);
}
/**
@ -472,7 +472,7 @@ class Chunk{
*/
public function setBiomeId(int $x, int $z, int $biomeId){
$this->hasChanged = true;
$this->biomeIds{($z << 4) | $x} = chr($biomeId & 0xff);
$this->biomeIds[($z << 4) | $x] = chr($biomeId & 0xff);
}
/**
@ -869,13 +869,10 @@ class Chunk{
public function networkSerialize() : string{
$result = "";
$subChunkCount = $this->getSubChunkSendCount();
$result .= chr($subChunkCount);
for($y = 0; $y < $subChunkCount; ++$y){
$result .= $this->subChunks[$y]->networkSerialize();
}
$result .= pack("v*", ...$this->heightMap)
. $this->biomeIds
. chr(0); //border block array count
$result .= $this->biomeIds . chr(0); //border block array count
//Border block entry format: 1 byte (4 bits X, 4 bits Z). These are however useless since they crash the regular client.
foreach($this->tiles as $tile){

View File

@ -71,31 +71,31 @@ class SubChunk implements SubChunkInterface{
}
public function getBlockId(int $x, int $y, int $z) : int{
return ord($this->ids{($x << 8) | ($z << 4) | $y});
return ord($this->ids[($x << 8) | ($z << 4) | $y]);
}
public function setBlockId(int $x, int $y, int $z, int $id) : bool{
$this->ids{($x << 8) | ($z << 4) | $y} = chr($id);
$this->ids[($x << 8) | ($z << 4) | $y] = chr($id);
return true;
}
public function getBlockData(int $x, int $y, int $z) : int{
return (ord($this->data{($x << 7) | ($z << 3) | ($y >> 1)}) >> (($y & 1) << 2)) & 0xf;
return (ord($this->data[($x << 7) | ($z << 3) | ($y >> 1)]) >> (($y & 1) << 2)) & 0xf;
}
public function setBlockData(int $x, int $y, int $z, int $data) : bool{
$i = ($x << 7) | ($z << 3) | ($y >> 1);
$shift = ($y & 1) << 2;
$byte = ord($this->data{$i});
$this->data{$i} = chr(($byte & ~(0xf << $shift)) | (($data & 0xf) << $shift));
$byte = ord($this->data[$i]);
$this->data[$i] = chr(($byte & ~(0xf << $shift)) | (($data & 0xf) << $shift));
return true;
}
public function getFullBlock(int $x, int $y, int $z) : int{
$i = ($x << 8) | ($z << 4) | $y;
return (ord($this->ids{$i}) << 4) | ((ord($this->data{$i >> 1}) >> (($y & 1) << 2)) & 0xf);
return (ord($this->ids[$i]) << 4) | ((ord($this->data[$i >> 1]) >> (($y & 1) << 2)) & 0xf);
}
public function setBlock(int $x, int $y, int $z, ?int $id = null, ?int $data = null) : bool{
@ -103,8 +103,8 @@ class SubChunk implements SubChunkInterface{
$changed = false;
if($id !== null){
$block = chr($id);
if($this->ids{$i} !== $block){
$this->ids{$i} = $block;
if($this->ids[$i] !== $block){
$this->ids[$i] = $block;
$changed = true;
}
}
@ -113,10 +113,10 @@ class SubChunk implements SubChunkInterface{
$i >>= 1;
$shift = ($y & 1) << 2;
$oldPair = ord($this->data{$i});
$oldPair = ord($this->data[$i]);
$newPair = ($oldPair & ~(0xf << $shift)) | (($data & 0xf) << $shift);
if($newPair !== $oldPair){
$this->data{$i} = chr($newPair);
$this->data[$i] = chr($newPair);
$changed = true;
}
}
@ -125,29 +125,29 @@ class SubChunk implements SubChunkInterface{
}
public function getBlockLight(int $x, int $y, int $z) : int{
return (ord($this->blockLight{($x << 7) | ($z << 3) | ($y >> 1)}) >> (($y & 1) << 2)) & 0xf;
return (ord($this->blockLight[($x << 7) | ($z << 3) | ($y >> 1)]) >> (($y & 1) << 2)) & 0xf;
}
public function setBlockLight(int $x, int $y, int $z, int $level) : bool{
$i = ($x << 7) | ($z << 3) | ($y >> 1);
$shift = ($y & 1) << 2;
$byte = ord($this->blockLight{$i});
$this->blockLight{$i} = chr(($byte & ~(0xf << $shift)) | (($level & 0xf) << $shift));
$byte = ord($this->blockLight[$i]);
$this->blockLight[$i] = chr(($byte & ~(0xf << $shift)) | (($level & 0xf) << $shift));
return true;
}
public function getBlockSkyLight(int $x, int $y, int $z) : int{
return (ord($this->skyLight{($x << 7) | ($z << 3) | ($y >> 1)}) >> (($y & 1) << 2)) & 0xf;
return (ord($this->skyLight[($x << 7) | ($z << 3) | ($y >> 1)]) >> (($y & 1) << 2)) & 0xf;
}
public function setBlockSkyLight(int $x, int $y, int $z, int $level) : bool{
$i = ($x << 7) | ($z << 3) | ($y >> 1);
$shift = ($y & 1) << 2;
$byte = ord($this->skyLight{$i});
$this->skyLight{$i} = chr(($byte & ~(0xf << $shift)) | (($level & 0xf) << $shift));
$byte = ord($this->skyLight[$i]);
$this->skyLight[$i] = chr(($byte & ~(0xf << $shift)) | (($level & 0xf) << $shift));
return true;
}
@ -156,7 +156,7 @@ class SubChunk implements SubChunkInterface{
$low = ($x << 8) | ($z << 4);
$i = $low | 0x0f;
for(; $i >= $low; --$i){
if($this->ids{$i} !== "\x00"){
if($this->ids[$i] !== "\x00"){
return $i & 0x0f;
}
}

View File

@ -26,7 +26,7 @@ namespace pocketmine\level\format\io;
use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\FullChunkDataPacket;
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
use pocketmine\scheduler\AsyncTask;
use pocketmine\Server;
use function assert;
@ -42,6 +42,9 @@ class ChunkRequestTask extends AsyncTask{
protected $compressionLevel;
/** @var int */
private $subChunkCount;
public function __construct(Level $level, int $chunkX, int $chunkZ, Chunk $chunk){
$this->levelId = $level->getId();
$this->compressionLevel = $level->getServer()->networkCompressionLevel;
@ -49,13 +52,11 @@ class ChunkRequestTask extends AsyncTask{
$this->chunk = $chunk->networkSerialize();
$this->chunkX = $chunkX;
$this->chunkZ = $chunkZ;
$this->subChunkCount = $chunk->getSubChunkSendCount();
}
public function onRun(){
$pk = new FullChunkDataPacket();
$pk->chunkX = $this->chunkX;
$pk->chunkZ = $this->chunkZ;
$pk->data = $this->chunk;
$pk = LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $this->subChunkCount, $this->chunk);
$batch = new BatchPacket();
$batch->addPacket($pk);

View File

@ -47,7 +47,7 @@ if(!extension_loaded('pocketmine_chunkutils')){
for($z = $x; $z < $zM; $z += 16){
$yM = $z + 4096;
for($y = $z; $y < $yM; $y += 256){
$result{$i} = $array{$y};
$result[$i] = $array[$y];
++$i;
}
}
@ -76,13 +76,13 @@ if(!extension_loaded('pocketmine_chunkutils')){
for($y = 0; $y < 8; ++$y){
$j = (($y << 8) | $zx);
$j80 = ($j | 0x80);
if($array{$j} === $commonValue and $array{$j80} === $commonValue){
if($array[$j] === $commonValue and $array[$j80] === $commonValue){
//values are already filled
}else{
$i1 = ord($array{$j});
$i2 = ord($array{$j80});
$result{$i} = chr(($i2 << 4) | ($i1 & 0x0f));
$result{$i | 0x80} = chr(($i1 >> 4) | ($i2 & 0xf0));
$i1 = ord($array[$j]);
$i2 = ord($array[$j80]);
$result[$i] = chr(($i2 << 4) | ($i1 & 0x0f));
$result[$i | 0x80] = chr(($i1 >> 4) | ($i2 & 0xf0));
}
$i++;
}
@ -104,7 +104,7 @@ if(!extension_loaded('pocketmine_chunkutils')){
public static function convertBiomeColors(array $array) : string{
$result = str_repeat("\x00", 256);
foreach($array as $i => $color){
$result{$i} = chr(($color >> 24) & 0xff);
$result[$i] = chr(($color >> 24) & 0xff);
}
return $result;
}

View File

@ -30,7 +30,7 @@ use pocketmine\level\ChunkManager;
use pocketmine\math\Vector3;
use pocketmine\utils\Random;
use pocketmine\utils\Utils;
use function ctype_digit;
use function preg_match;
abstract class Generator{
@ -44,7 +44,7 @@ abstract class Generator{
public static function convertSeed(string $seed) : ?int{
if($seed === ""){ //empty seed should cause a random seed to be selected - can't use 0 here because 0 is a valid seed
$convertedSeed = null;
}elseif(ctype_digit($seed)){ //this avoids treating seeds like "404.4" as integer seeds
}elseif(preg_match('/^-?\d+$/', $seed) === 1){ //this avoids treating seeds like "404.4" as integer seeds
$convertedSeed = (int) $seed;
}else{
$convertedSeed = Utils::javaStringHash($seed);

View File

@ -48,7 +48,7 @@ class GroundCover extends Populator{
$column = $chunk->getBlockIdColumn($x, $z);
for($y = 127; $y > 0; --$y){
if($column{$y} !== "\x00" and !BlockFactory::get(ord($column{$y}))->isTransparent()){
if($column[$y] !== "\x00" and !BlockFactory::get(ord($column[$y]))->isTransparent()){
break;
}
}
@ -56,10 +56,10 @@ class GroundCover extends Populator{
$endY = $startY - count($cover);
for($y = $startY; $y > $endY and $y >= 0; --$y){
$b = $cover[$startY - $y];
if($column{$y} === "\x00" and $b->isSolid()){
if($column[$y] === "\x00" and $b->isSolid()){
break;
}
if($b->canBeFlowedInto() and BlockFactory::get(ord($column{$y})) instanceof Liquid){
if($b->canBeFlowedInto() and BlockFactory::get(ord($column[$y])) instanceof Liquid){
continue;
}
if($b->getDamage() === 0){

View File

@ -30,7 +30,7 @@ use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\RemoveEntityPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\utils\UUID;
use function str_repeat;
@ -84,7 +84,7 @@ class FloatingTextParticle extends Particle{
if($this->entityId === null){
$this->entityId = Entity::$entityCount++;
}else{
$pk0 = new RemoveEntityPacket();
$pk0 = new RemoveActorPacket();
$pk0->entityUniqueId = $this->entityId;
$p[] = $pk0;

View File

@ -29,59 +29,67 @@ use pocketmine\network\mcpe\protocol\DataPacket;
abstract class Particle extends Vector3{
public const TYPE_BUBBLE = 1;
public const TYPE_CRITICAL = 2;
public const TYPE_BLOCK_FORCE_FIELD = 3;
public const TYPE_SMOKE = 4;
public const TYPE_EXPLODE = 5;
public const TYPE_EVAPORATION = 6;
public const TYPE_FLAME = 7;
public const TYPE_LAVA = 8;
public const TYPE_LARGE_SMOKE = 9;
public const TYPE_REDSTONE = 10;
public const TYPE_RISING_RED_DUST = 11;
public const TYPE_ITEM_BREAK = 12;
public const TYPE_SNOWBALL_POOF = 13;
public const TYPE_HUGE_EXPLODE = 14;
public const TYPE_HUGE_EXPLODE_SEED = 15;
public const TYPE_MOB_FLAME = 16;
public const TYPE_HEART = 17;
public const TYPE_TERRAIN = 18;
public const TYPE_SUSPENDED_TOWN = 19, TYPE_TOWN_AURA = 19;
public const TYPE_PORTAL = 20;
public const TYPE_SPLASH = 21, TYPE_WATER_SPLASH = 21;
public const TYPE_WATER_WAKE = 22;
public const TYPE_DRIP_WATER = 23;
public const TYPE_DRIP_LAVA = 24;
public const TYPE_FALLING_DUST = 25, TYPE_DUST = 25;
public const TYPE_MOB_SPELL = 26;
public const TYPE_MOB_SPELL_AMBIENT = 27;
public const TYPE_MOB_SPELL_INSTANTANEOUS = 28;
public const TYPE_INK = 29;
public const TYPE_SLIME = 30;
public const TYPE_RAIN_SPLASH = 31;
public const TYPE_VILLAGER_ANGRY = 32;
public const TYPE_VILLAGER_HAPPY = 33;
public const TYPE_ENCHANTMENT_TABLE = 34;
public const TYPE_TRACKING_EMITTER = 35;
public const TYPE_NOTE = 36;
public const TYPE_WITCH_SPELL = 37;
public const TYPE_CARROT = 38;
//39 unknown
public const TYPE_END_ROD = 40;
public const TYPE_DRAGONS_BREATH = 41;
public const TYPE_SPIT = 42;
public const TYPE_TOTEM = 43;
public const TYPE_FOOD = 44;
public const TYPE_FIREWORKS_STARTER = 45;
public const TYPE_FIREWORKS_SPARK = 46;
public const TYPE_FIREWORKS_OVERLAY = 47;
public const TYPE_BALLOON_GAS = 48;
public const TYPE_COLORED_FLAME = 49;
public const TYPE_SPARKLER = 50;
public const TYPE_CONDUIT = 51;
public const TYPE_BUBBLE_COLUMN_UP = 52;
public const TYPE_BUBBLE_COLUMN_DOWN = 53;
public const TYPE_SNEEZE = 54;
//2 same as 1
public const TYPE_CRITICAL = 3;
public const TYPE_BLOCK_FORCE_FIELD = 4;
public const TYPE_SMOKE = 5;
public const TYPE_EXPLODE = 6;
public const TYPE_EVAPORATION = 7;
public const TYPE_FLAME = 8;
public const TYPE_LAVA = 9;
public const TYPE_LARGE_SMOKE = 10;
public const TYPE_REDSTONE = 11;
public const TYPE_RISING_RED_DUST = 12;
//62 same as 12
public const TYPE_ITEM_BREAK = 13;
public const TYPE_SNOWBALL_POOF = 14;
public const TYPE_HUGE_EXPLODE = 15;
//60 same as 15
public const TYPE_HUGE_EXPLODE_SEED = 16;
public const TYPE_MOB_FLAME = 17;
public const TYPE_HEART = 18;
public const TYPE_TERRAIN = 19;
public const TYPE_SUSPENDED_TOWN = 20, TYPE_TOWN_AURA = 20;
//61 same as 20
public const TYPE_PORTAL = 21;
//22 same as 21
public const TYPE_SPLASH = 23, TYPE_WATER_SPLASH = 23;
//24 same as 23
public const TYPE_WATER_WAKE = 25;
public const TYPE_DRIP_WATER = 26;
public const TYPE_DRIP_LAVA = 27;
public const TYPE_FALLING_DUST = 28, TYPE_DUST = 28;
public const TYPE_MOB_SPELL = 29;
public const TYPE_MOB_SPELL_AMBIENT = 30;
public const TYPE_MOB_SPELL_INSTANTANEOUS = 31;
public const TYPE_INK = 32;
public const TYPE_SLIME = 33;
public const TYPE_RAIN_SPLASH = 34;
public const TYPE_VILLAGER_ANGRY = 35;
//59 same as 35
public const TYPE_VILLAGER_HAPPY = 36;
public const TYPE_ENCHANTMENT_TABLE = 37;
public const TYPE_TRACKING_EMITTER = 38;
public const TYPE_NOTE = 39;
public const TYPE_WITCH_SPELL = 40;
public const TYPE_CARROT = 41;
//42 unknown
public const TYPE_END_ROD = 43;
//58 same as 43
public const TYPE_DRAGONS_BREATH = 44;
public const TYPE_SPIT = 45;
public const TYPE_TOTEM = 46;
public const TYPE_FOOD = 47;
public const TYPE_FIREWORKS_STARTER = 48;
public const TYPE_FIREWORKS_SPARK = 49;
public const TYPE_FIREWORKS_OVERLAY = 50;
public const TYPE_BALLOON_GAS = 51;
public const TYPE_COLORED_FLAME = 52;
public const TYPE_SPARKLER = 53;
public const TYPE_CONDUIT = 54;
public const TYPE_BUBBLE_COLUMN_UP = 55;
public const TYPE_BUBBLE_COLUMN_DOWN = 56;
public const TYPE_SNEEZE = 57;
/**
* @return DataPacket|DataPacket[]

View File

@ -27,12 +27,14 @@ namespace pocketmine\network\mcpe;
use pocketmine\entity\Attribute;
use pocketmine\entity\Entity;
use pocketmine\item\Durable;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\ItemIds;
use pocketmine\math\Vector3;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\utils\BinaryStream;
@ -42,6 +44,9 @@ use function strlen;
class NetworkBinaryStream extends BinaryStream{
private const DAMAGE_TAG = "Damage"; //TAG_Int
private const DAMAGE_TAG_CONFLICT_RESOLUTION = "___Damage_ProtocolCollisionResolution___";
public function getString() : string{
return $this->get($this->getUnsignedVarInt());
}
@ -76,15 +81,12 @@ class NetworkBinaryStream extends BinaryStream{
$auxValue = $this->getVarInt();
$data = $auxValue >> 8;
if($data === 0x7fff){
$data = -1;
}
$cnt = $auxValue & 0xff;
$nbtLen = $this->getLShort();
/** @var CompoundTag|string $nbt */
$nbt = "";
/** @var CompoundTag|null $nbt */
$nbt = null;
if($nbtLen === 0xffff){
$c = $this->getByte();
if($c !== 1){
@ -108,7 +110,22 @@ class NetworkBinaryStream extends BinaryStream{
if($id === ItemIds::SHIELD){
$this->getVarLong(); //"blocking tick" (ffs mojang)
}
if($nbt !== null){
if($nbt->hasTag(self::DAMAGE_TAG, IntTag::class)){
$data = $nbt->getInt(self::DAMAGE_TAG);
$nbt->removeTag(self::DAMAGE_TAG);
if($nbt->count() === 0){
$nbt = null;
goto end;
}
}
if(($conflicted = $nbt->getTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION)) !== null){
$nbt->removeTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
$conflicted->setName(self::DAMAGE_TAG);
$nbt->setTag($conflicted);
}
}
end:
return ItemFactory::get($id, $data, $cnt, $nbt);
}
@ -124,10 +141,27 @@ class NetworkBinaryStream extends BinaryStream{
$auxValue = (($item->getDamage() & 0x7fff) << 8) | $item->getCount();
$this->putVarInt($auxValue);
$nbt = null;
if($item->hasCompoundTag()){
$nbt = clone $item->getNamedTag();
}
if($item instanceof Durable and $item->getDamage() > 0){
if($nbt !== null){
if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){
$nbt->removeTag(self::DAMAGE_TAG);
$existing->setName(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
$nbt->setTag($existing);
}
}else{
$nbt = new CompoundTag();
}
$nbt->setInt(self::DAMAGE_TAG, $item->getDamage());
}
if($nbt !== null){
$this->putLShort(0xffff);
$this->putByte(1); //TODO: some kind of count field? always 1 as of 1.9.0
$this->put((new NetworkLittleEndianNBTStream())->write($item->getNamedTag()));
$this->put((new NetworkLittleEndianNBTStream())->write($nbt));
}else{
$this->putLShort(0);
}
@ -140,6 +174,29 @@ class NetworkBinaryStream extends BinaryStream{
}
}
public function getRecipeIngredient() : Item{
$id = $this->getVarInt();
if($id === 0){
return ItemFactory::get(ItemIds::AIR, 0, 0);
}
$meta = $this->getVarInt();
if($meta === 0x7fff){
$meta = -1;
}
$count = $this->getVarInt();
return ItemFactory::get($id, $meta, $count);
}
public function putRecipeIngredient(Item $item) : void{
if($item->isNull()){
$this->putVarInt(0);
}else{
$this->putVarInt($item->getId());
$this->putVarInt($item->getDamage() & 0x7fff);
$this->putVarInt($item->getCount());
}
}
/**
* Decodes entity metadata from the stream.
*

View File

@ -23,18 +23,22 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\ActorFallPacket;
use pocketmine\network\mcpe\protocol\ActorPickRequestPacket;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\AddBehaviorTreePacket;
use pocketmine\network\mcpe\protocol\AddEntityPacket;
use pocketmine\network\mcpe\protocol\AddItemEntityPacket;
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\AddPaintingPacket;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\AutomationClientConnectPacket;
use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket;
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
use pocketmine\network\mcpe\protocol\AvailableEntityIdentifiersPacket;
use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket;
use pocketmine\network\mcpe\protocol\BlockEntityDataPacket;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\BlockEventPacket;
use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
use pocketmine\network\mcpe\protocol\BookEditPacket;
@ -43,6 +47,9 @@ use pocketmine\network\mcpe\protocol\CameraPacket;
use pocketmine\network\mcpe\protocol\ChangeDimensionPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
use pocketmine\network\mcpe\protocol\ClientboundMapItemDataPacket;
use pocketmine\network\mcpe\protocol\ClientCacheBlobStatusPacket;
use pocketmine\network\mcpe\protocol\ClientCacheMissResponsePacket;
use pocketmine\network\mcpe\protocol\ClientCacheStatusPacket;
use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket;
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\CommandOutputPacket;
@ -54,12 +61,8 @@ use pocketmine\network\mcpe\protocol\CraftingDataPacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\EntityFallPacket;
use pocketmine\network\mcpe\protocol\EntityPickRequestPacket;
use pocketmine\network\mcpe\protocol\EventPacket;
use pocketmine\network\mcpe\protocol\ExplodePacket;
use pocketmine\network\mcpe\protocol\FullChunkDataPacket;
use pocketmine\network\mcpe\protocol\GameRulesChangedPacket;
use pocketmine\network\mcpe\protocol\GuiDataPickItemPacket;
use pocketmine\network\mcpe\protocol\HurtArmorPacket;
@ -70,6 +73,8 @@ use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket;
use pocketmine\network\mcpe\protocol\LabTablePacket;
use pocketmine\network\mcpe\protocol\LecternUpdatePacket;
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
use pocketmine\network\mcpe\protocol\LevelEventGenericPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacketV1;
@ -82,8 +87,8 @@ use pocketmine\network\mcpe\protocol\MobEffectPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
use pocketmine\network\mcpe\protocol\ModalFormResponsePacket;
use pocketmine\network\mcpe\protocol\MoveEntityAbsolutePacket;
use pocketmine\network\mcpe\protocol\MoveEntityDeltaPacket;
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
use pocketmine\network\mcpe\protocol\MoveActorDeltaPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
@ -98,6 +103,7 @@ use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\PlaySoundPacket;
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
use pocketmine\network\mcpe\protocol\PurchaseReceiptPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\RemoveEntityPacket;
use pocketmine\network\mcpe\protocol\RemoveObjectivePacket;
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
@ -113,13 +119,13 @@ use pocketmine\network\mcpe\protocol\ScriptCustomEventPacket;
use pocketmine\network\mcpe\protocol\ServerSettingsRequestPacket;
use pocketmine\network\mcpe\protocol\ServerSettingsResponsePacket;
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
use pocketmine\network\mcpe\protocol\SetActorDataPacket;
use pocketmine\network\mcpe\protocol\SetActorLinkPacket;
use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
use pocketmine\network\mcpe\protocol\SetCommandsEnabledPacket;
use pocketmine\network\mcpe\protocol\SetDefaultGameTypePacket;
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
use pocketmine\network\mcpe\protocol\SetDisplayObjectivePacket;
use pocketmine\network\mcpe\protocol\SetEntityDataPacket;
use pocketmine\network\mcpe\protocol\SetEntityLinkPacket;
use pocketmine\network\mcpe\protocol\SetEntityMotionPacket;
use pocketmine\network\mcpe\protocol\SetHealthPacket;
use pocketmine\network\mcpe\protocol\SetLastHurtByPacket;
use pocketmine\network\mcpe\protocol\SetLocalPlayerAsInitializedPacket;
@ -138,12 +144,15 @@ use pocketmine\network\mcpe\protocol\SpawnParticleEffectPacket;
use pocketmine\network\mcpe\protocol\StartGamePacket;
use pocketmine\network\mcpe\protocol\StopSoundPacket;
use pocketmine\network\mcpe\protocol\StructureBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataExportRequestPacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataExportResponsePacket;
use pocketmine\network\mcpe\protocol\SubClientLoginPacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\TransferPacket;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPropertiesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockSyncedPacket;
use pocketmine\network\mcpe\protocol\UpdateEquipPacket;
use pocketmine\network\mcpe\protocol\UpdateSoftEnumPacket;
@ -202,23 +211,23 @@ abstract class NetworkSession{
return false;
}
public function handleAddEntity(AddEntityPacket $packet) : bool{
public function handleAddActor(AddActorPacket $packet) : bool{
return false;
}
public function handleRemoveEntity(RemoveEntityPacket $packet) : bool{
public function handleRemoveActor(RemoveActorPacket $packet) : bool{
return false;
}
public function handleAddItemEntity(AddItemEntityPacket $packet) : bool{
public function handleAddItemActor(AddItemActorPacket $packet) : bool{
return false;
}
public function handleTakeItemEntity(TakeItemEntityPacket $packet) : bool{
public function handleTakeItemActor(TakeItemActorPacket $packet) : bool{
return false;
}
public function handleMoveEntityAbsolute(MoveEntityAbsolutePacket $packet) : bool{
public function handleMoveActorAbsolute(MoveActorAbsolutePacket $packet) : bool{
return false;
}
@ -254,7 +263,7 @@ abstract class NetworkSession{
return false;
}
public function handleEntityEvent(EntityEventPacket $packet) : bool{
public function handleActorEvent(ActorEventPacket $packet) : bool{
return false;
}
@ -286,7 +295,7 @@ abstract class NetworkSession{
return false;
}
public function handleEntityPickRequest(EntityPickRequestPacket $packet) : bool{
public function handleActorPickRequest(ActorPickRequestPacket $packet) : bool{
return false;
}
@ -294,7 +303,7 @@ abstract class NetworkSession{
return false;
}
public function handleEntityFall(EntityFallPacket $packet) : bool{
public function handleActorFall(ActorFallPacket $packet) : bool{
return false;
}
@ -302,15 +311,15 @@ abstract class NetworkSession{
return false;
}
public function handleSetEntityData(SetEntityDataPacket $packet) : bool{
public function handleSetActorData(SetActorDataPacket $packet) : bool{
return false;
}
public function handleSetEntityMotion(SetEntityMotionPacket $packet) : bool{
public function handleSetActorMotion(SetActorMotionPacket $packet) : bool{
return false;
}
public function handleSetEntityLink(SetEntityLinkPacket $packet) : bool{
public function handleSetActorLink(SetActorLinkPacket $packet) : bool{
return false;
}
@ -370,7 +379,7 @@ abstract class NetworkSession{
return false;
}
public function handleBlockEntityData(BlockEntityDataPacket $packet) : bool{
public function handleBlockActorData(BlockActorDataPacket $packet) : bool{
return false;
}
@ -378,7 +387,7 @@ abstract class NetworkSession{
return false;
}
public function handleFullChunkData(FullChunkDataPacket $packet) : bool{
public function handleLevelChunk(LevelChunkPacket $packet) : bool{
return false;
}
@ -590,7 +599,7 @@ abstract class NetworkSession{
return false;
}
public function handleMoveEntityDelta(MoveEntityDeltaPacket $packet) : bool{
public function handleMoveActorDelta(MoveActorDeltaPacket $packet) : bool{
return false;
}
@ -618,7 +627,7 @@ abstract class NetworkSession{
return false;
}
public function handleAvailableEntityIdentifiers(AvailableEntityIdentifiersPacket $packet) : bool{
public function handleAvailableActorIdentifiers(AvailableActorIdentifiersPacket $packet) : bool{
return false;
}
@ -638,6 +647,10 @@ abstract class NetworkSession{
return false;
}
public function handleLevelEventGeneric(LevelEventGenericPacket $packet) : bool{
return false;
}
public function handleLecternUpdate(LecternUpdatePacket $packet) : bool{
return false;
}
@ -646,11 +659,43 @@ abstract class NetworkSession{
return false;
}
public function handleMapCreateLockedCopy(MapCreateLockedCopyPacket $packet) : bool{
public function handleAddEntity(AddEntityPacket $packet) : bool{
return false;
}
public function handleRemoveEntity(RemoveEntityPacket $packet) : bool{
return false;
}
public function handleClientCacheStatus(ClientCacheStatusPacket $packet) : bool{
return false;
}
public function handleOnScreenTextureAnimation(OnScreenTextureAnimationPacket $packet) : bool{
return false;
}
public function handleMapCreateLockedCopy(MapCreateLockedCopyPacket $packet) : bool{
return false;
}
public function handleStructureTemplateDataExportRequest(StructureTemplateDataExportRequestPacket $packet) : bool{
return false;
}
public function handleStructureTemplateDataExportResponse(StructureTemplateDataExportResponsePacket $packet) : bool{
return false;
}
public function handleUpdateBlockProperties(UpdateBlockPropertiesPacket $packet) : bool{
return false;
}
public function handleClientCacheBlobStatus(ClientCacheBlobStatusPacket $packet) : bool{
return false;
}
public function handleClientCacheMissResponse(ClientCacheMissResponsePacket $packet) : bool{
return false;
}
}

View File

@ -25,9 +25,12 @@ namespace pocketmine\network\mcpe;
use pocketmine\event\server\DataPacketReceiveEvent;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\ActorFallPacket;
use pocketmine\network\mcpe\protocol\ActorPickRequestPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\BlockEntityDataPacket;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
use pocketmine\network\mcpe\protocol\BookEditPacket;
use pocketmine\network\mcpe\protocol\BossEventPacket;
@ -37,9 +40,6 @@ use pocketmine\network\mcpe\protocol\CommandRequestPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
use pocketmine\network\mcpe\protocol\EntityFallPacket;
use pocketmine\network\mcpe\protocol\EntityPickRequestPacket;
use pocketmine\network\mcpe\protocol\InteractPacket;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket;
@ -142,7 +142,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
return true; //useless leftover from 1.8
}
public function handleEntityEvent(EntityEventPacket $packet) : bool{
public function handleActorEvent(ActorEventPacket $packet) : bool{
return $this->player->handleEntityEvent($packet);
}
@ -166,7 +166,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
return $this->player->handleBlockPickRequest($packet);
}
public function handleEntityPickRequest(EntityPickRequestPacket $packet) : bool{
public function handleActorPickRequest(ActorPickRequestPacket $packet) : bool{
return false; //TODO
}
@ -174,7 +174,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
return $this->player->handlePlayerAction($packet);
}
public function handleEntityFall(EntityFallPacket $packet) : bool{
public function handleActorFall(ActorFallPacket $packet) : bool{
return true; //Not used
}
@ -198,7 +198,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
return $this->player->handleAdventureSettings($packet);
}
public function handleBlockEntityData(BlockEntityDataPacket $packet) : bool{
public function handleBlockActorData(BlockActorDataPacket $packet) : bool{
return $this->player->handleBlockEntityData($packet);
}

View File

@ -120,12 +120,12 @@ class VerifyLoginTask extends AsyncTask{
[$rString, $sString] = str_split($plainSignature, 48);
$rString = ltrim($rString, "\x00");
if(ord($rString{0}) >= 128){ //Would be considered signed, pad it with an extra zero
if(ord($rString[0]) >= 128){ //Would be considered signed, pad it with an extra zero
$rString = "\x00" . $rString;
}
$sString = ltrim($sString, "\x00");
if(ord($sString{0}) >= 128){ //Would be considered signed, pad it with an extra zero
if(ord($sString[0]) >= 128){ //Would be considered signed, pad it with an extra zero
$sString = "\x00" . $sString;
}

View File

@ -28,8 +28,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class EntityEventPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ENTITY_EVENT_PACKET;
class ActorEventPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ACTOR_EVENT_PACKET;
public const HURT_ANIMATION = 2;
public const DEATH_ANIMATION = 3;
@ -103,6 +103,6 @@ class EntityEventPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleEntityEvent($this);
return $session->handleActorEvent($this);
}
}

View File

@ -28,8 +28,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class EntityFallPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ENTITY_FALL_PACKET;
class ActorFallPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ACTOR_FALL_PACKET;
/** @var int */
public $entityRuntimeId;
@ -51,6 +51,6 @@ class EntityFallPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleEntityFall($this);
return $session->handleActorFall($this);
}
}

View File

@ -27,8 +27,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class EntityPickRequestPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ENTITY_PICK_REQUEST_PACKET;
class ActorPickRequestPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ACTOR_PICK_REQUEST_PACKET;
/** @var int */
public $entityUniqueId;
@ -46,6 +46,6 @@ class EntityPickRequestPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleEntityPickRequest($this);
return $session->handleActorPickRequest($this);
}
}

View File

@ -0,0 +1,240 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\entity\Attribute;
use pocketmine\entity\EntityIds;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use function array_search;
use function count;
class AddActorPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ADD_ACTOR_PACKET;
/*
* Really really really really really nasty hack, to preserve backwards compatibility.
* We can't transition to string IDs within 3.x because the network IDs (the integer ones) are exposed
* to the API in some places (for god's sake shoghi).
*
* TODO: remove this on 4.0
*/
public const LEGACY_ID_MAP_BC = [
EntityIds::NPC => "minecraft:npc",
EntityIds::PLAYER => "minecraft:player",
EntityIds::WITHER_SKELETON => "minecraft:wither_skeleton",
EntityIds::HUSK => "minecraft:husk",
EntityIds::STRAY => "minecraft:stray",
EntityIds::WITCH => "minecraft:witch",
EntityIds::ZOMBIE_VILLAGER => "minecraft:zombie_villager",
EntityIds::BLAZE => "minecraft:blaze",
EntityIds::MAGMA_CUBE => "minecraft:magma_cube",
EntityIds::GHAST => "minecraft:ghast",
EntityIds::CAVE_SPIDER => "minecraft:cave_spider",
EntityIds::SILVERFISH => "minecraft:silverfish",
EntityIds::ENDERMAN => "minecraft:enderman",
EntityIds::SLIME => "minecraft:slime",
EntityIds::ZOMBIE_PIGMAN => "minecraft:zombie_pigman",
EntityIds::SPIDER => "minecraft:spider",
EntityIds::SKELETON => "minecraft:skeleton",
EntityIds::CREEPER => "minecraft:creeper",
EntityIds::ZOMBIE => "minecraft:zombie",
EntityIds::SKELETON_HORSE => "minecraft:skeleton_horse",
EntityIds::MULE => "minecraft:mule",
EntityIds::DONKEY => "minecraft:donkey",
EntityIds::DOLPHIN => "minecraft:dolphin",
EntityIds::TROPICALFISH => "minecraft:tropicalfish",
EntityIds::WOLF => "minecraft:wolf",
EntityIds::SQUID => "minecraft:squid",
EntityIds::DROWNED => "minecraft:drowned",
EntityIds::SHEEP => "minecraft:sheep",
EntityIds::MOOSHROOM => "minecraft:mooshroom",
EntityIds::PANDA => "minecraft:panda",
EntityIds::SALMON => "minecraft:salmon",
EntityIds::PIG => "minecraft:pig",
EntityIds::VILLAGER => "minecraft:villager",
EntityIds::COD => "minecraft:cod",
EntityIds::PUFFERFISH => "minecraft:pufferfish",
EntityIds::COW => "minecraft:cow",
EntityIds::CHICKEN => "minecraft:chicken",
EntityIds::BALLOON => "minecraft:balloon",
EntityIds::LLAMA => "minecraft:llama",
EntityIds::IRON_GOLEM => "minecraft:iron_golem",
EntityIds::RABBIT => "minecraft:rabbit",
EntityIds::SNOW_GOLEM => "minecraft:snow_golem",
EntityIds::BAT => "minecraft:bat",
EntityIds::OCELOT => "minecraft:ocelot",
EntityIds::HORSE => "minecraft:horse",
EntityIds::CAT => "minecraft:cat",
EntityIds::POLAR_BEAR => "minecraft:polar_bear",
EntityIds::ZOMBIE_HORSE => "minecraft:zombie_horse",
EntityIds::TURTLE => "minecraft:turtle",
EntityIds::PARROT => "minecraft:parrot",
EntityIds::GUARDIAN => "minecraft:guardian",
EntityIds::ELDER_GUARDIAN => "minecraft:elder_guardian",
EntityIds::VINDICATOR => "minecraft:vindicator",
EntityIds::WITHER => "minecraft:wither",
EntityIds::ENDER_DRAGON => "minecraft:ender_dragon",
EntityIds::SHULKER => "minecraft:shulker",
EntityIds::ENDERMITE => "minecraft:endermite",
EntityIds::MINECART => "minecraft:minecart",
EntityIds::HOPPER_MINECART => "minecraft:hopper_minecart",
EntityIds::TNT_MINECART => "minecraft:tnt_minecart",
EntityIds::CHEST_MINECART => "minecraft:chest_minecart",
EntityIds::COMMAND_BLOCK_MINECART => "minecraft:command_block_minecart",
EntityIds::ARMOR_STAND => "minecraft:armor_stand",
EntityIds::ITEM => "minecraft:item",
EntityIds::TNT => "minecraft:tnt",
EntityIds::FALLING_BLOCK => "minecraft:falling_block",
EntityIds::XP_BOTTLE => "minecraft:xp_bottle",
EntityIds::XP_ORB => "minecraft:xp_orb",
EntityIds::EYE_OF_ENDER_SIGNAL => "minecraft:eye_of_ender_signal",
EntityIds::ENDER_CRYSTAL => "minecraft:ender_crystal",
EntityIds::SHULKER_BULLET => "minecraft:shulker_bullet",
EntityIds::FISHING_HOOK => "minecraft:fishing_hook",
EntityIds::DRAGON_FIREBALL => "minecraft:dragon_fireball",
EntityIds::ARROW => "minecraft:arrow",
EntityIds::SNOWBALL => "minecraft:snowball",
EntityIds::EGG => "minecraft:egg",
EntityIds::PAINTING => "minecraft:painting",
EntityIds::THROWN_TRIDENT => "minecraft:thrown_trident",
EntityIds::FIREBALL => "minecraft:fireball",
EntityIds::SPLASH_POTION => "minecraft:splash_potion",
EntityIds::ENDER_PEARL => "minecraft:ender_pearl",
EntityIds::LEASH_KNOT => "minecraft:leash_knot",
EntityIds::WITHER_SKULL => "minecraft:wither_skull",
EntityIds::WITHER_SKULL_DANGEROUS => "minecraft:wither_skull_dangerous",
EntityIds::BOAT => "minecraft:boat",
EntityIds::LIGHTNING_BOLT => "minecraft:lightning_bolt",
EntityIds::SMALL_FIREBALL => "minecraft:small_fireball",
EntityIds::LLAMA_SPIT => "minecraft:llama_spit",
EntityIds::AREA_EFFECT_CLOUD => "minecraft:area_effect_cloud",
EntityIds::LINGERING_POTION => "minecraft:lingering_potion",
EntityIds::FIREWORKS_ROCKET => "minecraft:fireworks_rocket",
EntityIds::EVOCATION_FANG => "minecraft:evocation_fang",
EntityIds::EVOCATION_ILLAGER => "minecraft:evocation_illager",
EntityIds::VEX => "minecraft:vex",
EntityIds::AGENT => "minecraft:agent",
EntityIds::ICE_BOMB => "minecraft:ice_bomb",
EntityIds::PHANTOM => "minecraft:phantom",
EntityIds::TRIPOD_CAMERA => "minecraft:tripod_camera"
];
/** @var int|null */
public $entityUniqueId = null; //TODO
/** @var int */
public $entityRuntimeId;
/** @var int */
public $type;
/** @var Vector3 */
public $position;
/** @var Vector3|null */
public $motion;
/** @var float */
public $pitch = 0.0;
/** @var float */
public $yaw = 0.0;
/** @var float */
public $headYaw = 0.0;
/** @var Attribute[] */
public $attributes = [];
/** @var array */
public $metadata = [];
/** @var EntityLink[] */
public $links = [];
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->type = array_search($t = $this->getString(), self::LEGACY_ID_MAP_BC, true);
if($this->type === false){
throw new \UnexpectedValueException("Can't map ID $t to legacy ID");
}
$this->position = $this->getVector3();
$this->motion = $this->getVector3();
$this->pitch = $this->getLFloat();
$this->yaw = $this->getLFloat();
$this->headYaw = $this->getLFloat();
$attrCount = $this->getUnsignedVarInt();
for($i = 0; $i < $attrCount; ++$i){
$name = $this->getString();
$min = $this->getLFloat();
$current = $this->getLFloat();
$max = $this->getLFloat();
$attr = Attribute::getAttributeByName($name);
if($attr !== null){
$attr->setMinValue($min);
$attr->setMaxValue($max);
$attr->setValue($current);
$this->attributes[] = $attr;
}else{
throw new \UnexpectedValueException("Unknown attribute type \"$name\"");
}
}
$this->metadata = $this->getEntityMetadata();
$linkCount = $this->getUnsignedVarInt();
for($i = 0; $i < $linkCount; ++$i){
$this->links[] = $this->getEntityLink();
}
}
protected function encodePayload(){
$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
$this->putEntityRuntimeId($this->entityRuntimeId);
if(!isset(self::LEGACY_ID_MAP_BC[$this->type])){
throw new \InvalidArgumentException("Unknown entity numeric ID $this->type");
}
$this->putString(self::LEGACY_ID_MAP_BC[$this->type]);
$this->putVector3($this->position);
$this->putVector3Nullable($this->motion);
$this->putLFloat($this->pitch);
$this->putLFloat($this->yaw);
$this->putLFloat($this->headYaw);
$this->putUnsignedVarInt(count($this->attributes));
foreach($this->attributes as $attribute){
$this->putString($attribute->getName());
$this->putLFloat($attribute->getMinValue());
$this->putLFloat($attribute->getValue());
$this->putLFloat($attribute->getMaxValue());
}
$this->putEntityMetadata($this->metadata);
$this->putUnsignedVarInt(count($this->links));
foreach($this->links as $link){
$this->putEntityLink($link);
}
}
public function handle(NetworkSession $session) : bool{
return $session->handleAddActor($this);
}
}

View File

@ -25,216 +25,36 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\entity\Attribute;
use pocketmine\entity\EntityIds;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use function array_search;
use function count;
class AddEntityPacket extends DataPacket{
class AddEntityPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::ADD_ENTITY_PACKET;
/*
* Really really really really really nasty hack, to preserve backwards compatibility.
* We can't transition to string IDs within 3.x because the network IDs (the integer ones) are exposed
* to the API in some places (for god's sake shoghi).
*
* TODO: remove this on 4.0
/** @var int */
private $uvarint1;
public static function create(int $uvarint1) : self{
$result = new self;
$result->uvarint1 = $uvarint1;
return $result;
}
/**
* @return int
*/
public const LEGACY_ID_MAP_BC = [
EntityIds::NPC => "minecraft:npc",
EntityIds::PLAYER => "minecraft:player",
EntityIds::WITHER_SKELETON => "minecraft:wither_skeleton",
EntityIds::HUSK => "minecraft:husk",
EntityIds::STRAY => "minecraft:stray",
EntityIds::WITCH => "minecraft:witch",
EntityIds::ZOMBIE_VILLAGER => "minecraft:zombie_villager",
EntityIds::BLAZE => "minecraft:blaze",
EntityIds::MAGMA_CUBE => "minecraft:magma_cube",
EntityIds::GHAST => "minecraft:ghast",
EntityIds::CAVE_SPIDER => "minecraft:cave_spider",
EntityIds::SILVERFISH => "minecraft:silverfish",
EntityIds::ENDERMAN => "minecraft:enderman",
EntityIds::SLIME => "minecraft:slime",
EntityIds::ZOMBIE_PIGMAN => "minecraft:zombie_pigman",
EntityIds::SPIDER => "minecraft:spider",
EntityIds::SKELETON => "minecraft:skeleton",
EntityIds::CREEPER => "minecraft:creeper",
EntityIds::ZOMBIE => "minecraft:zombie",
EntityIds::SKELETON_HORSE => "minecraft:skeleton_horse",
EntityIds::MULE => "minecraft:mule",
EntityIds::DONKEY => "minecraft:donkey",
EntityIds::DOLPHIN => "minecraft:dolphin",
EntityIds::TROPICALFISH => "minecraft:tropicalfish",
EntityIds::WOLF => "minecraft:wolf",
EntityIds::SQUID => "minecraft:squid",
EntityIds::DROWNED => "minecraft:drowned",
EntityIds::SHEEP => "minecraft:sheep",
EntityIds::MOOSHROOM => "minecraft:mooshroom",
EntityIds::PANDA => "minecraft:panda",
EntityIds::SALMON => "minecraft:salmon",
EntityIds::PIG => "minecraft:pig",
EntityIds::VILLAGER => "minecraft:villager",
EntityIds::COD => "minecraft:cod",
EntityIds::PUFFERFISH => "minecraft:pufferfish",
EntityIds::COW => "minecraft:cow",
EntityIds::CHICKEN => "minecraft:chicken",
EntityIds::BALLOON => "minecraft:balloon",
EntityIds::LLAMA => "minecraft:llama",
EntityIds::IRON_GOLEM => "minecraft:iron_golem",
EntityIds::RABBIT => "minecraft:rabbit",
EntityIds::SNOW_GOLEM => "minecraft:snow_golem",
EntityIds::BAT => "minecraft:bat",
EntityIds::OCELOT => "minecraft:ocelot",
EntityIds::HORSE => "minecraft:horse",
EntityIds::CAT => "minecraft:cat",
EntityIds::POLAR_BEAR => "minecraft:polar_bear",
EntityIds::ZOMBIE_HORSE => "minecraft:zombie_horse",
EntityIds::TURTLE => "minecraft:turtle",
EntityIds::PARROT => "minecraft:parrot",
EntityIds::GUARDIAN => "minecraft:guardian",
EntityIds::ELDER_GUARDIAN => "minecraft:elder_guardian",
EntityIds::VINDICATOR => "minecraft:vindicator",
EntityIds::WITHER => "minecraft:wither",
EntityIds::ENDER_DRAGON => "minecraft:ender_dragon",
EntityIds::SHULKER => "minecraft:shulker",
EntityIds::ENDERMITE => "minecraft:endermite",
EntityIds::MINECART => "minecraft:minecart",
EntityIds::HOPPER_MINECART => "minecraft:hopper_minecart",
EntityIds::TNT_MINECART => "minecraft:tnt_minecart",
EntityIds::CHEST_MINECART => "minecraft:chest_minecart",
EntityIds::COMMAND_BLOCK_MINECART => "minecraft:command_block_minecart",
EntityIds::ARMOR_STAND => "minecraft:armor_stand",
EntityIds::ITEM => "minecraft:item",
EntityIds::TNT => "minecraft:tnt",
EntityIds::FALLING_BLOCK => "minecraft:falling_block",
EntityIds::XP_BOTTLE => "minecraft:xp_bottle",
EntityIds::XP_ORB => "minecraft:xp_orb",
EntityIds::EYE_OF_ENDER_SIGNAL => "minecraft:eye_of_ender_signal",
EntityIds::ENDER_CRYSTAL => "minecraft:ender_crystal",
EntityIds::SHULKER_BULLET => "minecraft:shulker_bullet",
EntityIds::FISHING_HOOK => "minecraft:fishing_hook",
EntityIds::DRAGON_FIREBALL => "minecraft:dragon_fireball",
EntityIds::ARROW => "minecraft:arrow",
EntityIds::SNOWBALL => "minecraft:snowball",
EntityIds::EGG => "minecraft:egg",
EntityIds::PAINTING => "minecraft:painting",
EntityIds::THROWN_TRIDENT => "minecraft:thrown_trident",
EntityIds::FIREBALL => "minecraft:fireball",
EntityIds::SPLASH_POTION => "minecraft:splash_potion",
EntityIds::ENDER_PEARL => "minecraft:ender_pearl",
EntityIds::LEASH_KNOT => "minecraft:leash_knot",
EntityIds::WITHER_SKULL => "minecraft:wither_skull",
EntityIds::WITHER_SKULL_DANGEROUS => "minecraft:wither_skull_dangerous",
EntityIds::BOAT => "minecraft:boat",
EntityIds::LIGHTNING_BOLT => "minecraft:lightning_bolt",
EntityIds::SMALL_FIREBALL => "minecraft:small_fireball",
EntityIds::LLAMA_SPIT => "minecraft:llama_spit",
EntityIds::AREA_EFFECT_CLOUD => "minecraft:area_effect_cloud",
EntityIds::LINGERING_POTION => "minecraft:lingering_potion",
EntityIds::FIREWORKS_ROCKET => "minecraft:fireworks_rocket",
EntityIds::EVOCATION_FANG => "minecraft:evocation_fang",
EntityIds::EVOCATION_ILLAGER => "minecraft:evocation_illager",
EntityIds::VEX => "minecraft:vex",
EntityIds::AGENT => "minecraft:agent",
EntityIds::ICE_BOMB => "minecraft:ice_bomb",
EntityIds::PHANTOM => "minecraft:phantom",
EntityIds::TRIPOD_CAMERA => "minecraft:tripod_camera"
];
/** @var int|null */
public $entityUniqueId = null; //TODO
/** @var int */
public $entityRuntimeId;
/** @var int */
public $type;
/** @var Vector3 */
public $position;
/** @var Vector3|null */
public $motion;
/** @var float */
public $pitch = 0.0;
/** @var float */
public $yaw = 0.0;
/** @var float */
public $headYaw = 0.0;
/** @var Attribute[] */
public $attributes = [];
/** @var array */
public $metadata = [];
/** @var EntityLink[] */
public $links = [];
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->type = array_search($t = $this->getString(), self::LEGACY_ID_MAP_BC, true);
if($this->type === false){
throw new \UnexpectedValueException("Can't map ID $t to legacy ID");
}
$this->position = $this->getVector3();
$this->motion = $this->getVector3();
$this->pitch = $this->getLFloat();
$this->yaw = $this->getLFloat();
$this->headYaw = $this->getLFloat();
$attrCount = $this->getUnsignedVarInt();
for($i = 0; $i < $attrCount; ++$i){
$name = $this->getString();
$min = $this->getLFloat();
$current = $this->getLFloat();
$max = $this->getLFloat();
$attr = Attribute::getAttributeByName($name);
if($attr !== null){
$attr->setMinValue($min);
$attr->setMaxValue($max);
$attr->setValue($current);
$this->attributes[] = $attr;
}else{
throw new \UnexpectedValueException("Unknown attribute type \"$name\"");
}
}
$this->metadata = $this->getEntityMetadata();
$linkCount = $this->getUnsignedVarInt();
for($i = 0; $i < $linkCount; ++$i){
$this->links[] = $this->getEntityLink();
}
public function getUvarint1() : int{
return $this->uvarint1;
}
protected function encodePayload(){
$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
$this->putEntityRuntimeId($this->entityRuntimeId);
if(!isset(self::LEGACY_ID_MAP_BC[$this->type])){
throw new \InvalidArgumentException("Unknown entity numeric ID $this->type");
}
$this->putString(self::LEGACY_ID_MAP_BC[$this->type]);
$this->putVector3($this->position);
$this->putVector3Nullable($this->motion);
$this->putLFloat($this->pitch);
$this->putLFloat($this->yaw);
$this->putLFloat($this->headYaw);
$this->putUnsignedVarInt(count($this->attributes));
foreach($this->attributes as $attribute){
$this->putString($attribute->getName());
$this->putLFloat($attribute->getMinValue());
$this->putLFloat($attribute->getValue());
$this->putLFloat($attribute->getMaxValue());
}
$this->putEntityMetadata($this->metadata);
$this->putUnsignedVarInt(count($this->links));
foreach($this->links as $link){
$this->putEntityLink($link);
}
protected function decodePayload() : void{
$this->uvarint1 = $this->getUnsignedVarInt();
}
public function handle(NetworkSession $session) : bool{
return $session->handleAddEntity($this);
protected function encodePayload() : void{
$this->putUnsignedVarInt($this->uvarint1);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleAddEntity($this);
}
}

View File

@ -29,8 +29,8 @@ use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
class AddItemEntityPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ADD_ITEM_ENTITY_PACKET;
class AddItemActorPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ADD_ITEM_ACTOR_PACKET;
/** @var int|null */
public $entityUniqueId = null; //TODO
@ -68,6 +68,6 @@ class AddItemEntityPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleAddItemEntity($this);
return $session->handleAddItemActor($this);
}
}

View File

@ -26,30 +26,27 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
class AddPaintingPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ADD_PAINTING_PACKET;
/** @var string */
public $title;
/** @var int */
public $entityRuntimeId;
/** @var int */
public $x;
/** @var int|null */
public $entityUniqueId = null;
/** @var int */
public $y;
/** @var int */
public $z;
public $entityRuntimeId;
/** @var Vector3 */
public $position;
/** @var int */
public $direction;
/** @var string */
public $title;
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->getBlockPosition($this->x, $this->y, $this->z);
$this->position = $this->getVector3();
$this->direction = $this->getVarInt();
$this->title = $this->getString();
}
@ -57,7 +54,7 @@ class AddPaintingPacket extends DataPacket{
protected function encodePayload(){
$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
$this->putEntityRuntimeId($this->entityRuntimeId);
$this->putBlockPosition($this->x, $this->y, $this->z);
$this->putVector3($this->position);
$this->putVarInt($this->direction);
$this->putString($this->title);
}

View File

@ -35,6 +35,8 @@ class AnimatePacket extends DataPacket{
public const ACTION_STOP_SLEEP = 3;
public const ACTION_CRITICAL_HIT = 4;
public const ACTION_ROW_RIGHT = 128;
public const ACTION_ROW_LEFT = 129;
/** @var int */
public $action;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -28,8 +28,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class BlockEntityDataPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::BLOCK_ENTITY_DATA_PACKET;
class BlockActorDataPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::BLOCK_ACTOR_DATA_PACKET;
/** @var int */
public $x;
@ -51,6 +51,6 @@ class BlockEntityDataPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleBlockEntityData($this);
return $session->handleBlockActorData($this);
}
}

View File

@ -0,0 +1,95 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use function count;
class ClientCacheBlobStatusPacket extends DataPacket/* implements ServerboundPacket*/{
public const NETWORK_ID = ProtocolInfo::CLIENT_CACHE_BLOB_STATUS_PACKET;
/** @var int[] xxHash64 subchunk data hashes */
private $hitHashes = [];
/** @var int[] xxHash64 subchunk data hashes */
private $missHashes = [];
/**
* @param int[] $hitHashes
* @param int[] $missHashes
*
* @return self
*/
public static function create(array $hitHashes, array $missHashes) : self{
//type checks
(static function(int ...$hashes){})(...$hitHashes);
(static function(int ...$hashes){})(...$missHashes);
$result = new self;
$result->hitHashes = $hitHashes;
$result->missHashes = $missHashes;
return $result;
}
/**
* @return int[]
*/
public function getHitHashes() : array{
return $this->hitHashes;
}
/**
* @return int[]
*/
public function getMissHashes() : array{
return $this->missHashes;
}
protected function decodePayload() : void{
$hitCount = $this->getUnsignedVarInt();
$missCount = $this->getUnsignedVarInt();
for($i = 0; $i < $hitCount; ++$i){
$this->hitHashes[] = $this->getLLong();
}
for($i = 0; $i < $missCount; ++$i){
$this->missHashes[] = $this->getLLong();
}
}
protected function encodePayload() : void{
$this->putUnsignedVarInt(count($this->hitHashes));
$this->putUnsignedVarInt(count($this->missHashes));
foreach($this->hitHashes as $hash){
$this->putLLong($hash);
}
foreach($this->missHashes as $hash){
$this->putLLong($hash);
}
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleClientCacheBlobStatus($this);
}
}

View File

@ -0,0 +1,78 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ChunkCacheBlob;
use function count;
class ClientCacheMissResponsePacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::CLIENT_CACHE_MISS_RESPONSE_PACKET;
/** @var ChunkCacheBlob[] */
private $blobs = [];
/**
* @param ChunkCacheBlob[] $blobs
*
* @return self
*/
public static function create(array $blobs) : self{
//type check
(static function(ChunkCacheBlob ...$blobs){})($blobs);
$result = new self;
$result->blobs = $blobs;
return $result;
}
/**
* @return ChunkCacheBlob[]
*/
public function getBlobs() : array{
return $this->blobs;
}
protected function decodePayload() : void{
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$hash = $this->getLLong();
$payload = $this->getString();
$this->blobs[] = new ChunkCacheBlob($hash, $payload);
}
}
protected function encodePayload() : void{
$this->putUnsignedVarInt(count($this->blobs));
foreach($this->blobs as $blob){
$this->putLLong($blob->getHash());
$this->putString($blob->getPayload());
}
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleClientCacheMissResponse($this);
}
}

View File

@ -0,0 +1,60 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class ClientCacheStatusPacket extends DataPacket/* implements ServerboundPacket*/{
public const NETWORK_ID = ProtocolInfo::CLIENT_CACHE_STATUS_PACKET;
/** @var bool */
private $enabled;
public static function create(bool $enabled) : self{
$result = new self;
$result->enabled = $enabled;
return $result;
}
/**
* @return bool
*/
public function isEnabled() : bool{
return $this->enabled;
}
protected function decodePayload() : void{
$this->enabled = $this->getBool();
}
protected function encodePayload() : void{
$this->putBool($this->enabled);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleClientCacheStatus($this);
}
}

View File

@ -59,6 +59,10 @@ class CommandBlockUpdatePacket extends DataPacket{
public $name;
/** @var bool */
public $shouldTrackOutput;
/** @var int */
public $tickDelay;
/** @var bool */
public $executeOnFirstTick;
protected function decodePayload(){
$this->isBlock = $this->getBool();
@ -78,6 +82,8 @@ class CommandBlockUpdatePacket extends DataPacket{
$this->name = $this->getString();
$this->shouldTrackOutput = $this->getBool();
$this->tickDelay = $this->getLInt();
$this->executeOnFirstTick = $this->getBool();
}
protected function encodePayload(){
@ -97,6 +103,8 @@ class CommandBlockUpdatePacket extends DataPacket{
$this->putString($this->name);
$this->putBool($this->shouldTrackOutput);
$this->putLInt($this->tickDelay);
$this->putBool($this->executeOnFirstTick);
}
public function handle(NetworkSession $session) : bool{

View File

@ -33,6 +33,9 @@ use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
#ifndef COMPILE
use pocketmine\utils\Binary;
#endif
use function count;
use function str_repeat;
@ -72,11 +75,13 @@ class CraftingDataPacket extends DataPacket{
case self::ENTRY_SHAPELESS:
case self::ENTRY_SHULKER_BOX:
case self::ENTRY_SHAPELESS_CHEMISTRY:
$entry["recipe_id"] = $this->getString();
$ingredientCount = $this->getUnsignedVarInt();
/** @var Item */
$entry["input"] = [];
for($j = 0; $j < $ingredientCount; ++$j){
$entry["input"][] = $this->getSlot();
$entry["input"][] = $in = $this->getRecipeIngredient();
$in->setCount(1); //TODO HACK: they send a useless count field which breaks the PM crafting system because it isn't always 1
}
$resultCount = $this->getUnsignedVarInt();
$entry["output"] = [];
@ -85,16 +90,19 @@ class CraftingDataPacket extends DataPacket{
}
$entry["uuid"] = $this->getUUID()->toString();
$entry["block"] = $this->getString();
$entry["priority"] = $this->getVarInt();
break;
case self::ENTRY_SHAPED:
case self::ENTRY_SHAPED_CHEMISTRY:
$entry["recipe_id"] = $this->getString();
$entry["width"] = $this->getVarInt();
$entry["height"] = $this->getVarInt();
$count = $entry["width"] * $entry["height"];
$entry["input"] = [];
for($j = 0; $j < $count; ++$j){
$entry["input"][] = $this->getSlot();
$entry["input"][] = $in = $this->getRecipeIngredient();
$in->setCount(1); //TODO HACK: they send a useless count field which breaks the PM crafting system
}
$resultCount = $this->getUnsignedVarInt();
$entry["output"] = [];
@ -103,6 +111,7 @@ class CraftingDataPacket extends DataPacket{
}
$entry["uuid"] = $this->getUUID()->toString();
$entry["block"] = $this->getString();
$entry["priority"] = $this->getVarInt();
break;
case self::ENTRY_FURNACE:
@ -116,7 +125,10 @@ class CraftingDataPacket extends DataPacket{
}
}
$entry["input"] = ItemFactory::get($inputId, $inputData);
$entry["output"] = $this->getSlot();
$entry["output"] = $out = $this->getSlot();
if($out->getDamage() === 0x7fff){
$out->setDamage(0); //TODO HACK: some 1.12 furnace recipe outputs have wildcard damage values
}
$entry["block"] = $this->getString();
break;
@ -131,11 +143,11 @@ class CraftingDataPacket extends DataPacket{
$this->getBool(); //cleanRecipes
}
private static function writeEntry($entry, NetworkBinaryStream $stream){
private static function writeEntry($entry, NetworkBinaryStream $stream, int $pos){
if($entry instanceof ShapelessRecipe){
return self::writeShapelessRecipe($entry, $stream);
return self::writeShapelessRecipe($entry, $stream, $pos);
}elseif($entry instanceof ShapedRecipe){
return self::writeShapedRecipe($entry, $stream);
return self::writeShapedRecipe($entry, $stream, $pos);
}elseif($entry instanceof FurnaceRecipe){
return self::writeFurnaceRecipe($entry, $stream);
}
@ -144,10 +156,11 @@ class CraftingDataPacket extends DataPacket{
return -1;
}
private static function writeShapelessRecipe(ShapelessRecipe $recipe, NetworkBinaryStream $stream){
private static function writeShapelessRecipe(ShapelessRecipe $recipe, NetworkBinaryStream $stream, int $pos){
$stream->putString(Binary::writeInt($pos)); //some kind of recipe ID, doesn't matter what it is as long as it's unique
$stream->putUnsignedVarInt($recipe->getIngredientCount());
foreach($recipe->getIngredientList() as $item){
$stream->putSlot($item);
$stream->putRecipeIngredient($item);
}
$results = $recipe->getResults();
@ -158,17 +171,19 @@ class CraftingDataPacket extends DataPacket{
$stream->put(str_repeat("\x00", 16)); //Null UUID
$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
$stream->putVarInt(50); //TODO: priority
return CraftingDataPacket::ENTRY_SHAPELESS;
}
private static function writeShapedRecipe(ShapedRecipe $recipe, NetworkBinaryStream $stream){
private static function writeShapedRecipe(ShapedRecipe $recipe, NetworkBinaryStream $stream, int $pos){
$stream->putString(Binary::writeInt($pos)); //some kind of recipe ID, doesn't matter what it is as long as it's unique
$stream->putVarInt($recipe->getWidth());
$stream->putVarInt($recipe->getHeight());
for($z = 0; $z < $recipe->getHeight(); ++$z){
for($x = 0; $x < $recipe->getWidth(); ++$x){
$stream->putSlot($recipe->getIngredient($x, $z));
$stream->putRecipeIngredient($recipe->getIngredient($x, $z));
}
}
@ -180,6 +195,7 @@ class CraftingDataPacket extends DataPacket{
$stream->put(str_repeat("\x00", 16)); //Null UUID
$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
$stream->putVarInt(50); //TODO: priority
return CraftingDataPacket::ENTRY_SHAPED;
}
@ -212,8 +228,9 @@ class CraftingDataPacket extends DataPacket{
$this->putUnsignedVarInt(count($this->entries));
$writer = new NetworkBinaryStream();
$counter = 0;
foreach($this->entries as $d){
$entryType = self::writeEntry($d, $writer);
$entryType = self::writeEntry($d, $writer, $counter++);
if($entryType >= 0){
$this->putVarInt($entryType);
$this->put($writer->getBuffer());

View File

@ -0,0 +1,145 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use function count;
class LevelChunkPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::LEVEL_CHUNK_PACKET;
/** @var int */
private $chunkX;
/** @var int */
private $chunkZ;
/** @var int */
private $subChunkCount;
/** @var bool */
private $cacheEnabled;
/** @var int[] */
private $usedBlobHashes = [];
/** @var string */
private $extraPayload;
public static function withoutCache(int $chunkX, int $chunkZ, int $subChunkCount, string $payload) : self{
$result = new self;
$result->chunkX = $chunkX;
$result->chunkZ = $chunkZ;
$result->subChunkCount = $subChunkCount;
$result->extraPayload = $payload;
$result->cacheEnabled = false;
return $result;
}
public static function withCache(int $chunkX, int $chunkZ, int $subChunkCount, array $usedBlobHashes, string $extraPayload) : self{
(static function(int ...$hashes){})($usedBlobHashes);
$result = new self;
$result->chunkX = $chunkX;
$result->chunkZ = $chunkZ;
$result->subChunkCount = $subChunkCount;
$result->extraPayload = $extraPayload;
$result->cacheEnabled = true;
$result->usedBlobHashes = $usedBlobHashes;
return $result;
}
/**
* @return int
*/
public function getChunkX() : int{
return $this->chunkX;
}
/**
* @return int
*/
public function getChunkZ() : int{
return $this->chunkZ;
}
/**
* @return int
*/
public function getSubChunkCount() : int{
return $this->subChunkCount;
}
/**
* @return bool
*/
public function isCacheEnabled() : bool{
return $this->cacheEnabled;
}
/**
* @return int[]
*/
public function getUsedBlobHashes() : array{
return $this->usedBlobHashes;
}
/**
* @return string
*/
public function getExtraPayload() : string{
return $this->extraPayload;
}
protected function decodePayload() : void{
$this->chunkX = $this->getVarInt();
$this->chunkZ = $this->getVarInt();
$this->subChunkCount = $this->getUnsignedVarInt();
$this->cacheEnabled = $this->getBool();
if($this->cacheEnabled){
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->usedBlobHashes[] = $this->getLLong();
}
}
$this->extraPayload = $this->getString();
}
protected function encodePayload() : void{
$this->putVarInt($this->chunkX);
$this->putVarInt($this->chunkZ);
$this->putUnsignedVarInt($this->subChunkCount);
$this->putBool($this->cacheEnabled);
if($this->cacheEnabled){
$this->putUnsignedVarInt(count($this->usedBlobHashes));
foreach($this->usedBlobHashes as $hash){
$this->putLLong($hash);
}
}
$this->putString($this->extraPayload);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleLevelChunk($this);
}
}

View File

@ -0,0 +1,74 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\NetworkSession;
class LevelEventGenericPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::LEVEL_EVENT_GENERIC_PACKET;
/** @var int */
private $eventId;
/** @var string network-format NBT */
private $eventData;
public static function create(int $eventId, CompoundTag $data) : self{
$result = new self;
$result->eventId = $eventId;
$result->eventData = (new NetworkLittleEndianNBTStream())->write($data);
return $result;
}
/**
* @return int
*/
public function getEventId() : int{
return $this->eventId;
}
/**
* @return string
*/
public function getEventData() : string{
return $this->eventData;
}
protected function decodePayload() : void{
$this->eventId = $this->getVarInt();
$this->eventData = $this->getRemaining();
}
protected function encodePayload() : void{
$this->putVarInt($this->eventId);
$this->put($this->eventData);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleLevelEventGeneric($this);
}
}

View File

@ -292,8 +292,8 @@ class LevelSoundEventPacket extends DataPacket{
public const SOUND_STUN = 261;
public const SOUND_BLOCK_SWEET_BERRY_BUSH_HURT = 262;
public const SOUND_BLOCK_SWEET_BERRY_BUSH_PICK = 263;
public const SOUND_UI_CARTOGRAPHY_TABLE_TAKE_RESULT = 264;
public const SOUND_UI_STONECUTTER_TAKE_RESULT = 265;
public const SOUND_BLOCK_CARTOGRAPHY_TABLE_USE = 264;
public const SOUND_BLOCK_STONECUTTER_USE = 265;
public const SOUND_BLOCK_COMPOSTER_EMPTY = 266;
public const SOUND_BLOCK_COMPOSTER_FILL = 267;
public const SOUND_BLOCK_COMPOSTER_FILL_SUCCESS = 268;
@ -302,7 +302,14 @@ class LevelSoundEventPacket extends DataPacket{
public const SOUND_BLOCK_BARREL_CLOSE = 271;
public const SOUND_RAID_HORN = 272;
public const SOUND_BLOCK_LOOM_USE = 273;
public const SOUND_UNDEFINED = 274;
public const SOUND_AMBIENT_IN_RAID = 274;
public const SOUND_UI_CARTOGRAPHY_TABLE_TAKE_RESULT = 275;
public const SOUND_UI_STONECUTTER_TAKE_RESULT = 276;
public const SOUND_UI_LOOM_TAKE_RESULT = 277;
public const SOUND_BLOCK_SMOKER_SMOKE = 278;
public const SOUND_BLOCK_BLASTFURNACE_FIRE_CRACKLE = 279;
public const SOUND_BLOCK_SMITHING_TABLE_USE = 280;
public const SOUND_UNDEFINED = 281;
/** @var int */
public $sound;

View File

@ -29,8 +29,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
class MoveEntityAbsolutePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::MOVE_ENTITY_ABSOLUTE_PACKET;
class MoveActorAbsolutePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::MOVE_ACTOR_ABSOLUTE_PACKET;
public const FLAG_GROUND = 0x01;
public const FLAG_TELEPORT = 0x02;
@ -67,6 +67,6 @@ class MoveEntityAbsolutePacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleMoveEntityAbsolute($this);
return $session->handleMoveActorAbsolute($this);
}
}

View File

@ -27,8 +27,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class MoveEntityDeltaPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::MOVE_ENTITY_DELTA_PACKET;
class MoveActorDeltaPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::MOVE_ACTOR_DELTA_PACKET;
public const FLAG_HAS_X = 0x01;
public const FLAG_HAS_Y = 0x02;
@ -103,6 +103,6 @@ class MoveEntityDeltaPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleMoveEntityDelta($this);
return $session->handleMoveActorDelta($this);
}
}

View File

@ -45,11 +45,11 @@ class PacketPool{
static::registerPacket(new SetTimePacket());
static::registerPacket(new StartGamePacket());
static::registerPacket(new AddPlayerPacket());
static::registerPacket(new AddEntityPacket());
static::registerPacket(new RemoveEntityPacket());
static::registerPacket(new AddItemEntityPacket());
static::registerPacket(new TakeItemEntityPacket());
static::registerPacket(new MoveEntityAbsolutePacket());
static::registerPacket(new AddActorPacket());
static::registerPacket(new RemoveActorPacket());
static::registerPacket(new AddItemActorPacket());
static::registerPacket(new TakeItemActorPacket());
static::registerPacket(new MoveActorAbsolutePacket());
static::registerPacket(new MovePlayerPacket());
static::registerPacket(new RiderJumpPacket());
static::registerPacket(new UpdateBlockPacket());
@ -58,7 +58,7 @@ class PacketPool{
static::registerPacket(new LevelSoundEventPacketV1());
static::registerPacket(new LevelEventPacket());
static::registerPacket(new BlockEventPacket());
static::registerPacket(new EntityEventPacket());
static::registerPacket(new ActorEventPacket());
static::registerPacket(new MobEffectPacket());
static::registerPacket(new UpdateAttributesPacket());
static::registerPacket(new InventoryTransactionPacket());
@ -66,13 +66,13 @@ class PacketPool{
static::registerPacket(new MobArmorEquipmentPacket());
static::registerPacket(new InteractPacket());
static::registerPacket(new BlockPickRequestPacket());
static::registerPacket(new EntityPickRequestPacket());
static::registerPacket(new ActorPickRequestPacket());
static::registerPacket(new PlayerActionPacket());
static::registerPacket(new EntityFallPacket());
static::registerPacket(new ActorFallPacket());
static::registerPacket(new HurtArmorPacket());
static::registerPacket(new SetEntityDataPacket());
static::registerPacket(new SetEntityMotionPacket());
static::registerPacket(new SetEntityLinkPacket());
static::registerPacket(new SetActorDataPacket());
static::registerPacket(new SetActorMotionPacket());
static::registerPacket(new SetActorLinkPacket());
static::registerPacket(new SetHealthPacket());
static::registerPacket(new SetSpawnPositionPacket());
static::registerPacket(new AnimatePacket());
@ -87,9 +87,9 @@ class PacketPool{
static::registerPacket(new CraftingEventPacket());
static::registerPacket(new GuiDataPickItemPacket());
static::registerPacket(new AdventureSettingsPacket());
static::registerPacket(new BlockEntityDataPacket());
static::registerPacket(new BlockActorDataPacket());
static::registerPacket(new PlayerInputPacket());
static::registerPacket(new FullChunkDataPacket());
static::registerPacket(new LevelChunkPacket());
static::registerPacket(new SetCommandsEnabledPacket());
static::registerPacket(new SetDifficultyPacket());
static::registerPacket(new ChangeDimensionPacket());
@ -142,22 +142,31 @@ class PacketPool{
static::registerPacket(new SetScorePacket());
static::registerPacket(new LabTablePacket());
static::registerPacket(new UpdateBlockSyncedPacket());
static::registerPacket(new MoveEntityDeltaPacket());
static::registerPacket(new MoveActorDeltaPacket());
static::registerPacket(new SetScoreboardIdentityPacket());
static::registerPacket(new SetLocalPlayerAsInitializedPacket());
static::registerPacket(new UpdateSoftEnumPacket());
static::registerPacket(new NetworkStackLatencyPacket());
static::registerPacket(new ScriptCustomEventPacket());
static::registerPacket(new SpawnParticleEffectPacket());
static::registerPacket(new AvailableEntityIdentifiersPacket());
static::registerPacket(new AvailableActorIdentifiersPacket());
static::registerPacket(new LevelSoundEventPacketV2());
static::registerPacket(new NetworkChunkPublisherUpdatePacket());
static::registerPacket(new BiomeDefinitionListPacket());
static::registerPacket(new LevelSoundEventPacket());
static::registerPacket(new LevelEventGenericPacket());
static::registerPacket(new LecternUpdatePacket());
static::registerPacket(new VideoStreamConnectPacket());
static::registerPacket(new MapCreateLockedCopyPacket());
static::registerPacket(new AddEntityPacket());
static::registerPacket(new RemoveEntityPacket());
static::registerPacket(new ClientCacheStatusPacket());
static::registerPacket(new OnScreenTextureAnimationPacket());
static::registerPacket(new MapCreateLockedCopyPacket());
static::registerPacket(new StructureTemplateDataExportRequestPacket());
static::registerPacket(new StructureTemplateDataExportResponsePacket());
static::registerPacket(new UpdateBlockPropertiesPacket());
static::registerPacket(new ClientCacheBlobStatusPacket());
static::registerPacket(new ClientCacheMissResponsePacket());
}
/**

View File

@ -56,6 +56,7 @@ class PlayerActionPacket extends DataPacket{
public const ACTION_STOP_SWIMMING = 22;
public const ACTION_START_SPIN_ATTACK = 23;
public const ACTION_STOP_SPIN_ATTACK = 24;
public const ACTION_INTERACT_BLOCK = 25;
/** @var int */
public $entityRuntimeId;

View File

@ -39,15 +39,15 @@ interface ProtocolInfo{
/**
* Actual Minecraft: PE protocol version
*/
public const CURRENT_PROTOCOL = 354;
public const CURRENT_PROTOCOL = 361;
/**
* Current Minecraft PE version reported by the server. This is usually the earliest currently supported version.
*/
public const MINECRAFT_VERSION = 'v1.11.0';
public const MINECRAFT_VERSION = 'v1.12.0';
/**
* Version number sent to clients in ping responses.
*/
public const MINECRAFT_VERSION_NETWORK = '1.11.0';
public const MINECRAFT_VERSION_NETWORK = '1.12.0';
public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02;
@ -61,12 +61,12 @@ interface ProtocolInfo{
public const SET_TIME_PACKET = 0x0a;
public const START_GAME_PACKET = 0x0b;
public const ADD_PLAYER_PACKET = 0x0c;
public const ADD_ENTITY_PACKET = 0x0d;
public const REMOVE_ENTITY_PACKET = 0x0e;
public const ADD_ITEM_ENTITY_PACKET = 0x0f;
public const ADD_ACTOR_PACKET = 0x0d;
public const REMOVE_ACTOR_PACKET = 0x0e;
public const ADD_ITEM_ACTOR_PACKET = 0x0f;
public const TAKE_ITEM_ENTITY_PACKET = 0x11;
public const MOVE_ENTITY_ABSOLUTE_PACKET = 0x12;
public const TAKE_ITEM_ACTOR_PACKET = 0x11;
public const MOVE_ACTOR_ABSOLUTE_PACKET = 0x12;
public const MOVE_PLAYER_PACKET = 0x13;
public const RIDER_JUMP_PACKET = 0x14;
public const UPDATE_BLOCK_PACKET = 0x15;
@ -75,7 +75,7 @@ interface ProtocolInfo{
public const LEVEL_SOUND_EVENT_PACKET_V1 = 0x18;
public const LEVEL_EVENT_PACKET = 0x19;
public const BLOCK_EVENT_PACKET = 0x1a;
public const ENTITY_EVENT_PACKET = 0x1b;
public const ACTOR_EVENT_PACKET = 0x1b;
public const MOB_EFFECT_PACKET = 0x1c;
public const UPDATE_ATTRIBUTES_PACKET = 0x1d;
public const INVENTORY_TRANSACTION_PACKET = 0x1e;
@ -83,13 +83,13 @@ interface ProtocolInfo{
public const MOB_ARMOR_EQUIPMENT_PACKET = 0x20;
public const INTERACT_PACKET = 0x21;
public const BLOCK_PICK_REQUEST_PACKET = 0x22;
public const ENTITY_PICK_REQUEST_PACKET = 0x23;
public const ACTOR_PICK_REQUEST_PACKET = 0x23;
public const PLAYER_ACTION_PACKET = 0x24;
public const ENTITY_FALL_PACKET = 0x25;
public const ACTOR_FALL_PACKET = 0x25;
public const HURT_ARMOR_PACKET = 0x26;
public const SET_ENTITY_DATA_PACKET = 0x27;
public const SET_ENTITY_MOTION_PACKET = 0x28;
public const SET_ENTITY_LINK_PACKET = 0x29;
public const SET_ACTOR_DATA_PACKET = 0x27;
public const SET_ACTOR_MOTION_PACKET = 0x28;
public const SET_ACTOR_LINK_PACKET = 0x29;
public const SET_HEALTH_PACKET = 0x2a;
public const SET_SPAWN_POSITION_PACKET = 0x2b;
public const ANIMATE_PACKET = 0x2c;
@ -104,9 +104,9 @@ interface ProtocolInfo{
public const CRAFTING_EVENT_PACKET = 0x35;
public const GUI_DATA_PICK_ITEM_PACKET = 0x36;
public const ADVENTURE_SETTINGS_PACKET = 0x37;
public const BLOCK_ENTITY_DATA_PACKET = 0x38;
public const BLOCK_ACTOR_DATA_PACKET = 0x38;
public const PLAYER_INPUT_PACKET = 0x39;
public const FULL_CHUNK_DATA_PACKET = 0x3a;
public const LEVEL_CHUNK_PACKET = 0x3a;
public const SET_COMMANDS_ENABLED_PACKET = 0x3b;
public const SET_DIFFICULTY_PACKET = 0x3c;
public const CHANGE_DIMENSION_PACKET = 0x3d;
@ -159,7 +159,7 @@ interface ProtocolInfo{
public const SET_SCORE_PACKET = 0x6c;
public const LAB_TABLE_PACKET = 0x6d;
public const UPDATE_BLOCK_SYNCED_PACKET = 0x6e;
public const MOVE_ENTITY_DELTA_PACKET = 0x6f;
public const MOVE_ACTOR_DELTA_PACKET = 0x6f;
public const SET_SCOREBOARD_IDENTITY_PACKET = 0x70;
public const SET_LOCAL_PLAYER_AS_INITIALIZED_PACKET = 0x71;
public const UPDATE_SOFT_ENUM_PACKET = 0x72;
@ -167,14 +167,23 @@ interface ProtocolInfo{
public const SCRIPT_CUSTOM_EVENT_PACKET = 0x75;
public const SPAWN_PARTICLE_EFFECT_PACKET = 0x76;
public const AVAILABLE_ENTITY_IDENTIFIERS_PACKET = 0x77;
public const AVAILABLE_ACTOR_IDENTIFIERS_PACKET = 0x77;
public const LEVEL_SOUND_EVENT_PACKET_V2 = 0x78;
public const NETWORK_CHUNK_PUBLISHER_UPDATE_PACKET = 0x79;
public const BIOME_DEFINITION_LIST_PACKET = 0x7a;
public const LEVEL_SOUND_EVENT_PACKET = 0x7b;
public const LECTERN_UPDATE_PACKET = 0x7c;
public const VIDEO_STREAM_CONNECT_PACKET = 0x7d;
public const MAP_CREATE_LOCKED_COPY_PACKET = 0x7e;
public const ON_SCREEN_TEXTURE_ANIMATION_PACKET = 0x7f;
public const LEVEL_EVENT_GENERIC_PACKET = 0x7c;
public const LECTERN_UPDATE_PACKET = 0x7d;
public const VIDEO_STREAM_CONNECT_PACKET = 0x7e;
public const ADD_ENTITY_PACKET = 0x7f;
public const REMOVE_ENTITY_PACKET = 0x80;
public const CLIENT_CACHE_STATUS_PACKET = 0x81;
public const ON_SCREEN_TEXTURE_ANIMATION_PACKET = 0x82;
public const MAP_CREATE_LOCKED_COPY_PACKET = 0x83;
public const STRUCTURE_TEMPLATE_DATA_EXPORT_REQUEST_PACKET = 0x84;
public const STRUCTURE_TEMPLATE_DATA_EXPORT_RESPONSE_PACKET = 0x85;
public const UPDATE_BLOCK_PROPERTIES_PACKET = 0x86;
public const CLIENT_CACHE_BLOB_STATUS_PACKET = 0x87;
public const CLIENT_CACHE_MISS_RESPONSE_PACKET = 0x88;
}

View File

@ -0,0 +1,48 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class RemoveActorPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::REMOVE_ACTOR_PACKET;
/** @var int */
public $entityUniqueId;
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
}
protected function encodePayload(){
$this->putEntityUniqueId($this->entityUniqueId);
}
public function handle(NetworkSession $session) : bool{
return $session->handleRemoveActor($this);
}
}

View File

@ -25,24 +25,36 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class RemoveEntityPacket extends DataPacket{
class RemoveEntityPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::REMOVE_ENTITY_PACKET;
/** @var int */
public $entityUniqueId;
private $uvarint1;
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
public static function create(int $uvarint1) : self{
$result = new self;
$result->uvarint1 = $uvarint1;
return $result;
}
protected function encodePayload(){
$this->putEntityUniqueId($this->entityUniqueId);
/**
* @return int
*/
public function getUvarint1() : int{
return $this->uvarint1;
}
public function handle(NetworkSession $session) : bool{
return $session->handleRemoveEntity($this);
protected function decodePayload() : void{
$this->uvarint1 = $this->getUnsignedVarInt();
}
protected function encodePayload() : void{
$this->putUnsignedVarInt($this->uvarint1);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleRemoveEntity($this);
}
}

View File

@ -28,6 +28,7 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ResourcePackType;
class ResourcePackDataInfoPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::RESOURCE_PACK_DATA_INFO_PACKET;
@ -42,6 +43,10 @@ class ResourcePackDataInfoPacket extends DataPacket{
public $compressedPackSize;
/** @var string */
public $sha256;
/** @var bool */
public $isPremium = false;
/** @var int */
public $packType = ResourcePackType::RESOURCES; //TODO: check the values for this
protected function decodePayload(){
$this->packId = $this->getString();
@ -49,6 +54,8 @@ class ResourcePackDataInfoPacket extends DataPacket{
$this->chunkCount = $this->getLInt();
$this->compressedPackSize = $this->getLLong();
$this->sha256 = $this->getString();
$this->isPremium = $this->getBool();
$this->packType = $this->getByte();
}
protected function encodePayload(){
@ -57,6 +64,8 @@ class ResourcePackDataInfoPacket extends DataPacket{
$this->putLInt($this->chunkCount);
$this->putLLong($this->compressedPackSize);
$this->putString($this->sha256);
$this->putBool($this->isPremium);
$this->putByte($this->packType);
}
public function handle(NetworkSession $session) : bool{

View File

@ -28,8 +28,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class SetEntityDataPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SET_ENTITY_DATA_PACKET;
class SetActorDataPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SET_ACTOR_DATA_PACKET;
/** @var int */
public $entityRuntimeId;
@ -47,6 +47,6 @@ class SetEntityDataPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleSetEntityData($this);
return $session->handleSetActorData($this);
}
}

View File

@ -29,8 +29,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\EntityLink;
class SetEntityLinkPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SET_ENTITY_LINK_PACKET;
class SetActorLinkPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SET_ACTOR_LINK_PACKET;
/** @var EntityLink */
public $link;
@ -44,6 +44,6 @@ class SetEntityLinkPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleSetEntityLink($this);
return $session->handleSetActorLink($this);
}
}

View File

@ -29,8 +29,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
class SetEntityMotionPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SET_ENTITY_MOTION_PACKET;
class SetActorMotionPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SET_ACTOR_MOTION_PACKET;
/** @var int */
public $entityRuntimeId;
@ -48,6 +48,6 @@ class SetEntityMotionPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleSetEntityMotion($this);
return $session->handleSetActorMotion($this);
}
}

View File

@ -61,6 +61,7 @@ class SetScorePacket extends DataPacket{
throw new \UnexpectedValueException("Unknown entry type $entry->type");
}
}
$this->entries[] = $entry;
}
}

View File

@ -32,12 +32,17 @@ use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
use function count;
use function file_get_contents;
use function json_decode;
use const pocketmine\RESOURCE_PATH;
class StartGamePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::START_GAME_PACKET;
/** @var string|null */
private static $runtimeIdTableCache;
private static $blockTableCache = null;
/** @var string|null */
private static $itemTableCache = null;
/** @var int */
public $entityUniqueId;
@ -122,6 +127,8 @@ class StartGamePacket extends DataPacket{
public $isFromWorldTemplate = false;
/** @var bool */
public $isWorldTemplateOptionLocked = false;
/** @var bool */
public $onlySpawnV1Villagers = false;
/** @var string */
public $levelId = ""; //base64 string, usually the same as world folder name in vanilla
@ -138,11 +145,10 @@ class StartGamePacket extends DataPacket{
/** @var string */
public $multiplayerCorrelationId = ""; //TODO: this should be filled with a UUID of some sort
/** @var bool */
public $onlySpawnV1Villagers = false;
/** @var array|null each entry must have a "name" (string) and "data" (int16) element */
public $runtimeIdTable = null;
/** @var array|null ["name" (string), "data" (int16), "legacy_id" (int16)] */
public $blockTable = null;
/** @var array|null string (name) => int16 (legacyID) */
public $itemTable = null;
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
@ -185,6 +191,7 @@ class StartGamePacket extends DataPacket{
$this->useMsaGamertagsOnly = $this->getBool();
$this->isFromWorldTemplate = $this->getBool();
$this->isWorldTemplateOptionLocked = $this->getBool();
$this->onlySpawnV1Villagers = $this->getBool();
$this->levelId = $this->getString();
$this->worldName = $this->getString();
@ -194,18 +201,23 @@ class StartGamePacket extends DataPacket{
$this->enchantmentSeed = $this->getVarInt();
$count = $this->getUnsignedVarInt();
$table = [];
for($i = 0; $i < $count; ++$i){
$this->blockTable = [];
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$id = $this->getString();
$data = $this->getLShort();
$data = $this->getSignedLShort();
$unknown = $this->getSignedLShort();
$table[$i] = ["name" => $id, "data" => $data];
$this->blockTable[$i] = ["name" => $id, "data" => $data, "legacy_id" => $unknown];
}
$this->itemTable = [];
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$id = $this->getString();
$legacyId = $this->getSignedLShort();
$this->itemTable[$id] = $legacyId;
}
$this->runtimeIdTable = $table;
$this->multiplayerCorrelationId = $this->getString();
$this->onlySpawnV1Villagers = $this->getBool();
}
protected function encodePayload(){
@ -249,6 +261,7 @@ class StartGamePacket extends DataPacket{
$this->putBool($this->useMsaGamertagsOnly);
$this->putBool($this->isFromWorldTemplate);
$this->putBool($this->isWorldTemplateOptionLocked);
$this->putBool($this->onlySpawnV1Villagers);
$this->putString($this->levelId);
$this->putString($this->worldName);
@ -258,18 +271,25 @@ class StartGamePacket extends DataPacket{
$this->putVarInt($this->enchantmentSeed);
if($this->runtimeIdTable === null){
if(self::$runtimeIdTableCache === null){
if($this->blockTable === null){
if(self::$blockTableCache === null){
//this is a really nasty hack, but it'll do for now
self::$runtimeIdTableCache = self::serializeBlockTable(RuntimeBlockMapping::getBedrockKnownStates());
self::$blockTableCache = self::serializeBlockTable(RuntimeBlockMapping::getBedrockKnownStates());
}
$this->put(self::$runtimeIdTableCache);
$this->put(self::$blockTableCache);
}else{
$this->put(self::serializeBlockTable($this->runtimeIdTable));
$this->put(self::serializeBlockTable($this->blockTable));
}
if($this->itemTable === null){
if(self::$itemTableCache === null){
self::$itemTableCache = self::serializeItemTable(json_decode(file_get_contents(RESOURCE_PATH . '/vanilla/item_id_map.json'), true));
}
$this->put(self::$itemTableCache);
}else{
$this->put(self::serializeItemTable($this->itemTable));
}
$this->putString($this->multiplayerCorrelationId);
$this->putBool($this->onlySpawnV1Villagers);
}
private static function serializeBlockTable(array $table) : string{
@ -278,6 +298,17 @@ class StartGamePacket extends DataPacket{
foreach($table as $v){
$stream->putString($v["name"]);
$stream->putLShort($v["data"]);
$stream->putLShort($v["legacy_id"]);
}
return $stream->getBuffer();
}
private static function serializeItemTable(array $table) : string{
$stream = new NetworkBinaryStream();
$stream->putUnsignedVarInt(count($table));
foreach($table as $name => $legacyId){
$stream->putString($name);
$stream->putLShort($legacyId);
}
return $stream->getBuffer();
}

View File

@ -0,0 +1,44 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class StructureTemplateDataExportRequestPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_EXPORT_REQUEST_PACKET;
protected function decodePayload() : void{
//TODO
}
protected function encodePayload() : void{
//TODO
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleStructureTemplateDataExportRequest($this);
}
}

View File

@ -0,0 +1,44 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class StructureTemplateDataExportResponsePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_EXPORT_RESPONSE_PACKET;
protected function decodePayload() : void{
//TODO
}
protected function encodePayload() : void{
//TODO
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleStructureTemplateDataExportResponse($this);
}
}

View File

@ -28,8 +28,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class TakeItemEntityPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::TAKE_ITEM_ENTITY_PACKET;
class TakeItemActorPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::TAKE_ITEM_ACTOR_PACKET;
/** @var int */
public $target;
@ -47,6 +47,6 @@ class TakeItemEntityPacket extends DataPacket{
}
public function handle(NetworkSession $session) : bool{
return $session->handleTakeItemEntity($this);
return $session->handleTakeItemActor($this);
}
}

View File

@ -37,7 +37,7 @@ class UnknownPacket extends DataPacket{
public function pid(){
if(strlen($this->payload ?? "") > 0){
return ord($this->payload{0});
return ord($this->payload[0]);
}
return self::NETWORK_ID;
}

View File

@ -25,32 +25,31 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\NetworkSession;
class FullChunkDataPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::FULL_CHUNK_DATA_PACKET;
class UpdateBlockPropertiesPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::UPDATE_BLOCK_PROPERTIES_PACKET;
/** @var int */
public $chunkX;
/** @var int */
public $chunkZ;
/** @var string */
public $data;
private $nbt;
protected function decodePayload(){
$this->chunkX = $this->getVarInt();
$this->chunkZ = $this->getVarInt();
$this->data = $this->getString();
public static function create(CompoundTag $data) : self{
$result = new self;
$result->nbt = (new NetworkLittleEndianNBTStream())->write($data);
return $result;
}
protected function encodePayload(){
$this->putVarInt($this->chunkX);
$this->putVarInt($this->chunkZ);
$this->putString($this->data);
protected function decodePayload() : void{
$this->nbt = $this->getRemaining();
}
public function handle(NetworkSession $session) : bool{
return $session->handleFullChunkData($this);
protected function encodePayload() : void{
$this->put($this->nbt);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleUpdateBlockProperties($this);
}
}

View File

@ -39,17 +39,25 @@ class VideoStreamConnectPacket extends DataPacket/* implements ClientboundPacket
public $frameSendFrequency;
/** @var int */
public $action;
/** @var int */
public $resolutionX;
/** @var int */
public $resolutionY;
protected function decodePayload() : void{
$this->serverUri = $this->getString();
$this->frameSendFrequency = $this->getLFloat();
$this->action = $this->getByte();
$this->resolutionX = $this->getLInt();
$this->resolutionY = $this->getLInt();
}
protected function encodePayload() : void{
$this->putString($this->serverUri);
$this->putLFloat($this->frameSendFrequency);
$this->putByte($this->action);
$this->putLInt($this->resolutionX);
$this->putLInt($this->resolutionY);
}
public function handle(NetworkSession $session) : bool{

View File

@ -0,0 +1,56 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
class ChunkCacheBlob{
/** @var int */
private $hash;
/** @var string */
private $payload;
/**
* ChunkCacheBlob constructor.
*
* @param int $hash
* @param string $payload
*/
public function __construct(int $hash, string $payload){
$this->hash = $hash;
$this->payload = $payload;
}
/**
* @return int
*/
public function getHash() : int{
return $this->hash;
}
/**
* @return string
*/
public function getPayload() : string{
return $this->payload;
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
final class ResourcePackType{
private function __construct(){
//NOOP
}
public const INVALID = 0;
public const RESOURCES = 1;
public const BEHAVIORS = 2;
public const WORLD_TEMPLATE = 3;
public const ADDON = 4; //scripts?
public const SKINS = 5;
}

View File

@ -56,9 +56,11 @@ final class RuntimeBlockMapping{
foreach($compressedTable as $prefix => $entries){
foreach($entries as $shortStringId => $states){
foreach($states as $state){
$name = "$prefix:$shortStringId";
$decompressed[] = [
"name" => "$prefix:$shortStringId",
"data" => $state
"name" => $name,
"data" => $state,
"legacy_id" => $legacyIdMap[$name]
];
}
}
@ -66,11 +68,12 @@ final class RuntimeBlockMapping{
self::$bedrockKnownStates = self::randomizeTable($decompressed);
foreach(self::$bedrockKnownStates as $k => $obj){
//this has to use the json offset to make sure the mapping is consistent with what we send over network, even though we aren't using all the entries
if(!isset($legacyIdMap[$obj["name"]])){
if($obj["data"] > 15){
//TODO: in 1.12 they started using data values bigger than 4 bits which we can't handle right now
continue;
}
self::registerMapping($k, $legacyIdMap[$obj["name"]], $obj["data"]);
//this has to use the json offset to make sure the mapping is consistent with what we send over network, even though we aren't using all the entries
self::registerMapping($k, $obj["legacy_id"], $obj["data"]);
}
}

View File

@ -92,7 +92,7 @@ class QueryHandler{
public function handle(AdvancedSourceInterface $interface, string $address, int $port, string $packet){
$offset = 2;
$packetType = ord($packet{$offset++});
$packetType = ord($packet[$offset++]);
$sessionID = Binary::readInt(substr($packet, $offset, 4));
$offset += 4;
$payload = substr($packet, $offset);

View File

@ -154,7 +154,7 @@ class BanList{
$fp = @fopen($this->file, "r");
if(is_resource($fp)){
while(($line = fgets($fp)) !== false){
if($line{0} !== "#"){
if($line[0] !== "#"){
try{
$entry = BanEntry::fromString($line);
if($entry instanceof BanEntry){

View File

@ -286,7 +286,7 @@ class PluginManager{
$plugins[$name] = $file;
$softDependencies[$name] = $description->getSoftDepend();
$softDependencies[$name] = array_merge($softDependencies[$name] ?? [], $description->getSoftDepend());
$dependencies[$name] = $description->getDepend();
foreach($description->getLoadBefore() as $before){

@ -1 +1 @@
Subproject commit 7d9cec8861a9de033da78bb133f8159f2dfd41c5
Subproject commit b5a8c68c4262e5d9d7f8280c1d07c252a5e8dbf8

View File

@ -34,12 +34,12 @@ use function unserialize;
*
* An AsyncTask does not have its own thread. It is queued into an AsyncPool and executed if there is an async worker
* with no AsyncTask running. Therefore, an AsyncTask SHOULD NOT execute for more than a few seconds. For tasks that
* run for a long time or infinitely, start another {@link \pocketmine\Thread} instead.
* run for a long time or infinitely, start another thread instead.
*
* WARNING: Any non-Threaded objects WILL BE SERIALIZED when assigned to members of AsyncTasks or other Threaded object.
* If later accessed from said Threaded object, you will be operating on a COPY OF THE OBJECT, NOT THE ORIGINAL OBJECT.
* If you want to store non-serializable objects to access when the task completes, store them using
* {@link AsyncTask#storeLocal}.
* {@link AsyncTask::storeLocal}.
*
* WARNING: As of pthreads v3.1.6, arrays are converted to Volatile objects when assigned as members of Threaded objects.
* Keep this in mind when using arrays stored as members of your AsyncTask.
@ -185,8 +185,8 @@ abstract class AsyncTask extends Collectable{
}
/**
* Call this method from {@link AsyncTask#onRun} (AsyncTask execution thread) to schedule a call to
* {@link AsyncTask#onProgressUpdate} from the main thread with the given progress parameter.
* Call this method from {@link AsyncTask::onRun} (AsyncTask execution thread) to schedule a call to
* {@link AsyncTask::onProgressUpdate} from the main thread with the given progress parameter.
*
* @param mixed $progress A value that can be safely serialize()'ed.
*/
@ -207,12 +207,12 @@ abstract class AsyncTask extends Collectable{
}
/**
* Called from the main thread after {@link AsyncTask#publishProgress} is called.
* All {@link AsyncTask#publishProgress} calls should result in {@link AsyncTask#onProgressUpdate} calls before
* {@link AsyncTask#onCompletion} is called.
* Called from the main thread after {@link AsyncTask::publishProgress} is called.
* All {@link AsyncTask::publishProgress} calls should result in {@link AsyncTask::onProgressUpdate} calls before
* {@link AsyncTask::onCompletion} is called.
*
* @param Server $server
* @param mixed $progress The parameter passed to {@link AsyncTask#publishProgress}. It is serialize()'ed
* @param mixed $progress The parameter passed to {@link AsyncTask::publishProgress}. It is serialize()'ed
* and then unserialize()'ed, as if it has been cloned.
*/
public function onProgressUpdate(Server $server, $progress){
@ -221,20 +221,20 @@ abstract class AsyncTask extends Collectable{
/**
* Saves mixed data in thread-local storage on the parent thread. You may use this to retain references to objects
* or arrays which you need to access in {@link AsyncTask#onCompletion} which cannot be stored as a property of
* or arrays which you need to access in {@link AsyncTask::onCompletion} which cannot be stored as a property of
* your task (due to them becoming serialized).
*
* Scalar types can be stored directly in class properties instead of using this storage.
*
* Objects stored in this storage MUST be retrieved through {@link #fetchLocal} when {@link #onCompletion} is called.
* Objects stored in this storage MUST be retrieved through {@link AsyncTask::fetchLocal} when {@link AsyncTask::onCompletion} is called.
* Otherwise, a NOTICE level message will be raised and the reference will be removed after onCompletion exits.
*
* WARNING: Use this method carefully. It might take a long time before an AsyncTask is completed. PocketMine will
* keep a strong reference to objects passed in this method. This may result in a light memory leak. Usually this
* does not cause memory failure, but be aware that the object may be no longer usable when the AsyncTask completes.
* (E.g. a {@link \pocketmine\Level} object is no longer usable because it is unloaded while the AsyncTask is
* executing, or even a plugin might be unloaded). Since PocketMine keeps a strong reference, the objects are still
* valid, but the implementation is responsible for checking whether these objects are still usable.
* (E.g. a Level object is no longer usable because it is unloaded while the AsyncTask is executing, or even a
* plugin might be unloaded). Since PocketMine keeps a strong reference, the objects are still valid, but the
* implementation is responsible for checking whether these objects are still usable.
*
* WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD!
*
@ -259,13 +259,13 @@ abstract class AsyncTask extends Collectable{
/**
* Returns and removes mixed data in thread-local storage on the parent thread. Call this method from
* {@link AsyncTask#onCompletion} to fetch the data stored in the object store, if any.
* {@link AsyncTask::onCompletion} to fetch the data stored in the object store, if any.
*
* If no data was stored in the local store, or if the data was already retrieved by a previous call to fetchLocal,
* do NOT call this method, or an exception will be thrown.
*
* Do not call this method from {@link AsyncTask#onProgressUpdate}, because this method deletes stored data, which
* means that you will not be able to retrieve it again afterwards. Use {@link AsyncTask#peekLocal} instead to
* Do not call this method from {@link AsyncTask::onProgressUpdate}, because this method deletes stored data, which
* means that you will not be able to retrieve it again afterwards. Use {@link AsyncTask::peekLocal} instead to
* retrieve stored data without removing it from the store.
*
* WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD!
@ -287,11 +287,11 @@ abstract class AsyncTask extends Collectable{
/**
* Returns mixed data in thread-local storage on the parent thread **without clearing** it. Call this method from
* {@link AsyncTask#onProgressUpdate} to fetch the data stored if you need to be able to access the data later on,
* {@link AsyncTask::onProgressUpdate} to fetch the data stored if you need to be able to access the data later on,
* such as in another progress update.
*
* Use {@link AsyncTask#fetchLocal} instead from {@link AsyncTask#onCompletion}, because this method does not delete
* the data, and not clearing the data will result in a warning for memory leak after {@link AsyncTask#onCompletion}
* Use {@link AsyncTask::fetchLocal} instead from {@link AsyncTask::onCompletion}, because this method does not delete
* the data, and not clearing the data will result in a warning for memory leak after {@link AsyncTask::onCompletion}
* finished executing.
*
* WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD!

View File

@ -31,9 +31,7 @@ use function unserialize;
/**
* Executes a consecutive list of cURL operations.
*
* The result of this AsyncTask is an array of arrays (returned from {@link Utils::simpleCurl}) or InternetException objects.
*
* @package pocketmine\scheduler
* The result of this AsyncTask is an array of arrays (returned from {@link Internet::simpleCurl}) or InternetException objects.
*/
class BulkCurlTask extends AsyncTask{
private $operations;

View File

@ -28,7 +28,7 @@ use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\BlockEntityDataPacket;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\Player;
abstract class Spawnable extends Tile{
@ -37,8 +37,8 @@ abstract class Spawnable extends Tile{
/** @var NetworkLittleEndianNBTStream|null */
private static $nbtWriter = null;
public function createSpawnPacket() : BlockEntityDataPacket{
$pk = new BlockEntityDataPacket();
public function createSpawnPacket() : BlockActorDataPacket{
$pk = new BlockActorDataPacket();
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;

View File

@ -300,7 +300,7 @@ class MainLogger extends \AttachableThreadedLogger{
$threadName = (new \ReflectionClass($thread))->getShortName() . " thread";
}
$message = sprintf($this->format, $time->format("H:i:s"), $color, $threadName, $prefix, $message);
$message = sprintf($this->format, $time->format("H:i:s"), $color, $threadName, $prefix, TextFormat::clean($message, false));
if(!Terminal::isInit()){
Terminal::init($this->mainThreadHasFormattingCodes); //lazy-init colour codes because we don't know if they've been registered on this thread

View File

@ -455,7 +455,7 @@ class Utils{
public static function javaStringHash(string $string) : int{
$hash = 0;
for($i = 0, $len = strlen($string); $i < $len; $i++){
$ord = ord($string{$i});
$ord = ord($string[$i]);
if($ord & 0x80){
$ord -= 0x100;
}