1
0
mirror of https://github.com/pmmp/PocketMine-MP.git synced 2025-06-01 09:47:43 +00:00

Initial update to 1.13

This commit is contained in:
Drew 2019-10-30 21:36:08 -04:00
parent 5edff79f5f
commit cd2b60a860
20 changed files with 408 additions and 164 deletions

@ -160,6 +160,8 @@ use pocketmine\tile\ItemFrame;
use pocketmine\tile\Spawnable; use pocketmine\tile\Spawnable;
use pocketmine\tile\Tile; use pocketmine\tile\Tile;
use pocketmine\timings\Timings; use pocketmine\timings\Timings;
use pocketmine\utils\SerializedImage;
use pocketmine\utils\SkinAnimation;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
use pocketmine\utils\UUID; use pocketmine\utils\UUID;
use function abs; use function abs;
@ -834,12 +836,10 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* Plugin developers should not use this, use setSkin() and sendSkin() instead. * Plugin developers should not use this, use setSkin() and sendSkin() instead.
* *
* @param Skin $skin * @param Skin $skin
* @param string $newSkinName
* @param string $oldSkinName
* *
* @return bool * @return bool
*/ */
public function changeSkin(Skin $skin, string $newSkinName, string $oldSkinName) : bool{ public function changeSkin(Skin $skin) : bool{
if(!$skin->isValid()){ if(!$skin->isValid()){
return false; return false;
} }
@ -1112,9 +1112,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
} }
} }
protected function sendRespawnPacket(Vector3 $pos){ protected function sendRespawnPacket(Vector3 $pos, int $respawnState = 1){
$pk = new RespawnPacket(); $pk = new RespawnPacket();
$pk->position = $pos->add(0, $this->baseOffset, 0); $pk->position = $pos->add(0, $this->baseOffset, 0);
$pk->respawnState = $respawnState;
$pk->entityRuntimeId = $this->getId();
$this->dataPacket($pk); $this->dataPacket($pk);
} }
@ -1913,12 +1915,22 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->uuid = UUID::fromString($packet->clientUUID); $this->uuid = UUID::fromString($packet->clientUUID);
$this->rawUUID = $this->uuid->toBinary(); $this->rawUUID = $this->uuid->toBinary();
$animations = [];
foreach($packet->clientData["AnimatedImageData"] as $animatedData){
$animations[] = new SkinAnimation(new SerializedImage($animatedData["ImageWidth"], $animatedData["ImageHeight"], base64_decode($animatedData["Image"])), $animatedData["Type"], $animatedData["Frames"]);
}
$skin = new Skin( $skin = new Skin(
$packet->clientData["SkinId"], $packet->clientData["SkinId"],
base64_decode($packet->clientData["SkinData"] ?? ""), base64_decode($packet->clientData["SkinResourcePatch"] ?? ""),
base64_decode($packet->clientData["CapeData"] ?? ""), new SerializedImage($packet->clientData["SkinImageHeight"], $packet->clientData["SkinImageWidth"], base64_decode($packet->clientData["SkinData" ?? ""])), //SerializedImage
$packet->clientData["SkinGeometryName"] ?? "", $animations,
base64_decode($packet->clientData["SkinGeometry"] ?? "") new SerializedImage($packet->clientData["CapeImageHeight"], $packet->clientData["CapeImageWidth"], base64_decode($packet->clientData["CapeData"] ?? "")),
base64_decode($packet->clientData["SkinGeometryData"] ?? ""),
base64_decode($packet->clientData["SkinAnimationData"] ?? ""),
(bool) $packet->clientData["PremiumSkin"] ?? false,
(bool) $packet->clientData["PersonaSkin"] ?? false,
(bool) $packet->clientData["CapeOnClassicSkin"] ?? false,
$packet->clientData["CapeId"] ?? ""
); );
if(!$skin->isValid()){ if(!$skin->isValid()){

@ -24,6 +24,8 @@ declare(strict_types=1);
namespace pocketmine\entity; namespace pocketmine\entity;
use Ahc\Json\Comment as CommentedJsonDecoder; use Ahc\Json\Comment as CommentedJsonDecoder;
use pocketmine\utils\SerializedImage;
use pocketmine\utils\SkinAnimation;
use function implode; use function implode;
use function in_array; use function in_array;
use function json_encode; use function json_encode;
@ -39,20 +41,38 @@ class Skin{
/** @var string */ /** @var string */
private $skinId; private $skinId;
/** @var string */ /** @var string */
private $skinResourcePatch;
/** @var SerializedImage */
private $skinData; private $skinData;
/** @var string */ /** @var SkinAnimation[] */
private $animations = [];
/** @var SerializedImage */
private $capeData; private $capeData;
/** @var string */ /** @var string */
private $geometryName;
/** @var string */
private $geometryData; private $geometryData;
/** @var string */
private $animationData;
/** @var bool */
private $premium;
/** @var bool */
private $persona;
/** @var bool */
private $capeOnClassic;
/** @var string */
private $capeId;
public function __construct(string $skinId, string $skinData, string $capeData = "", string $geometryName = "", string $geometryData = ""){ public function __construct(string $skinId, string $skinResourcePatch, SerializedImage $skinData, array $animations = [], SerializedImage $capeData = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $capeOnClassic = false, string $capeId = ""){
$this->skinId = $skinId; $this->skinId = $skinId;
$this->skinResourcePatch = $skinResourcePatch;
$this->skinData = $skinData; $this->skinData = $skinData;
$this->animations = $animations;
$this->capeData = $capeData; $this->capeData = $capeData;
$this->geometryName = $geometryName;
$this->geometryData = $geometryData; $this->geometryData = $geometryData;
$this->animationData = $animationData;
$this->premium = $premium;
$this->persona = $persona;
$this->capeOnClassic = $capeOnClassic;
$this->capeId = $capeId;
} }
/** /**
@ -75,13 +95,14 @@ class Skin{
if($this->skinId === ""){ if($this->skinId === ""){
throw new \InvalidArgumentException("Skin ID must not be empty"); throw new \InvalidArgumentException("Skin ID must not be empty");
} }
$len = strlen($this->skinData); //Broken with Persona skins
/*$len = strlen($this->skinData->getData());
if(!in_array($len, self::ACCEPTED_SKIN_SIZES, true)){ if(!in_array($len, self::ACCEPTED_SKIN_SIZES, true)){
throw new \InvalidArgumentException("Invalid skin data size $len bytes (allowed sizes: " . implode(", ", self::ACCEPTED_SKIN_SIZES) . ")"); throw new \InvalidArgumentException("Invalid skin data size $len bytes (allowed sizes: " . implode(", ", self::ACCEPTED_SKIN_SIZES) . ")");
} }
if($this->capeData !== "" and strlen($this->capeData) !== 8192){ if($this->capeData->getData() !== "" and strlen($this->capeData->getData()) !== 8192){
throw new \InvalidArgumentException("Invalid cape data size " . strlen($this->capeData) . " bytes (must be exactly 8192 bytes)"); throw new \InvalidArgumentException("Invalid cape data size " . strlen($this->capeData->getData()) . " bytes (must be exactly 8192 bytes)");
} }*/
//TODO: validate geometry //TODO: validate geometry
} }
@ -95,22 +116,29 @@ class Skin{
/** /**
* @return string * @return string
*/ */
public function getSkinData() : string{ public function getSkinResourcePatch() : string{
return $this->skinResourcePatch;
}
/**
* @return SerializedImage
*/
public function getSkinData() : SerializedImage{
return $this->skinData; return $this->skinData;
} }
/** /**
* @return string * @return SkinAnimation[]
*/ */
public function getCapeData() : string{ public function getAnimations() : array{
return $this->capeData; return $this->animations;
} }
/** /**
* @return string * @return SerializedImage
*/ */
public function getGeometryName() : string{ public function getCapeData() : SerializedImage{
return $this->geometryName; return $this->capeData;
} }
/** /**
@ -120,6 +148,48 @@ class Skin{
return $this->geometryData; return $this->geometryData;
} }
/**
* @return string
*/
public function getAnimationData() : string{
return $this->animationData;
}
/**
* @return bool
*/
public function getPremium() : bool{
return $this->premium;
}
/**
* @return bool
*/
public function getPersona() : bool{
return $this->persona;
}
/**
* @return bool
*/
public function getCapeOnClassic() : bool{
return $this->capeOnClassic;
}
/**
* @return string
*/
public function getCapeId() : string{
return $this->capeId;
}
/**
* @return string
*/
public function getFullSkinId() : string{
return $this->skinId . "_" . $this->capeId;
}
/** /**
* Hack to cut down on network overhead due to skins, by un-pretty-printing geometry JSON. * Hack to cut down on network overhead due to skins, by un-pretty-printing geometry JSON.
* *

@ -38,7 +38,6 @@ use pocketmine\level\particle\HugeExplodeSeedParticle;
use pocketmine\level\utils\SubChunkIteratorManager; use pocketmine\level\utils\SubChunkIteratorManager;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\ExplodePacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\tile\Chest; use pocketmine\tile\Chest;
use pocketmine\tile\Container; use pocketmine\tile\Container;
@ -260,12 +259,6 @@ class Explosion{
$send[] = new Vector3($block->x - $source->x, $block->y - $source->y, $block->z - $source->z); $send[] = new Vector3($block->x - $source->x, $block->y - $source->y, $block->z - $source->z);
} }
$pk = new ExplodePacket();
$pk->position = $this->source->asVector3();
$pk->radius = $this->size;
$pk->records = $send;
$this->level->broadcastPacketToViewers($source, $pk);
$this->level->addParticle(new HugeExplodeSeedParticle($source)); $this->level->addParticle(new HugeExplodeSeedParticle($source));
$this->level->broadcastLevelSoundEvent($source, LevelSoundEventPacket::SOUND_EXPLODE); $this->level->broadcastLevelSoundEvent($source, LevelSoundEventPacket::SOUND_EXPLODE);

@ -39,6 +39,7 @@ use pocketmine\network\mcpe\protocol\types\CommandOriginData;
use pocketmine\network\mcpe\protocol\types\EntityLink; use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\network\mcpe\protocol\types\StructureSettings; use pocketmine\network\mcpe\protocol\types\StructureSettings;
use pocketmine\utils\BinaryStream; use pocketmine\utils\BinaryStream;
use pocketmine\utils\SerializedImage;
use pocketmine\utils\UUID; use pocketmine\utils\UUID;
use function count; use function count;
use function strlen; use function strlen;
@ -74,6 +75,19 @@ class NetworkBinaryStream extends BinaryStream{
$this->putLInt($uuid->getPart(2)); $this->putLInt($uuid->getPart(2));
} }
public function putImage(SerializedImage $image) : void{
$this->putLInt($image->getWidth());
$this->putLInt($image->getHeight());
$this->putString($image->getData());
}
public function getImage() : SerializedImage{
$width = $this->getLInt();
$height = $this->getLInt();
$data = $this->getString();
return new SerializedImage($height, $width, $data);
}
public function getSlot() : Item{ public function getSlot() : Item{
$id = $this->getVarInt(); $id = $this->getVarInt();
if($id === 0){ if($id === 0){

@ -247,10 +247,6 @@ abstract class NetworkSession{
return false; return false;
} }
public function handleExplode(ExplodePacket $packet) : bool{
return false;
}
public function handleLevelSoundEventPacketV1(LevelSoundEventPacketV1 $packet) : bool{ public function handleLevelSoundEventPacketV1(LevelSoundEventPacketV1 $packet) : bool{
return false; return false;
} }

@ -248,7 +248,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
} }
public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{ public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{
return $this->player->changeSkin($packet->skin, $packet->newSkinName, $packet->oldSkinName); return $this->player->changeSkin($packet->skin);
} }
public function handleBookEdit(BookEditPacket $packet) : bool{ public function handleBookEdit(BookEditPacket $packet) : bool{

@ -1,73 +0,0 @@
<?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\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use function count;
class ExplodePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::EXPLODE_PACKET;
/** @var Vector3 */
public $position;
/** @var float */
public $radius;
/** @var Vector3[] */
public $records = [];
public function clean(){
$this->records = [];
return parent::clean();
}
protected function decodePayload(){
$this->position = $this->getVector3();
$this->radius = (float) ($this->getVarInt() / 32);
$count = $this->getUnsignedVarInt();
for($i = 0; $i < $count; ++$i){
$x = $y = $z = null;
$this->getSignedBlockPosition($x, $y, $z);
$this->records[$i] = new Vector3($x, $y, $z);
}
}
protected function encodePayload(){
$this->putVector3($this->position);
$this->putVarInt((int) ($this->radius * 32));
$this->putUnsignedVarInt(count($this->records));
if(count($this->records) > 0){
foreach($this->records as $record){
$this->putSignedBlockPosition((int) $record->x, (int) $record->y, (int) $record->z);
}
}
}
public function handle(NetworkSession $session) : bool{
return $session->handleExplode($this);
}
}

@ -54,7 +54,6 @@ class PacketPool{
static::registerPacket(new RiderJumpPacket()); static::registerPacket(new RiderJumpPacket());
static::registerPacket(new UpdateBlockPacket()); static::registerPacket(new UpdateBlockPacket());
static::registerPacket(new AddPaintingPacket()); static::registerPacket(new AddPaintingPacket());
static::registerPacket(new ExplodePacket());
static::registerPacket(new LevelSoundEventPacketV1()); static::registerPacket(new LevelSoundEventPacketV1());
static::registerPacket(new LevelEventPacket()); static::registerPacket(new LevelEventPacket());
static::registerPacket(new BlockEventPacket()); static::registerPacket(new BlockEventPacket());

@ -29,6 +29,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\entity\Skin; use pocketmine\entity\Skin;
use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry; use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\utils\SerializedImage;
use pocketmine\utils\SkinAnimation;
use function count; use function count;
class PlayerListPacket extends DataPacket{ class PlayerListPacket extends DataPacket{
@ -57,22 +59,32 @@ class PlayerListPacket extends DataPacket{
$entry->uuid = $this->getUUID(); $entry->uuid = $this->getUUID();
$entry->entityUniqueId = $this->getEntityUniqueId(); $entry->entityUniqueId = $this->getEntityUniqueId();
$entry->username = $this->getString(); $entry->username = $this->getString();
$skinId = $this->getString();
$skinData = $this->getString();
$capeData = $this->getString();
$geometryName = $this->getString();
$geometryData = $this->getString();
$entry->skin = new Skin(
$skinId,
$skinData,
$capeData,
$geometryName,
$geometryData
);
$entry->xboxUserId = $this->getString(); $entry->xboxUserId = $this->getString();
$entry->platformChatId = $this->getString(); $entry->platformChatId = $this->getString();
$entry->buildPlatform = $this->getLInt();
$skinId = $this->getString();
$skinResourcePatch = $this->getString();
$skinData = $this->getImage();
$animations = [];
for($i = 0; $i < $this->getLInt(); ++$i){
$animations[] = new SkinAnimation($this->getImage(), $this->getLInt(), $this->getLFloat());
}
$capeData = $this->getImage();
$geometryData = $this->getString();
$animationData = $this->getString();
$premium = $this->getBool();
$persona = $this->getBool();
$capeOnClassic = $this->getBool();
$capeId = $this->getString();
$fullSkinId = $this->getString();
$entry->skin = new Skin(
$skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId
);
$entry->isTeacher = $this->getBool();
$entry->isHost = $this->getBool();
}else{ }else{
$entry->uuid = $this->getUUID(); $entry->uuid = $this->getUUID();
} }
@ -89,13 +101,30 @@ class PlayerListPacket extends DataPacket{
$this->putUUID($entry->uuid); $this->putUUID($entry->uuid);
$this->putEntityUniqueId($entry->entityUniqueId); $this->putEntityUniqueId($entry->entityUniqueId);
$this->putString($entry->username); $this->putString($entry->username);
$this->putString($entry->skin->getSkinId());
$this->putString($entry->skin->getSkinData());
$this->putString($entry->skin->getCapeData());
$this->putString($entry->skin->getGeometryName());
$this->putString($entry->skin->getGeometryData());
$this->putString($entry->xboxUserId); $this->putString($entry->xboxUserId);
$this->putString($entry->platformChatId); $this->putString($entry->platformChatId);
$this->putLInt($entry->buildPlatform);
$this->putString($entry->skin->getSkinId());
$this->putString($entry->skin->getSkinResourcePatch());
$this->putImage($entry->skin->getSkinData());
$this->putLInt(count($entry->skin->getAnimations()));
foreach($entry->skin->getAnimations() as $animation){
$this->putImage($animation->getImage());
$this->putLInt($animation->getType());
$this->putLFloat($animation->getFrames());
}
$this->putImage($entry->skin->getCapeData());
$this->putString($entry->skin->getGeometryData());
$this->putString($entry->skin->getAnimationData());
$this->putBool($entry->skin->getPremium());
$this->putBool($entry->skin->getPersona());
$this->putBool($entry->skin->getCapeOnClassic());
$this->putString($entry->skin->getCapeId());
$this->putString($entry->skin->getFullSkinId());
$this->putBool($entry->isTeacher);
$this->putBool($entry->isHost);
}else{ }else{
$this->putUUID($entry->uuid); $this->putUUID($entry->uuid);
} }

@ -27,6 +27,8 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\entity\Skin; use pocketmine\entity\Skin;
use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\NetworkSession;
use pocketmine\utils\SerializedImage;
use pocketmine\utils\SkinAnimation;
use pocketmine\utils\UUID; use pocketmine\utils\UUID;
class PlayerSkinPacket extends DataPacket{ class PlayerSkinPacket extends DataPacket{
@ -34,43 +36,53 @@ class PlayerSkinPacket extends DataPacket{
/** @var UUID */ /** @var UUID */
public $uuid; public $uuid;
/** @var string */
public $oldSkinName = "";
/** @var string */
public $newSkinName = "";
/** @var Skin */ /** @var Skin */
public $skin; public $skin;
/** @var bool */
public $premiumSkin = false;
protected function decodePayload(){ protected function decodePayload(){
$this->uuid = $this->getUUID(); $this->uuid = $this->getUUID();
$skinId = $this->getString(); $skinId = $this->getString();
$this->newSkinName = $this->getString(); $skinResourcePatch = $this->getString();
$this->oldSkinName = $this->getString(); $skinData = $this->getImage();
$skinData = $this->getString(); $animations = [];
$capeData = $this->getString(); for($i = 0; $i < $this->getLInt(); ++$i){
$geometryModel = $this->getString(); $animations[] = new SkinAnimation($this->getImage(), $this->getLInt(), $this->getLFloat());
}
$capeData = $this->getImage();
$geometryData = $this->getString(); $geometryData = $this->getString();
$animationData = $this->getString();
$premium = $this->getBool();
$persona = $this->getBool();
$capeOnClassic = $this->getBool();
$capeId = $this->getString();
$fullSkinId = $this->getString();
$this->skin = new Skin($skinId, $skinData, $capeData, $geometryModel, $geometryData); $this->skin = new Skin(
$skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId
$this->premiumSkin = $this->getBool(); );
} }
protected function encodePayload(){ protected function encodePayload(){
$this->putUUID($this->uuid); $this->putUUID($this->uuid);
$this->putString($this->skin->getSkinId()); $this->putString($this->skin->getSkinId());
$this->putString($this->newSkinName); $this->putString($this->skin->getSkinResourcePatch());
$this->putString($this->oldSkinName); $this->putImage($this->skin->getSkinData());
$this->putString($this->skin->getSkinData()); $this->putLInt(count($this->skin->getAnimations()));
$this->putString($this->skin->getCapeData()); foreach($this->skin->getAnimations() as $animation){
$this->putString($this->skin->getGeometryName()); $this->putImage($animation->getImage());
$this->putLInt($animation->getType());
$this->putLFloat($animation->getFrames());
}
$this->putImage($this->skin->getCapeData());
$this->putString($this->skin->getGeometryData()); $this->putString($this->skin->getGeometryData());
$this->putString($this->skin->getAnimationData());
$this->putBool($this->premiumSkin); $this->putBool($this->skin->getPremium());
$this->putBool($this->skin->getPersona());
$this->putBool($this->skin->getCapeOnClassic());
$this->putString($this->skin->getCapeId());
$this->putString($this->skin->getFullSkinId());
} }
public function handle(NetworkSession $session) : bool{ public function handle(NetworkSession $session) : bool{

@ -39,15 +39,15 @@ interface ProtocolInfo{
/** /**
* Actual Minecraft: PE protocol version * Actual Minecraft: PE protocol version
*/ */
public const CURRENT_PROTOCOL = 361; public const CURRENT_PROTOCOL = 388;
/** /**
* Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. * Current Minecraft PE version reported by the server. This is usually the earliest currently supported version.
*/ */
public const MINECRAFT_VERSION = 'v1.12.0'; public const MINECRAFT_VERSION = 'v1.13.0';
/** /**
* Version number sent to clients in ping responses. * Version number sent to clients in ping responses.
*/ */
public const MINECRAFT_VERSION_NETWORK = '1.12.0'; public const MINECRAFT_VERSION_NETWORK = '1.13.0';
public const LOGIN_PACKET = 0x01; public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02; public const PLAY_STATUS_PACKET = 0x02;
@ -71,7 +71,7 @@ interface ProtocolInfo{
public const RIDER_JUMP_PACKET = 0x14; public const RIDER_JUMP_PACKET = 0x14;
public const UPDATE_BLOCK_PACKET = 0x15; public const UPDATE_BLOCK_PACKET = 0x15;
public const ADD_PAINTING_PACKET = 0x16; public const ADD_PAINTING_PACKET = 0x16;
public const EXPLODE_PACKET = 0x17; public const TICK_SYNC_PACKET = 0x17;
public const LEVEL_SOUND_EVENT_PACKET_V1 = 0x18; public const LEVEL_SOUND_EVENT_PACKET_V1 = 0x18;
public const LEVEL_EVENT_PACKET = 0x19; public const LEVEL_EVENT_PACKET = 0x19;
public const BLOCK_EVENT_PACKET = 0x1a; public const BLOCK_EVENT_PACKET = 0x1a;
@ -185,5 +185,13 @@ interface ProtocolInfo{
public const UPDATE_BLOCK_PROPERTIES_PACKET = 0x86; public const UPDATE_BLOCK_PROPERTIES_PACKET = 0x86;
public const CLIENT_CACHE_BLOB_STATUS_PACKET = 0x87; public const CLIENT_CACHE_BLOB_STATUS_PACKET = 0x87;
public const CLIENT_CACHE_MISS_RESPONSE_PACKET = 0x88; public const CLIENT_CACHE_MISS_RESPONSE_PACKET = 0x88;
public const EDUCATION_SETTINGS_PACKET = 0x89;
public const EMOTE_PACKET = 0x8a;
public const MULTIPLAYER_SETTINGS_PACKET = 0x8b;
public const SETTINGS_COMMAND_PACKET = 0x8c;
public const ANVIL_DAMAGE_PACKET = 0x8d;
public const COMPLETED_USING_ITEM_PACKET = 0x8e;
public const NETWORK_SETTINGS_PACKET = 0x8f;
public const PLAYER_AUTH_INPUT_PACKET = 0x90;
} }

@ -46,15 +46,14 @@ class ResourcePackChunkDataPacket extends DataPacket{
$this->packId = $this->getString(); $this->packId = $this->getString();
$this->chunkIndex = $this->getLInt(); $this->chunkIndex = $this->getLInt();
$this->progress = $this->getLLong(); $this->progress = $this->getLLong();
$this->data = $this->get($this->getLInt()); $this->data = $this->getString();
} }
protected function encodePayload(){ protected function encodePayload(){
$this->putString($this->packId); $this->putString($this->packId);
$this->putLInt($this->chunkIndex); $this->putLInt($this->chunkIndex);
$this->putLLong($this->progress); $this->putLLong($this->progress);
$this->putLInt(strlen($this->data)); $this->putString($this->data);
$this->put($this->data);
} }
public function handle(NetworkSession $session) : bool{ public function handle(NetworkSession $session) : bool{

@ -34,13 +34,21 @@ class RespawnPacket extends DataPacket{
/** @var Vector3 */ /** @var Vector3 */
public $position; public $position;
/** @var int */
public $respawnState = 1; //TODO: Add
/** @var int */
public $entityRuntimeId;
protected function decodePayload(){ protected function decodePayload(){
$this->position = $this->getVector3(); $this->position = $this->getVector3();
$this->respawnState = $this->getInt();
$this->entityRuntimeId = $this->getEntityRuntimeId();
} }
protected function encodePayload(){ protected function encodePayload(){
$this->putVector3($this->position); $this->putVector3($this->position);
$this->putInt($this->respawnState);
$this->putEntityRuntimeId($this->entityRuntimeId);
} }
public function handle(NetworkSession $session) : bool{ public function handle(NetworkSession $session) : bool{

@ -27,6 +27,10 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\NetworkBinaryStream; use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions; use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
@ -130,6 +134,8 @@ class StartGamePacket extends DataPacket{
/** @var bool */ /** @var bool */
public $onlySpawnV1Villagers = false; public $onlySpawnV1Villagers = false;
/** @var string */
public $vanillaVersion = ProtocolInfo::MINECRAFT_VERSION_NETWORK;
/** @var string */ /** @var string */
public $levelId = ""; //base64 string, usually the same as world folder name in vanilla public $levelId = ""; //base64 string, usually the same as world folder name in vanilla
/** @var string */ /** @var string */
@ -138,6 +144,8 @@ class StartGamePacket extends DataPacket{
public $premiumWorldTemplateId = ""; public $premiumWorldTemplateId = "";
/** @var bool */ /** @var bool */
public $isTrial = false; public $isTrial = false;
/** @var bool */
public $isMovementServerAuthoritative = false;
/** @var int */ /** @var int */
public $currentTick = 0; //only used if isTrial is true public $currentTick = 0; //only used if isTrial is true
/** @var int */ /** @var int */
@ -193,10 +201,12 @@ class StartGamePacket extends DataPacket{
$this->isWorldTemplateOptionLocked = $this->getBool(); $this->isWorldTemplateOptionLocked = $this->getBool();
$this->onlySpawnV1Villagers = $this->getBool(); $this->onlySpawnV1Villagers = $this->getBool();
$this->vanillaVersion = $this->getString();
$this->levelId = $this->getString(); $this->levelId = $this->getString();
$this->worldName = $this->getString(); $this->worldName = $this->getString();
$this->premiumWorldTemplateId = $this->getString(); $this->premiumWorldTemplateId = $this->getString();
$this->isTrial = $this->getBool(); $this->isTrial = $this->getBool();
$this->isMovementServerAuthoritative = $this->getBool();
$this->currentTick = $this->getLLong(); $this->currentTick = $this->getLLong();
$this->enchantmentSeed = $this->getVarInt(); $this->enchantmentSeed = $this->getVarInt();
@ -263,10 +273,12 @@ class StartGamePacket extends DataPacket{
$this->putBool($this->isWorldTemplateOptionLocked); $this->putBool($this->isWorldTemplateOptionLocked);
$this->putBool($this->onlySpawnV1Villagers); $this->putBool($this->onlySpawnV1Villagers);
$this->putString($this->vanillaVersion);
$this->putString($this->levelId); $this->putString($this->levelId);
$this->putString($this->worldName); $this->putString($this->worldName);
$this->putString($this->premiumWorldTemplateId); $this->putString($this->premiumWorldTemplateId);
$this->putBool($this->isTrial); $this->putBool($this->isTrial);
$this->putBool($this->isMovementServerAuthoritative);
$this->putLLong($this->currentTick); $this->putLLong($this->currentTick);
$this->putVarInt($this->enchantmentSeed); $this->putVarInt($this->enchantmentSeed);
@ -293,14 +305,27 @@ class StartGamePacket extends DataPacket{
} }
private static function serializeBlockTable(array $table) : string{ private static function serializeBlockTable(array $table) : string{
$stream = new NetworkBinaryStream(); $states = new ListTag();
foreach($table as $v){
$state = new CompoundTag();
$state->setTag(new CompoundTag("block", [
new StringTag("name", $v["name"]),
$v["states"]
]));
$state->setShort("id", $v["legacy_id"]);
$states->push($state);
}
($stream = new NetworkLittleEndianNBTStream())->writeTag($states);
return $stream->buffer;
/*$stream = new NetworkBinaryStream();
$stream->putUnsignedVarInt(count($table)); $stream->putUnsignedVarInt(count($table));
foreach($table as $v){ foreach($table as $v){
$stream->putString($v["name"]); $stream->putString($v["name"]);
$stream->putLShort($v["data"]); $stream->putLShort($v["data"]);
$stream->putLShort($v["legacy_id"]); $stream->putLShort($v["legacy_id"]);
} }
return $stream->getBuffer(); return $stream->getBuffer();*/
} }
private static function serializeItemTable(array $table) : string{ private static function serializeItemTable(array $table) : string{

@ -34,12 +34,18 @@ class PlayerListEntry{
public $entityUniqueId; public $entityUniqueId;
/** @var string */ /** @var string */
public $username; public $username;
/** @var Skin */
public $skin;
/** @var string */ /** @var string */
public $xboxUserId; public $xboxUserId;
/** @var string */ /** @var string */
public $platformChatId = ""; public $platformChatId = "";
/** @var int */
public $buildPlatform = 0; //Unknown
/** @var Skin */
public $skin;
/** @var bool */
public $isTeacher = false;
/** @var bool */
public $isHost = false;
public static function createRemovalEntry(UUID $uuid) : PlayerListEntry{ public static function createRemovalEntry(UUID $uuid) : PlayerListEntry{
$entry = new PlayerListEntry(); $entry = new PlayerListEntry();
@ -48,7 +54,7 @@ class PlayerListEntry{
return $entry; return $entry;
} }
public static function createAdditionEntry(UUID $uuid, int $entityUniqueId, string $username, Skin $skin, string $xboxUserId = "", string $platformChatId = "") : PlayerListEntry{ public static function createAdditionEntry(UUID $uuid, int $entityUniqueId, string $username, Skin $skin, string $xboxUserId = "", string $platformChatId = "", int $buildPlatform = 0, bool $isTeacher = false, bool $isHost = false) : PlayerListEntry{
$entry = new PlayerListEntry(); $entry = new PlayerListEntry();
$entry->uuid = $uuid; $entry->uuid = $uuid;
$entry->entityUniqueId = $entityUniqueId; $entry->entityUniqueId = $entityUniqueId;
@ -56,6 +62,9 @@ class PlayerListEntry{
$entry->skin = $skin; $entry->skin = $skin;
$entry->xboxUserId = $xboxUserId; $entry->xboxUserId = $xboxUserId;
$entry->platformChatId = $platformChatId; $entry->platformChatId = $platformChatId;
$entry->buildPlatform = $buildPlatform;
$entry->isTeacher = $isTeacher;
$entry->isHost = $isHost;
return $entry; return $entry;
} }

@ -29,6 +29,7 @@ final class ResourcePackType{
//NOOP //NOOP
} }
//Needs updated
public const INVALID = 0; public const INVALID = 0;
public const RESOURCES = 1; public const RESOURCES = 1;
public const BEHAVIORS = 2; public const BEHAVIORS = 2;

@ -24,6 +24,9 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types; namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\block\BlockIds; use pocketmine\block\BlockIds;
use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\utils\BinaryDataException;
use function file_get_contents; use function file_get_contents;
use function getmypid; use function getmypid;
use function json_decode; use function json_decode;
@ -51,8 +54,29 @@ final class RuntimeBlockMapping{
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true); $legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true);
$compressedTable = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/required_block_states.json"), true); $compressedTable = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/required_block_states.json"), true);
try{
/** @var CompoundTag $tag */
$tag = (new BigEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "runtime_block_states.dat"));
}catch(BinaryDataException $e){
throw new \RuntimeException("", 0, $e);
}
$decompressed = []; $decompressed = [];
$states = $tag->getListTag("Palette");
foreach($states as $state){
/** @var CompoundTag $state */
$block = $state->getCompoundTag("block");
$decompressed[] = [
"name" => $block->getString("name"),
"states" => $block->getCompoundTag("states"),
"data" => $state->getShort("meta"),
"legacy_id" => $state->getShort("id"),
];
}
/*
foreach($compressedTable as $prefix => $entries){ foreach($compressedTable as $prefix => $entries){
foreach($entries as $shortStringId => $states){ foreach($entries as $shortStringId => $states){
foreach($states as $state){ foreach($states as $state){
@ -63,8 +87,7 @@ final class RuntimeBlockMapping{
"legacy_id" => $legacyIdMap[$name] "legacy_id" => $legacyIdMap[$name]
]; ];
} }
} }*/
}
self::$bedrockKnownStates = self::randomizeTable($decompressed); self::$bedrockKnownStates = self::randomizeTable($decompressed);
foreach(self::$bedrockKnownStates as $k => $obj){ foreach(self::$bedrockKnownStates as $k => $obj){

Binary file not shown.

@ -0,0 +1,67 @@
<?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\utils;
class SerializedImage{
/** @var int */
private $height;
/** @var int */
private $width;
/** @var string */
private $data;
public function __construct(int $height, int $width, string $data){
$this->height = $height;
$this->width = $width;
$this->data = $data;
}
public static function fromLegacy(string $data) : SerializedImage{
switch(strlen($data)){
case 64 * 32 * 4:
return new self(64, 32, $data);
case 64 * 64 * 4:
return new self(64, 64, $data);
case 128 * 64 * 4:
return new self(128, 64, $data);
case 128 * 128 * 4:
return new self(128, 128, $data);
}
throw new \InvalidArgumentException("Unknown size");
}
public function getHeight() : int{
return $this->height;
}
public function getWidth() : int{
return $this->width;
}
public function getData() : string{
return $this->data;
}
}

@ -0,0 +1,52 @@
<?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\utils;
class SkinAnimation{
/** @var SerializedImage */
private $image;
/** @var int */
private $type;
/** @var float */
private $frames;
public function __construct(SerializedImage $image, int $type, float $frames){
$this->image = $image;
$this->type = $type;
$this->frames = $frames;
}
public function getImage() : SerializedImage{
return $this->image;
}
public function getType() : int{
return $this->type;
}
public function getFrames() : float{
return $this->frames;
}
}