Merge branch 'stable' into next-minor

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

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){

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;
}