Merge branch 'master' into mcpe-1.2.5

This commit is contained in:
Dylan K. Taylor 2017-11-21 16:48:18 +00:00
commit 1fd9994056
235 changed files with 5493 additions and 2406 deletions

3
.gitignore vendored
View File

@ -34,3 +34,6 @@ vendor/*
# Travis files
test_data/*
# Doxygen
Documentation/*

View File

@ -21,7 +21,7 @@
"ext-yaml": ">=2.0.0",
"ext-zip": "*",
"ext-zlib": ">=1.2.11",
"pmmp/raklib": "^0.9.0",
"pmmp/raklib": "dev-master#2b76936eb4a5b053128fe98050f33993cb3d8016",
"pmmp/pocketmine-spl": "^0.0.2"
},
"autoload": {

17
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "55bdbaf13ac4ea71f0705f03f715172d",
"content-hash": "2ef1e62099624431c885378a43b84cca",
"packages": [
{
"name": "pmmp/pocketmine-spl",
@ -40,16 +40,16 @@
},
{
"name": "pmmp/raklib",
"version": "0.9.0",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
"reference": "08470471eb16b4325fa02415fd12c5060eba9c34"
"reference": "2b76936eb4a5b053128fe98050f33993cb3d8016"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/08470471eb16b4325fa02415fd12c5060eba9c34",
"reference": "08470471eb16b4325fa02415fd12c5060eba9c34",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/2b76936eb4a5b053128fe98050f33993cb3d8016",
"reference": "2b76936eb4a5b053128fe98050f33993cb3d8016",
"shasum": ""
},
"require": {
@ -70,10 +70,10 @@
],
"description": "A RakNet server implementation written in PHP",
"support": {
"source": "https://github.com/pmmp/RakLib/tree/0.9.0",
"source": "https://github.com/pmmp/RakLib/tree/master",
"issues": "https://github.com/pmmp/RakLib/issues"
},
"time": "2017-11-14T19:03:14+00:00"
"time": "2017-11-21T14:32:13+00:00"
}
],
"packages-dev": [],
@ -81,7 +81,8 @@
"minimum-stability": "stable",
"stability-flags": {
"php": 5,
"ext-pthreads": 20
"ext-pthreads": 20,
"pmmp/raklib": 20
},
"prefer-stable": false,
"prefer-lowest": false,

2322
doxygen.conf Normal file

File diff suppressed because it is too large Load Diff

View File

@ -108,11 +108,11 @@ class OfflinePlayer implements IPlayer, Metadatable{
}
public function getFirstPlayed(){
return $this->namedtag instanceof CompoundTag ? $this->namedtag["firstPlayed"] : null;
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("firstPlayed", 0, true) : null;
}
public function getLastPlayed(){
return $this->namedtag instanceof CompoundTag ? $this->namedtag["lastPlayed"] : null;
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("lastPlayed", 0, true) : null;
}
public function hasPlayedBefore() : bool{

View File

@ -39,8 +39,6 @@ use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\inventory\InventoryCloseEvent;
use pocketmine\event\inventory\InventoryPickupArrowEvent;
use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\event\player\cheat\PlayerIllegalMoveEvent;
use pocketmine\event\player\PlayerAchievementAwardedEvent;
use pocketmine\event\player\PlayerAnimationEvent;
@ -97,6 +95,7 @@ use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteTag;
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\AdventureSettingsPacket;
@ -135,7 +134,6 @@ use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket;
use pocketmine\network\mcpe\protocol\SetTitlePacket;
use pocketmine\network\mcpe\protocol\StartGamePacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\TransferPacket;
use pocketmine\network\mcpe\protocol\types\CommandData;
@ -165,11 +163,11 @@ use pocketmine\utils\UUID;
*/
class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
const SURVIVAL = 0;
const CREATIVE = 1;
const ADVENTURE = 2;
const SPECTATOR = 3;
const VIEW = Player::SPECTATOR;
public const SURVIVAL = 0;
public const CREATIVE = 1;
public const ADVENTURE = 2;
public const SPECTATOR = 3;
public const VIEW = Player::SPECTATOR;
/**
* Checks a supplied username and checks it is valid.
@ -204,7 +202,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public $playedBefore;
public $spawned = false;
public $loggedIn = false;
public $joined = false;
public $gamemode;
public $lastBreak;
/** @var bool */
@ -229,8 +226,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public $achievements = [];
public $craftingType = 0; //0 = 2x2 crafting, 1 = 3x3 crafting, 2 = stonecutter
/** @var PlayerCursorInventory */
protected $cursorInventory;
@ -312,7 +307,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* @return TranslationContainer|string
*/
public function getLeaveMessage(){
if($this->joined){
if($this->spawned){
return new TranslationContainer(TextFormat::YELLOW . "%multiplayer.player.left", [
$this->getDisplayName()
]);
@ -400,11 +395,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
public function getFirstPlayed(){
return $this->namedtag instanceof CompoundTag ? $this->namedtag["firstPlayed"] : null;
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("firstPlayed", 0, true) : null;
}
public function getLastPlayed(){
return $this->namedtag instanceof CompoundTag ? $this->namedtag["lastPlayed"] : null;
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("lastPlayed", 0, true) : null;
}
public function hasPlayedBefore() : bool{
@ -1013,8 +1008,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if($this->getHealth() <= 0){
$this->sendRespawnPacket($this->getSpawn());
}
$this->joined = true;
}
protected function sendRespawnPacket(Vector3 $pos){
@ -1319,8 +1312,10 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->allowFlight = $this->isCreative();
if($this->isSpectator()){
$this->flying = true;
$this->keepMovement = true;
$this->despawnFromAll();
}else{
$this->keepMovement = $this->allowMovementCheats;
if($this->isSurvival()){
$this->flying = false;
}
@ -1337,11 +1332,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
$this->sendSettings();
$this->inventory->sendContents($this);
$this->inventory->sendContents($this->getViewers());
$this->inventory->sendHeldItem($this->hasSpawned);
$this->inventory->sendCreativeContents();
return true;
@ -1450,11 +1440,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$bb->minY = $this->y - 0.2;
$bb->maxY = $this->y + 0.2;
if(count($this->level->getCollisionBlocks($bb, true)) > 0){
$this->onGround = true;
}else{
$this->onGround = false;
}
$this->onGround = count($this->level->getCollisionBlocks($bb, true)) > 0;
}
$this->isCollided = $this->onGround;
}
@ -1473,57 +1459,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
continue;
}
if($entity instanceof Arrow and $entity->hadCollision){
$item = ItemFactory::get(Item::ARROW, 0, 1);
if($this->isSurvival() and !$this->inventory->canAddItem($item)){
continue;
}
$this->server->getPluginManager()->callEvent($ev = new InventoryPickupArrowEvent($this->inventory, $entity));
if($ev->isCancelled()){
continue;
}
$pk = new TakeItemEntityPacket();
$pk->eid = $this->id;
$pk->target = $entity->getId();
$this->server->broadcastPacket($entity->getViewers(), $pk);
$this->inventory->addItem(clone $item);
$entity->flagForDespawn();
}elseif($entity instanceof DroppedItem){
if($entity->getPickupDelay() <= 0){
$item = $entity->getItem();
if($item instanceof Item){
if($this->isSurvival() and !$this->inventory->canAddItem($item)){
continue;
}
$this->server->getPluginManager()->callEvent($ev = new InventoryPickupItemEvent($this->inventory, $entity));
if($ev->isCancelled()){
continue;
}
switch($item->getId()){
case Item::WOOD:
$this->awardAchievement("mineWood");
break;
case Item::DIAMOND:
$this->awardAchievement("diamond");
break;
}
$pk = new TakeItemEntityPacket();
$pk->eid = $this->id;
$pk->target = $entity->getId();
$this->server->broadcastPacket($entity->getViewers(), $pk);
$this->inventory->addItem(clone $item);
$entity->flagForDespawn();
}
}
}
$entity->onCollideWithPlayer($this);
}
}
@ -1796,7 +1732,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->orderChunks();
}
if(count($this->loadQueue) > 0 or !$this->spawned){
if(count($this->loadQueue) > 0){
$this->sendNextChunk();
}
@ -1836,6 +1772,100 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->addDefaultWindows();
}
public function handleLogin(LoginPacket $packet) : bool{
if($this->loggedIn){
return false;
}
$this->protocol = $packet->protocol;
if($packet->protocol !== ProtocolInfo::CURRENT_PROTOCOL){
if($packet->protocol < ProtocolInfo::CURRENT_PROTOCOL){
$this->sendPlayStatus(PlayStatusPacket::LOGIN_FAILED_CLIENT, true);
}else{
$this->sendPlayStatus(PlayStatusPacket::LOGIN_FAILED_SERVER, true);
}
//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
$this->close("", $this->server->getLanguage()->translateString("pocketmine.disconnect.incompatibleProtocol", [$packet->protocol ?? "unknown"]), false);
return true;
}
if(!self::isValidUserName($packet->username)){
$this->close("", "disconnectionScreen.invalidName");
return true;
}
$this->username = TextFormat::clean($packet->username);
$this->displayName = $this->username;
$this->iusername = strtolower($this->username);
if($packet->locale !== null){
$this->locale = $packet->locale;
}
if(count($this->server->getOnlinePlayers()) >= $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)){
return true;
}
$this->randomClientId = $packet->clientId;
$this->uuid = UUID::fromString($packet->clientUUID);
$this->rawUUID = $this->uuid->toBinary();
$skin = new Skin(
$packet->clientData["SkinId"],
base64_decode($packet->clientData["SkinData"] ?? ""),
base64_decode($packet->clientData["CapeData"] ?? ""),
$packet->clientData["SkinGeometryName"] ?? "",
base64_decode($packet->clientData["SkinGeometry"] ?? "")
);
$skin->debloatGeometryData();
if(!$skin->isValid()){
$this->close("", "disconnectionScreen.invalidSkin");
return true;
}
$this->setSkin($skin);
if(!$this->server->isWhitelisted($this->iusername) and $this->kick("Server is white-listed", false)){
return true;
}
if(
($this->server->getNameBans()->isBanned($this->iusername) or $this->server->getIPBans()->isBanned($this->getAddress())) and
$this->kick("You are banned", false)
){
return true;
}
$this->server->getPluginManager()->callEvent($ev = new PlayerPreLoginEvent($this, "Plugin reason"));
if($ev->isCancelled()){
$this->close("", $ev->getKickMessage());
return true;
}
if(!$packet->skipVerification){
$this->server->getScheduler()->scheduleAsyncTask(new VerifyLoginTask($this, $packet));
}else{
$this->onVerifyCompleted($packet, true, true);
}
return true;
}
public function sendPlayStatus(int $status, bool $immediate = false){
$pk = new PlayStatusPacket();
$pk->status = $status;
$pk->protocol = $this->protocol;
$this->sendDataPacket($pk, false, $immediate);
}
public function onVerifyCompleted(LoginPacket $packet, bool $isValid, bool $isAuthenticated) : void{
if($this->closed){
return;
@ -1873,13 +1903,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
protected function processLogin(){
foreach($this->server->getLoggedInPlayers() as $p){
if($p !== $this and $p->iusername === $this->iusername){
if($p->kick("logged in from another location") === false){
$this->close($this->getLeaveMessage(), "Logged in from another location");
return;
}
}elseif($p->loggedIn and $this->getUniqueId()->equals($p->getUniqueId())){
if($p !== $this and ($p->iusername === $this->iusername or $this->getUniqueId()->equals($p->getUniqueId()))){
if($p->kick("logged in from another location") === false){
$this->close($this->getLeaveMessage(), "Logged in from another location");
@ -1890,7 +1914,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->namedtag = $this->server->getOfflinePlayerData($this->username);
$this->playedBefore = ($this->namedtag["lastPlayed"] - $this->namedtag["firstPlayed"]) > 1; // microtime(true) - microtime(true) may have less than one millisecond difference
$this->playedBefore = ($this->getLastPlayed() - $this->getFirstPlayed()) > 1; // microtime(true) - microtime(true) may have less than one millisecond difference
$this->namedtag->setString("NameTag", $this->username);
$this->gamemode = $this->namedtag->getInt("playerGameType", self::SURVIVAL) & 0x03;
@ -1900,13 +1924,17 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
$this->allowFlight = $this->isCreative();
$this->keepMovement = $this->isSpectator() || $this->allowMovementCheats();
if(($level = $this->server->getLevelByName((string) $this->namedtag["Level"])) === null){
if(($level = $this->server->getLevelByName($this->namedtag->getString("Level", "", true))) === null){
$this->setLevel($this->server->getDefaultLevel());
$this->namedtag["Level"] = $this->level->getName();
$this->namedtag["Pos"][0] = $this->level->getSpawnLocation()->x;
$this->namedtag["Pos"][1] = $this->level->getSpawnLocation()->y;
$this->namedtag["Pos"][2] = $this->level->getSpawnLocation()->z;
$this->namedtag->setString("Level", $this->level->getName());
$spawnLocation = $this->level->getSpawnLocation();
$this->namedtag->setTag(new ListTag("Pos", [
new DoubleTag("", $spawnLocation->x),
new DoubleTag("", $spawnLocation->y),
new DoubleTag("", $spawnLocation->z)
]));
}else{
$this->setLevel($level);
}
@ -1936,6 +1964,51 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->dataPacket($pk);
}
public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
switch($packet->status){
case ResourcePackClientResponsePacket::STATUS_REFUSED:
//TODO: add lang strings for this
$this->close("", "You must accept resource packs to join this server.", true);
break;
case ResourcePackClientResponsePacket::STATUS_SEND_PACKS:
$manager = $this->server->getResourceManager();
foreach($packet->packIds as $uuid){
$pack = $manager->getPackById($uuid);
if(!($pack instanceof ResourcePack)){
//Client requested a resource pack but we don't have it available on the server
$this->close("", "disconnectionScreen.resourcePack", true);
$this->server->getLogger()->debug("Got a resource pack request for unknown pack with UUID " . $uuid . ", available packs: " . implode(", ", $manager->getPackIdList()));
return false;
}
$pk = new ResourcePackDataInfoPacket();
$pk->packId = $pack->getPackId();
$pk->maxChunkSize = 1048576; //1MB
$pk->chunkCount = (int) ceil($pack->getPackSize() / $pk->maxChunkSize);
$pk->compressedPackSize = $pack->getPackSize();
$pk->sha256 = $pack->getSha256();
$this->dataPacket($pk);
}
break;
case ResourcePackClientResponsePacket::STATUS_HAVE_ALL_PACKS:
$pk = new ResourcePackStackPacket();
$manager = $this->server->getResourceManager();
$pk->resourcePackStack = $manager->getResourceStack();
$pk->mustAccept = $manager->resourcePacksRequired();
$this->dataPacket($pk);
break;
case ResourcePackClientResponsePacket::STATUS_COMPLETED:
$this->completeLoginSequence();
break;
default:
return false;
}
return true;
}
protected function completeLoginSequence(){
parent::__construct($this->level, $this->namedtag);
$this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason"));
@ -1984,9 +2057,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->level->sendTime($this);
$this->sendAttributes(true);
$this->setNameTagVisible(true);
$this->setNameTagAlwaysVisible(true);
$this->setCanClimb(true);
$this->setNameTagVisible();
$this->setNameTagAlwaysVisible();
$this->setCanClimb();
$this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logIn", [
TextFormat::AQUA . $this->username . TextFormat::WHITE,
@ -2017,138 +2090,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->server->onPlayerCompleteLoginSequence($this);
}
public function handleLogin(LoginPacket $packet) : bool{
if($this->loggedIn){
return false;
}
$this->protocol = $packet->protocol;
if($packet->protocol !== ProtocolInfo::CURRENT_PROTOCOL){
if($packet->protocol < ProtocolInfo::CURRENT_PROTOCOL){
$this->sendPlayStatus(PlayStatusPacket::LOGIN_FAILED_CLIENT, true);
}else{
$this->sendPlayStatus(PlayStatusPacket::LOGIN_FAILED_SERVER, true);
}
//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
$this->close("", $this->server->getLanguage()->translateString("pocketmine.disconnect.incompatibleProtocol", [$packet->protocol ?? "unknown"]), false);
return true;
}
if(!self::isValidUserName($packet->username)){
$this->close("", "disconnectionScreen.invalidName");
return true;
}
$this->username = TextFormat::clean($packet->username);
$this->displayName = $this->username;
$this->iusername = strtolower($this->username);
if($packet->locale !== null){
$this->locale = $packet->locale;
}
if(count($this->server->getOnlinePlayers()) >= $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)){
return true;
}
$this->randomClientId = $packet->clientId;
$this->uuid = UUID::fromString($packet->clientUUID);
$this->rawUUID = $this->uuid->toBinary();
$skin = new Skin(
$packet->clientData["SkinId"],
base64_decode($packet->clientData["SkinData"] ?? ""),
base64_decode($packet->clientData["CapeData"] ?? ""),
$packet->clientData["SkinGeometryName"],
base64_decode($packet->clientData["SkinGeometry"] ?? "")
);
$skin->debloatGeometryData();
if(!$skin->isValid()){
$this->close("", "disconnectionScreen.invalidSkin");
return true;
}
$this->setSkin($skin);
if(!$this->server->isWhitelisted($this->iusername) and $this->kick("Server is white-listed", false)){
return true;
}
if(
($this->server->getNameBans()->isBanned($this->iusername) or $this->server->getIPBans()->isBanned($this->getAddress())) and
$this->kick("You are banned", false)
){
return true;
}
$this->server->getPluginManager()->callEvent($ev = new PlayerPreLoginEvent($this, "Plugin reason"));
if($ev->isCancelled()){
$this->close("", $ev->getKickMessage());
return true;
}
$this->server->getScheduler()->scheduleAsyncTask(new VerifyLoginTask($this, $packet));
return true;
}
public function sendPlayStatus(int $status, bool $immediate = false){
$pk = new PlayStatusPacket();
$pk->status = $status;
$pk->protocol = $this->protocol;
$this->sendDataPacket($pk, false, $immediate);
}
public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
switch($packet->status){
case ResourcePackClientResponsePacket::STATUS_REFUSED:
//TODO: add lang strings for this
$this->close("", "You must accept resource packs to join this server.", true);
break;
case ResourcePackClientResponsePacket::STATUS_SEND_PACKS:
$manager = $this->server->getResourceManager();
foreach($packet->packIds as $uuid){
$pack = $manager->getPackById($uuid);
if(!($pack instanceof ResourcePack)){
//Client requested a resource pack but we don't have it available on the server
$this->close("", "disconnectionScreen.resourcePack", true);
$this->server->getLogger()->debug("Got a resource pack request for unknown pack with UUID " . $uuid . ", available packs: " . implode(", ", $manager->getPackIdList()));
return false;
}
$pk = new ResourcePackDataInfoPacket();
$pk->packId = $pack->getPackId();
$pk->maxChunkSize = 1048576; //1MB
$pk->chunkCount = (int) ceil($pack->getPackSize() / $pk->maxChunkSize);
$pk->compressedPackSize = $pack->getPackSize();
$pk->sha256 = $pack->getSha256();
$this->dataPacket($pk);
}
break;
case ResourcePackClientResponsePacket::STATUS_HAVE_ALL_PACKS:
$pk = new ResourcePackStackPacket();
$manager = $this->server->getResourceManager();
$pk->resourcePackStack = $manager->getResourceStack();
$pk->mustAccept = $manager->resourcePacksRequired();
$this->dataPacket($pk);
break;
case ResourcePackClientResponsePacket::STATUS_COMPLETED:
$this->completeLoginSequence();
break;
default:
return false;
}
return true;
}
/**
* Sends a chat message as this player. If the message begins with a / (forward-slash) it will be treated
* as a command.
@ -2708,6 +2649,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
case PlayerActionPacket::ACTION_STOP_BREAK:
$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_BLOCK_STOP_BREAK);
break;
case PlayerActionPacket::ACTION_START_SLEEPING:
//unused
break;
case PlayerActionPacket::ACTION_STOP_SLEEPING:
$this->stopSleep();
break;
@ -2881,16 +2825,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return false;
}
public function handlePlayerHotbar(PlayerHotbarPacket $packet){
if($packet->windowId !== ContainerIds::INVENTORY){
return false; //In PE this should never happen
}
$this->inventory->equipItem($packet->selectedHotbarSlot);
return true;
}
public function handleAdventureSettings(AdventureSettingsPacket $packet) : bool{
if($packet->entityUniqueId !== $this->getId()){
return false; //TODO
@ -3188,17 +3122,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public function kick(string $reason = "", bool $isAdmin = true) : bool{
$this->server->getPluginManager()->callEvent($ev = new PlayerKickEvent($this, $reason, $this->getLeaveMessage()));
if(!$ev->isCancelled()){
$message = $reason;
if($isAdmin){
if(!$this->isBanned()){
$message = "Kicked by admin." . ($reason !== "" ? " Reason: " . $reason : "");
}else{
$message = $reason;
}
}else{
if($reason === ""){
$message = "disconnectionScreen.noReason";
}else{
$message = $reason;
}
}
$this->close($ev->getQuitMessage(), $message);
@ -3392,20 +3323,19 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->stopSleep();
if($this->joined){
if($this->spawned){
$this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message, $reason));
if($ev->getQuitMessage() != ""){
$this->server->broadcastMessage($ev->getQuitMessage());
}
try{
$this->save();
}catch(\Throwable $e){
$this->server->getLogger()->critical("Failed to save player data for " . $this->getName());
$this->server->getLogger()->logException($e);
}
$this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message, $reason));
if($ev->getQuitMessage() != ""){
$this->server->broadcastMessage($ev->getQuitMessage());
}
}
$this->joined = false;
if($this->isValid()){
foreach($this->usedChunks as $index => $d){
@ -3682,12 +3612,16 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}elseif($this->getLastDamageCause() === $source and $this->spawned){
$this->broadcastEntityEvent(EntityEventPacket::HURT_ANIMATION, null, [$this]);
if($this->isSurvival()){
$this->exhaust(0.3, PlayerExhaustEvent::CAUSE_DAMAGE);
}
$this->exhaust(0.3, PlayerExhaustEvent::CAUSE_DAMAGE);
}
}
public function getOffsetPosition(Vector3 $vector3) : Vector3{
$result = parent::getOffsetPosition($vector3);
$result->y += 0.001; //Hack for MCPE falling underground for no good reason (TODO: find out why it's doing this)
return $result;
}
public function sendPosition(Vector3 $pos, float $yaw = null, float $pitch = null, int $mode = MovePlayerPacket::MODE_NORMAL, array $targets = null){
$yaw = $yaw ?? $this->yaw;
$pitch = $pitch ?? $this->pitch;
@ -3787,7 +3721,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if($this->craftingGrid instanceof BigCraftingGrid){
$this->craftingGrid = new CraftingGrid($this);
$this->craftingType = 0;
}
}

View File

@ -131,34 +131,36 @@ namespace pocketmine {
define('pocketmine\COMPOSER_AUTOLOADER_PATH', \pocketmine\PATH . 'vendor/autoload.php');
if(is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
}else{
echo "[CRITICAL] Composer autoloader not found" . PHP_EOL;
echo "[CRITICAL] Please initialize composer dependencies before running." . PHP_EOL;
function composer_error_die($message){
echo "[CRITICAL] $message" . PHP_EOL;
echo "[CRITICAL] Please install/update Composer dependencies or use provided builds." . PHP_EOL;
exit(1);
}
if(is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
}else{
composer_error_die("Composer autoloader not found.");
}
if(!class_exists(RakLib::class)){
composer_error_die("Unable to find the RakLib library.");
}
if(version_compare(RakLib::VERSION, "0.9.0") < 0){ //TODO: remove this check (it's managed by Composer now)
composer_error_die("RakLib version 0.9.0 is required, while you have version " . RakLib::VERSION . ".");
}
if(!class_exists(\BaseClassLoader::class)){
composer_error_die("Unable to find the PocketMine-SPL library.");
}
/*
* We now use the Composer autoloader, but this autoloader is still used by RakLib and for loading plugins.
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
*/
$autoloader = new \BaseClassLoader();
$autoloader->addPath(\pocketmine\PATH . "src");
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
$autoloader->register(false);
if(!class_exists(RakLib::class)){
echo "[CRITICAL] Unable to find the RakLib library." . PHP_EOL;
echo "[CRITICAL] Please use provided builds or clone the repository recursively." . PHP_EOL;
exit(1);
}
if(version_compare(RakLib::VERSION, "0.8.2") < 0){
echo "[CRITICAL] RakLib version 0.8.2 is required, while you have version " . RakLib::VERSION . "." . PHP_EOL;
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
exit(1);
}
set_time_limit(0); //Who set it to 30 seconds?!?!
ini_set("allow_url_fopen", '1');
@ -464,8 +466,8 @@ namespace pocketmine {
if(extension_loaded("leveldb")){
$leveldb_version = phpversion("leveldb");
if(version_compare($leveldb_version, "0.2.0") < 0){
$logger->critical("php-leveldb >= 0.2.0 is required, while you have $leveldb_version");
if(version_compare($leveldb_version, "0.2.1") < 0){
$logger->critical("php-leveldb >= 0.2.1 is required, while you have $leveldb_version");
++$errors;
}
}

View File

@ -115,8 +115,8 @@ use pocketmine\utils\VersionString;
* The class that manages everything
*/
class Server{
const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin";
const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user";
public const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin";
public const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user";
/** @var Server */
private static $instance = null;
@ -1610,7 +1610,7 @@ class Server{
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.info", [
$this->getName(),
($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::WHITE,
($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::RESET,
$this->getCodename(),
$this->getApiVersion()
]));
@ -1657,12 +1657,11 @@ class Server{
LevelProviderManager::addProvider(Anvil::class);
LevelProviderManager::addProvider(McRegion::class);
LevelProviderManager::addProvider(PMAnvil::class);
LevelProviderManager::addProvider(LevelDB::class);
if(extension_loaded("leveldb")){
$this->logger->debug($this->getLanguage()->translateString("pocketmine.debug.enable"));
LevelProviderManager::addProvider(LevelDB::class);
}
Generator::addGenerator(Flat::class, "flat");
Generator::addGenerator(Normal::class, "normal");
Generator::addGenerator(Normal::class, "default");
@ -1715,8 +1714,9 @@ class Server{
$this->setDefaultLevel($this->getLevelByName($default));
}
$this->properties->save(true);
if($this->properties->hasChanged()){
$this->properties->save(true);
}
if(!($this->getDefaultLevel() instanceof Level)){
$this->getLogger()->emergency($this->getLanguage()->translateString("pocketmine.level.defaultError"));
@ -1981,7 +1981,7 @@ class Server{
}
$sender->sendMessage(new TranslationContainer(TextFormat::GOLD . "%commands.generic.notFound"));
$sender->sendMessage($this->getLanguage()->translateString(TextFormat::RED . "%commands.generic.notFound"));
return false;
}
@ -2074,8 +2074,10 @@ class Server{
$this->scheduler->mainThreadHeartbeat(PHP_INT_MAX);
}
$this->getLogger()->debug("Saving properties");
$this->properties->save();
if($this->properties->hasChanged()){
$this->getLogger()->debug("Saving properties");
$this->properties->save();
}
$this->getLogger()->debug("Closing console");
$this->console->shutdown();
@ -2357,7 +2359,7 @@ class Server{
foreach($this->players as $p){
if(!$p->loggedIn and ($tickTime - $p->creationTime) >= 10){
$p->close("", "Login timeout");
}elseif($this->alwaysTickPlayers and $p->joined){
}elseif($this->alwaysTickPlayers and $p->spawned){
$p->onUpdate($currentTick);
}
}
@ -2402,7 +2404,7 @@ class Server{
if($this->getAutoSave()){
Timings::$worldSaveTimer->startTiming();
foreach($this->players as $index => $player){
if($player->joined){
if($player->spawned){
$player->save(true);
}elseif(!$player->isConnected()){
$this->removePlayer($player);

View File

@ -33,9 +33,9 @@ use pocketmine\Player;
class Anvil extends Fallable{
const TYPE_NORMAL = 0;
const TYPE_SLIGHTLY_DAMAGED = 4;
const TYPE_VERY_DAMAGED = 8;
public const TYPE_NORMAL = 0;
public const TYPE_SLIGHTLY_DAMAGED = 4;
public const TYPE_VERY_DAMAGED = 8;
protected $id = self::ANVIL;

View File

@ -35,8 +35,8 @@ use pocketmine\tile\Tile;
use pocketmine\utils\TextFormat;
class Bed extends Transparent{
const BITFLAG_OCCUPIED = 0x04;
const BITFLAG_HEAD = 0x08;
public const BITFLAG_OCCUPIED = 0x04;
public const BITFLAG_HEAD = 0x08;
protected $id = self::BED_BLOCK;
@ -142,7 +142,7 @@ class Bed extends Transparent{
return true;
}elseif($player->distanceSquared($this) > 4 and $player->distanceSquared($other) > 4){
//MCPE doesn't have messages for bed too far away
$player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.tooFar"));
return true;
}

View File

@ -245,8 +245,8 @@ class BlockFactory{
self::registerBlock(new Coal());
self::registerBlock(new PackedIce());
self::registerBlock(new DoublePlant());
//TODO: STANDING_BANNER
//TODO: WALL_BANNER
self::registerBlock(new StandingBanner());
self::registerBlock(new WallBanner());
//TODO: DAYLIGHT_DETECTOR_INVERTED
self::registerBlock(new RedSandstone());
self::registerBlock(new RedSandstoneStairs());

View File

@ -25,255 +25,255 @@ namespace pocketmine\block;
interface BlockIds{
const AIR = 0;
const STONE = 1;
const GRASS = 2;
const DIRT = 3;
const COBBLESTONE = 4;
const PLANKS = 5, WOODEN_PLANKS = 5;
const SAPLING = 6;
const BEDROCK = 7;
const FLOWING_WATER = 8;
const STILL_WATER = 9, WATER = 9;
const FLOWING_LAVA = 10;
const LAVA = 11, STILL_LAVA = 11;
const SAND = 12;
const GRAVEL = 13;
const GOLD_ORE = 14;
const IRON_ORE = 15;
const COAL_ORE = 16;
const LOG = 17, WOOD = 17;
const LEAVES = 18;
const SPONGE = 19;
const GLASS = 20;
const LAPIS_ORE = 21;
const LAPIS_BLOCK = 22;
const DISPENSER = 23;
const SANDSTONE = 24;
const NOTEBLOCK = 25, NOTE_BLOCK = 25;
const BED_BLOCK = 26;
const GOLDEN_RAIL = 27, POWERED_RAIL = 27;
const DETECTOR_RAIL = 28;
const STICKY_PISTON = 29;
const COBWEB = 30, WEB = 30;
const TALLGRASS = 31, TALL_GRASS = 31;
const DEADBUSH = 32, DEAD_BUSH = 32;
const PISTON = 33;
const PISTONARMCOLLISION = 34, PISTON_ARM_COLLISION = 34;
const WOOL = 35;
public const AIR = 0;
public const STONE = 1;
public const GRASS = 2;
public const DIRT = 3;
public const COBBLESTONE = 4;
public const PLANKS = 5, WOODEN_PLANKS = 5;
public const SAPLING = 6;
public const BEDROCK = 7;
public const FLOWING_WATER = 8;
public const STILL_WATER = 9, WATER = 9;
public const FLOWING_LAVA = 10;
public const LAVA = 11, STILL_LAVA = 11;
public const SAND = 12;
public const GRAVEL = 13;
public const GOLD_ORE = 14;
public const IRON_ORE = 15;
public const COAL_ORE = 16;
public const LOG = 17, WOOD = 17;
public const LEAVES = 18;
public const SPONGE = 19;
public const GLASS = 20;
public const LAPIS_ORE = 21;
public const LAPIS_BLOCK = 22;
public const DISPENSER = 23;
public const SANDSTONE = 24;
public const NOTEBLOCK = 25, NOTE_BLOCK = 25;
public const BED_BLOCK = 26;
public const GOLDEN_RAIL = 27, POWERED_RAIL = 27;
public const DETECTOR_RAIL = 28;
public const STICKY_PISTON = 29;
public const COBWEB = 30, WEB = 30;
public const TALLGRASS = 31, TALL_GRASS = 31;
public const DEADBUSH = 32, DEAD_BUSH = 32;
public const PISTON = 33;
public const PISTONARMCOLLISION = 34, PISTON_ARM_COLLISION = 34;
public const WOOL = 35;
const DANDELION = 37, YELLOW_FLOWER = 37;
const POPPY = 38, RED_FLOWER = 38;
const BROWN_MUSHROOM = 39;
const RED_MUSHROOM = 40;
const GOLD_BLOCK = 41;
const IRON_BLOCK = 42;
const DOUBLE_STONE_SLAB = 43;
const STONE_SLAB = 44;
const BRICK_BLOCK = 45;
const TNT = 46;
const BOOKSHELF = 47;
const MOSSY_COBBLESTONE = 48, MOSS_STONE = 48;
const OBSIDIAN = 49;
const TORCH = 50;
const FIRE = 51;
const MOB_SPAWNER = 52, MONSTER_SPAWNER = 52;
const OAK_STAIRS = 53, WOODEN_STAIRS = 53;
const CHEST = 54;
const REDSTONE_WIRE = 55;
const DIAMOND_ORE = 56;
const DIAMOND_BLOCK = 57;
const CRAFTING_TABLE = 58, WORKBENCH = 58;
const WHEAT_BLOCK = 59;
const FARMLAND = 60;
const FURNACE = 61;
const BURNING_FURNACE = 62, LIT_FURNACE = 62;
const SIGN_POST = 63, STANDING_SIGN = 63;
const OAK_DOOR_BLOCK = 64, WOODEN_DOOR_BLOCK = 64;
const LADDER = 65;
const RAIL = 66;
const COBBLESTONE_STAIRS = 67, STONE_STAIRS = 67;
const WALL_SIGN = 68;
const LEVER = 69;
const STONE_PRESSURE_PLATE = 70;
const IRON_DOOR_BLOCK = 71;
const WOODEN_PRESSURE_PLATE = 72;
const REDSTONE_ORE = 73;
const GLOWING_REDSTONE_ORE = 74, LIT_REDSTONE_ORE = 74;
const UNLIT_REDSTONE_TORCH = 75;
const LIT_REDSTONE_TORCH = 76, REDSTONE_TORCH = 76;
const STONE_BUTTON = 77;
const SNOW_LAYER = 78;
const ICE = 79;
const SNOW = 80, SNOW_BLOCK = 80;
const CACTUS = 81;
const CLAY_BLOCK = 82;
const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
const JUKEBOX = 84;
const FENCE = 85;
const PUMPKIN = 86;
const NETHERRACK = 87;
const SOUL_SAND = 88;
const GLOWSTONE = 89;
const PORTAL = 90;
const JACK_O_LANTERN = 91, LIT_PUMPKIN = 91;
const CAKE_BLOCK = 92;
const REPEATER_BLOCK = 93, UNPOWERED_REPEATER = 93;
const POWERED_REPEATER = 94;
const INVISIBLEBEDROCK = 95, INVISIBLE_BEDROCK = 95;
const TRAPDOOR = 96, WOODEN_TRAPDOOR = 96;
const MONSTER_EGG = 97;
const STONEBRICK = 98, STONE_BRICK = 98, STONE_BRICKS = 98;
const BROWN_MUSHROOM_BLOCK = 99;
const RED_MUSHROOM_BLOCK = 100;
const IRON_BARS = 101;
const GLASS_PANE = 102;
const MELON_BLOCK = 103;
const PUMPKIN_STEM = 104;
const MELON_STEM = 105;
const VINE = 106, VINES = 106;
const FENCE_GATE = 107, OAK_FENCE_GATE = 107;
const BRICK_STAIRS = 108;
const STONE_BRICK_STAIRS = 109;
const MYCELIUM = 110;
const LILY_PAD = 111, WATERLILY = 111, WATER_LILY = 111;
const NETHER_BRICK_BLOCK = 112;
const NETHER_BRICK_FENCE = 113;
const NETHER_BRICK_STAIRS = 114;
const NETHER_WART_PLANT = 115;
const ENCHANTING_TABLE = 116, ENCHANTMENT_TABLE = 116;
const BREWING_STAND_BLOCK = 117;
const CAULDRON_BLOCK = 118;
const END_PORTAL = 119;
const END_PORTAL_FRAME = 120;
const END_STONE = 121;
const DRAGON_EGG = 122;
const REDSTONE_LAMP = 123;
const LIT_REDSTONE_LAMP = 124;
const DROPPER = 125;
const ACTIVATOR_RAIL = 126;
const COCOA = 127, COCOA_BLOCK = 127;
const SANDSTONE_STAIRS = 128;
const EMERALD_ORE = 129;
const ENDER_CHEST = 130;
const TRIPWIRE_HOOK = 131;
const TRIPWIRE = 132, TRIP_WIRE = 132;
const EMERALD_BLOCK = 133;
const SPRUCE_STAIRS = 134;
const BIRCH_STAIRS = 135;
const JUNGLE_STAIRS = 136;
const COMMAND_BLOCK = 137;
const BEACON = 138;
const COBBLESTONE_WALL = 139, STONE_WALL = 139;
const FLOWER_POT_BLOCK = 140;
const CARROTS = 141, CARROT_BLOCK = 141;
const POTATOES = 142, POTATO_BLOCK = 142;
const WOODEN_BUTTON = 143;
const MOB_HEAD_BLOCK = 144, SKULL_BLOCK = 144;
const ANVIL = 145;
const TRAPPED_CHEST = 146;
const LIGHT_WEIGHTED_PRESSURE_PLATE = 147;
const HEAVY_WEIGHTED_PRESSURE_PLATE = 148;
const COMPARATOR_BLOCK = 149, UNPOWERED_COMPARATOR = 149;
const POWERED_COMPARATOR = 150;
const DAYLIGHT_DETECTOR = 151, DAYLIGHT_SENSOR = 151;
const REDSTONE_BLOCK = 152;
const NETHER_QUARTZ_ORE = 153, QUARTZ_ORE = 153;
const HOPPER_BLOCK = 154;
const QUARTZ_BLOCK = 155;
const QUARTZ_STAIRS = 156;
const DOUBLE_WOODEN_SLAB = 157;
const WOODEN_SLAB = 158;
const STAINED_CLAY = 159, STAINED_HARDENED_CLAY = 159, TERRACOTTA = 159;
const STAINED_GLASS_PANE = 160;
const LEAVES2 = 161;
const LOG2 = 162, WOOD2 = 162;
const ACACIA_STAIRS = 163;
const DARK_OAK_STAIRS = 164;
const SLIME = 165, SLIME_BLOCK = 165;
public const DANDELION = 37, YELLOW_FLOWER = 37;
public const POPPY = 38, RED_FLOWER = 38;
public const BROWN_MUSHROOM = 39;
public const RED_MUSHROOM = 40;
public const GOLD_BLOCK = 41;
public const IRON_BLOCK = 42;
public const DOUBLE_STONE_SLAB = 43;
public const STONE_SLAB = 44;
public const BRICK_BLOCK = 45;
public const TNT = 46;
public const BOOKSHELF = 47;
public const MOSSY_COBBLESTONE = 48, MOSS_STONE = 48;
public const OBSIDIAN = 49;
public const TORCH = 50;
public const FIRE = 51;
public const MOB_SPAWNER = 52, MONSTER_SPAWNER = 52;
public const OAK_STAIRS = 53, WOODEN_STAIRS = 53;
public const CHEST = 54;
public const REDSTONE_WIRE = 55;
public const DIAMOND_ORE = 56;
public const DIAMOND_BLOCK = 57;
public const CRAFTING_TABLE = 58, WORKBENCH = 58;
public const WHEAT_BLOCK = 59;
public const FARMLAND = 60;
public const FURNACE = 61;
public const BURNING_FURNACE = 62, LIT_FURNACE = 62;
public const SIGN_POST = 63, STANDING_SIGN = 63;
public const OAK_DOOR_BLOCK = 64, WOODEN_DOOR_BLOCK = 64;
public const LADDER = 65;
public const RAIL = 66;
public const COBBLESTONE_STAIRS = 67, STONE_STAIRS = 67;
public const WALL_SIGN = 68;
public const LEVER = 69;
public const STONE_PRESSURE_PLATE = 70;
public const IRON_DOOR_BLOCK = 71;
public const WOODEN_PRESSURE_PLATE = 72;
public const REDSTONE_ORE = 73;
public const GLOWING_REDSTONE_ORE = 74, LIT_REDSTONE_ORE = 74;
public const UNLIT_REDSTONE_TORCH = 75;
public const LIT_REDSTONE_TORCH = 76, REDSTONE_TORCH = 76;
public const STONE_BUTTON = 77;
public const SNOW_LAYER = 78;
public const ICE = 79;
public const SNOW = 80, SNOW_BLOCK = 80;
public const CACTUS = 81;
public const CLAY_BLOCK = 82;
public const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
public const JUKEBOX = 84;
public const FENCE = 85;
public const PUMPKIN = 86;
public const NETHERRACK = 87;
public const SOUL_SAND = 88;
public const GLOWSTONE = 89;
public const PORTAL = 90;
public const JACK_O_LANTERN = 91, LIT_PUMPKIN = 91;
public const CAKE_BLOCK = 92;
public const REPEATER_BLOCK = 93, UNPOWERED_REPEATER = 93;
public const POWERED_REPEATER = 94;
public const INVISIBLEBEDROCK = 95, INVISIBLE_BEDROCK = 95;
public const TRAPDOOR = 96, WOODEN_TRAPDOOR = 96;
public const MONSTER_EGG = 97;
public const STONEBRICK = 98, STONE_BRICK = 98, STONE_BRICKS = 98;
public const BROWN_MUSHROOM_BLOCK = 99;
public const RED_MUSHROOM_BLOCK = 100;
public const IRON_BARS = 101;
public const GLASS_PANE = 102;
public const MELON_BLOCK = 103;
public const PUMPKIN_STEM = 104;
public const MELON_STEM = 105;
public const VINE = 106, VINES = 106;
public const FENCE_GATE = 107, OAK_FENCE_GATE = 107;
public const BRICK_STAIRS = 108;
public const STONE_BRICK_STAIRS = 109;
public const MYCELIUM = 110;
public const LILY_PAD = 111, WATERLILY = 111, WATER_LILY = 111;
public const NETHER_BRICK_BLOCK = 112;
public const NETHER_BRICK_FENCE = 113;
public const NETHER_BRICK_STAIRS = 114;
public const NETHER_WART_PLANT = 115;
public const ENCHANTING_TABLE = 116, ENCHANTMENT_TABLE = 116;
public const BREWING_STAND_BLOCK = 117;
public const CAULDRON_BLOCK = 118;
public const END_PORTAL = 119;
public const END_PORTAL_FRAME = 120;
public const END_STONE = 121;
public const DRAGON_EGG = 122;
public const REDSTONE_LAMP = 123;
public const LIT_REDSTONE_LAMP = 124;
public const DROPPER = 125;
public const ACTIVATOR_RAIL = 126;
public const COCOA = 127, COCOA_BLOCK = 127;
public const SANDSTONE_STAIRS = 128;
public const EMERALD_ORE = 129;
public const ENDER_CHEST = 130;
public const TRIPWIRE_HOOK = 131;
public const TRIPWIRE = 132, TRIP_WIRE = 132;
public const EMERALD_BLOCK = 133;
public const SPRUCE_STAIRS = 134;
public const BIRCH_STAIRS = 135;
public const JUNGLE_STAIRS = 136;
public const COMMAND_BLOCK = 137;
public const BEACON = 138;
public const COBBLESTONE_WALL = 139, STONE_WALL = 139;
public const FLOWER_POT_BLOCK = 140;
public const CARROTS = 141, CARROT_BLOCK = 141;
public const POTATOES = 142, POTATO_BLOCK = 142;
public const WOODEN_BUTTON = 143;
public const MOB_HEAD_BLOCK = 144, SKULL_BLOCK = 144;
public const ANVIL = 145;
public const TRAPPED_CHEST = 146;
public const LIGHT_WEIGHTED_PRESSURE_PLATE = 147;
public const HEAVY_WEIGHTED_PRESSURE_PLATE = 148;
public const COMPARATOR_BLOCK = 149, UNPOWERED_COMPARATOR = 149;
public const POWERED_COMPARATOR = 150;
public const DAYLIGHT_DETECTOR = 151, DAYLIGHT_SENSOR = 151;
public const REDSTONE_BLOCK = 152;
public const NETHER_QUARTZ_ORE = 153, QUARTZ_ORE = 153;
public const HOPPER_BLOCK = 154;
public const QUARTZ_BLOCK = 155;
public const QUARTZ_STAIRS = 156;
public const DOUBLE_WOODEN_SLAB = 157;
public const WOODEN_SLAB = 158;
public const STAINED_CLAY = 159, STAINED_HARDENED_CLAY = 159, TERRACOTTA = 159;
public const STAINED_GLASS_PANE = 160;
public const LEAVES2 = 161;
public const LOG2 = 162, WOOD2 = 162;
public const ACACIA_STAIRS = 163;
public const DARK_OAK_STAIRS = 164;
public const SLIME = 165, SLIME_BLOCK = 165;
const IRON_TRAPDOOR = 167;
const PRISMARINE = 168;
const SEALANTERN = 169, SEA_LANTERN = 169;
const HAY_BALE = 170, HAY_BLOCK = 170;
const CARPET = 171;
const HARDENED_CLAY = 172;
const COAL_BLOCK = 173;
const PACKED_ICE = 174;
const DOUBLE_PLANT = 175;
const STANDING_BANNER = 176;
const WALL_BANNER = 177;
const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
const RED_SANDSTONE = 179;
const RED_SANDSTONE_STAIRS = 180;
const DOUBLE_STONE_SLAB2 = 181;
const STONE_SLAB2 = 182;
const SPRUCE_FENCE_GATE = 183;
const BIRCH_FENCE_GATE = 184;
const JUNGLE_FENCE_GATE = 185;
const DARK_OAK_FENCE_GATE = 186;
const ACACIA_FENCE_GATE = 187;
const REPEATING_COMMAND_BLOCK = 188;
const CHAIN_COMMAND_BLOCK = 189;
public const IRON_TRAPDOOR = 167;
public const PRISMARINE = 168;
public const SEALANTERN = 169, SEA_LANTERN = 169;
public const HAY_BALE = 170, HAY_BLOCK = 170;
public const CARPET = 171;
public const HARDENED_CLAY = 172;
public const COAL_BLOCK = 173;
public const PACKED_ICE = 174;
public const DOUBLE_PLANT = 175;
public const STANDING_BANNER = 176;
public const WALL_BANNER = 177;
public const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
public const RED_SANDSTONE = 179;
public const RED_SANDSTONE_STAIRS = 180;
public const DOUBLE_STONE_SLAB2 = 181;
public const STONE_SLAB2 = 182;
public const SPRUCE_FENCE_GATE = 183;
public const BIRCH_FENCE_GATE = 184;
public const JUNGLE_FENCE_GATE = 185;
public const DARK_OAK_FENCE_GATE = 186;
public const ACACIA_FENCE_GATE = 187;
public const REPEATING_COMMAND_BLOCK = 188;
public const CHAIN_COMMAND_BLOCK = 189;
const SPRUCE_DOOR_BLOCK = 193;
const BIRCH_DOOR_BLOCK = 194;
const JUNGLE_DOOR_BLOCK = 195;
const ACACIA_DOOR_BLOCK = 196;
const DARK_OAK_DOOR_BLOCK = 197;
const GRASS_PATH = 198;
const FRAME_BLOCK = 199, ITEM_FRAME_BLOCK = 199;
const CHORUS_FLOWER = 200;
const PURPUR_BLOCK = 201;
public const SPRUCE_DOOR_BLOCK = 193;
public const BIRCH_DOOR_BLOCK = 194;
public const JUNGLE_DOOR_BLOCK = 195;
public const ACACIA_DOOR_BLOCK = 196;
public const DARK_OAK_DOOR_BLOCK = 197;
public const GRASS_PATH = 198;
public const FRAME_BLOCK = 199, ITEM_FRAME_BLOCK = 199;
public const CHORUS_FLOWER = 200;
public const PURPUR_BLOCK = 201;
const PURPUR_STAIRS = 203;
public const PURPUR_STAIRS = 203;
const UNDYED_SHULKER_BOX = 205;
const END_BRICKS = 206;
const FROSTED_ICE = 207;
const END_ROD = 208;
const END_GATEWAY = 209;
public const UNDYED_SHULKER_BOX = 205;
public const END_BRICKS = 206;
public const FROSTED_ICE = 207;
public const END_ROD = 208;
public const END_GATEWAY = 209;
const MAGMA = 213;
const NETHER_WART_BLOCK = 214;
const RED_NETHER_BRICK = 215;
const BONE_BLOCK = 216;
public const MAGMA = 213;
public const NETHER_WART_BLOCK = 214;
public const RED_NETHER_BRICK = 215;
public const BONE_BLOCK = 216;
const SHULKER_BOX = 218;
const PURPLE_GLAZED_TERRACOTTA = 219;
const WHITE_GLAZED_TERRACOTTA = 220;
const ORANGE_GLAZED_TERRACOTTA = 221;
const MAGENTA_GLAZED_TERRACOTTA = 222;
const LIGHT_BLUE_GLAZED_TERRACOTTA = 223;
const YELLOW_GLAZED_TERRACOTTA = 224;
const LIME_GLAZED_TERRACOTTA = 225;
const PINK_GLAZED_TERRACOTTA = 226;
const GRAY_GLAZED_TERRACOTTA = 227;
const SILVER_GLAZED_TERRACOTTA = 228;
const CYAN_GLAZED_TERRACOTTA = 229;
public const SHULKER_BOX = 218;
public const PURPLE_GLAZED_TERRACOTTA = 219;
public const WHITE_GLAZED_TERRACOTTA = 220;
public const ORANGE_GLAZED_TERRACOTTA = 221;
public const MAGENTA_GLAZED_TERRACOTTA = 222;
public const LIGHT_BLUE_GLAZED_TERRACOTTA = 223;
public const YELLOW_GLAZED_TERRACOTTA = 224;
public const LIME_GLAZED_TERRACOTTA = 225;
public const PINK_GLAZED_TERRACOTTA = 226;
public const GRAY_GLAZED_TERRACOTTA = 227;
public const SILVER_GLAZED_TERRACOTTA = 228;
public const CYAN_GLAZED_TERRACOTTA = 229;
const BLUE_GLAZED_TERRACOTTA = 231;
const BROWN_GLAZED_TERRACOTTA = 232;
const GREEN_GLAZED_TERRACOTTA = 233;
const RED_GLAZED_TERRACOTTA = 234;
const BLACK_GLAZED_TERRACOTTA = 235;
const CONCRETE = 236;
const CONCRETEPOWDER = 237, CONCRETE_POWDER = 237;
public const BLUE_GLAZED_TERRACOTTA = 231;
public const BROWN_GLAZED_TERRACOTTA = 232;
public const GREEN_GLAZED_TERRACOTTA = 233;
public const RED_GLAZED_TERRACOTTA = 234;
public const BLACK_GLAZED_TERRACOTTA = 235;
public const CONCRETE = 236;
public const CONCRETEPOWDER = 237, CONCRETE_POWDER = 237;
const CHORUS_PLANT = 240;
const STAINED_GLASS = 241;
public const CHORUS_PLANT = 240;
public const STAINED_GLASS = 241;
const PODZOL = 243;
const BEETROOT_BLOCK = 244;
const STONECUTTER = 245;
const GLOWINGOBSIDIAN = 246, GLOWING_OBSIDIAN = 246;
const NETHERREACTOR = 247, NETHER_REACTOR = 247;
const INFO_UPDATE = 248;
const INFO_UPDATE2 = 249;
const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
const OBSERVER = 251;
const STRUCTURE_BLOCK = 252;
public const PODZOL = 243;
public const BEETROOT_BLOCK = 244;
public const STONECUTTER = 245;
public const GLOWINGOBSIDIAN = 246, GLOWING_OBSIDIAN = 246;
public const NETHERREACTOR = 247, NETHER_REACTOR = 247;
public const INFO_UPDATE = 248;
public const INFO_UPDATE2 = 249;
public const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
public const OBSERVER = 251;
public const STRUCTURE_BLOCK = 252;
const RESERVED6 = 255;
public const RESERVED6 = 255;
}

View File

@ -28,8 +28,8 @@ use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
class CobblestoneWall extends Transparent{
const NONE_MOSSY_WALL = 0;
const MOSSY_WALL = 1;
public const NONE_MOSSY_WALL = 0;
public const MOSSY_WALL = 1;
protected $id = self::COBBLESTONE_WALL;

View File

@ -51,7 +51,6 @@ class CraftingTable extends Solid{
public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){
$player->setCraftingGrid(new BigCraftingGrid($player));
$player->craftingType = 1;
}
return true;

View File

@ -30,7 +30,7 @@ use pocketmine\math\Vector3;
use pocketmine\Player;
class DoublePlant extends Flowable{
const BITFLAG_TOP = 0x08;
public const BITFLAG_TOP = 0x08;
protected $id = self::DOUBLE_PLANT;

View File

@ -29,15 +29,15 @@ use pocketmine\math\Vector3;
use pocketmine\Player;
class Flower extends Flowable{
const TYPE_POPPY = 0;
const TYPE_BLUE_ORCHID = 1;
const TYPE_ALLIUM = 2;
const TYPE_AZURE_BLUET = 3;
const TYPE_RED_TULIP = 4;
const TYPE_ORANGE_TULIP = 5;
const TYPE_WHITE_TULIP = 6;
const TYPE_PINK_TULIP = 7;
const TYPE_OXEYE_DAISY = 8;
public const TYPE_POPPY = 0;
public const TYPE_BLUE_ORCHID = 1;
public const TYPE_ALLIUM = 2;
public const TYPE_AZURE_BLUET = 3;
public const TYPE_RED_TULIP = 4;
public const TYPE_ORANGE_TULIP = 5;
public const TYPE_WHITE_TULIP = 6;
public const TYPE_PINK_TULIP = 7;
public const TYPE_OXEYE_DAISY = 8;
protected $id = self::RED_FLOWER;

View File

@ -33,8 +33,8 @@ use pocketmine\tile\Tile;
class FlowerPot extends Flowable{
const STATE_EMPTY = 0;
const STATE_FULL = 1;
public const STATE_EMPTY = 0;
public const STATE_FULL = 1;
protected $id = self::FLOWER_POT_BLOCK;
protected $itemId = Item::FLOWER_POT;

View File

@ -58,17 +58,6 @@ class ItemFrame extends Flowable{
return true;
}
public function onBreak(Item $item, Player $player = null) : bool{
$tile = $this->level->getTile($this);
if($tile instanceof TileItemFrame){
//TODO: add events
if(lcg_value() <= $tile->getItemDropChance() and $tile->getItem()->getId() !== Item::AIR){
$this->level->dropItem($tile->getBlock(), $tile->getItem());
}
}
return parent::onBreak($item, $player);
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$sides = [
@ -109,4 +98,18 @@ class ItemFrame extends Flowable{
public function getVariantBitmask() : int{
return 0;
}
public function getDrops(Item $item) : array{
$drops = parent::getDrops($item);
$tile = $this->level->getTile($this);
if($tile instanceof TileItemFrame){
$tileItem = $tile->getItem();
if(lcg_value() <= $tile->getItemDropChance() and !$tileItem->isNull()){
$drops[] = $tileItem;
}
}
return $drops;
}
}

View File

@ -32,12 +32,12 @@ use pocketmine\math\Vector3;
use pocketmine\Player;
class Leaves extends Transparent{
const OAK = 0;
const SPRUCE = 1;
const BIRCH = 2;
const JUNGLE = 3;
const ACACIA = 0;
const DARK_OAK = 1;
public const OAK = 0;
public const SPRUCE = 1;
public const BIRCH = 2;
public const JUNGLE = 3;
public const ACACIA = 0;
public const DARK_OAK = 1;
protected $id = self::LEAVES;
protected $woodType = self::WOOD;

View File

@ -26,12 +26,12 @@ namespace pocketmine\block;
use pocketmine\item\Tool;
class Planks extends Solid{
const OAK = 0;
const SPRUCE = 1;
const BIRCH = 2;
const JUNGLE = 3;
const ACACIA = 4;
const DARK_OAK = 5;
public const OAK = 0;
public const SPRUCE = 1;
public const BIRCH = 2;
public const JUNGLE = 3;
public const ACACIA = 4;
public const DARK_OAK = 5;
protected $id = self::WOODEN_PLANKS;

View File

@ -28,9 +28,9 @@ use pocketmine\item\Tool;
class Prismarine extends Solid{
const NORMAL = 0;
const DARK = 1;
const BRICKS = 2;
public const NORMAL = 0;
public const DARK = 1;
public const BRICKS = 2;
protected $id = self::PRISMARINE;

View File

@ -31,9 +31,9 @@ use pocketmine\Player;
class Quartz extends Solid{
const NORMAL = 0;
const CHISELED = 1;
const PILLAR = 2;
public const NORMAL = 0;
public const CHISELED = 1;
public const PILLAR = 2;
protected $id = self::QUARTZ_BLOCK;

View File

@ -30,16 +30,16 @@ use pocketmine\Player;
class Rail extends Flowable{
const STRAIGHT_NORTH_SOUTH = 0;
const STRAIGHT_EAST_WEST = 1;
const ASCENDING_EAST = 2;
const ASCENDING_WEST = 3;
const ASCENDING_NORTH = 4;
const ASCENDING_SOUTH = 5;
const CURVE_SOUTHEAST = 6;
const CURVE_SOUTHWEST = 7;
const CURVE_NORTHWEST = 8;
const CURVE_NORTHEAST = 9;
public const STRAIGHT_NORTH_SOUTH = 0;
public const STRAIGHT_EAST_WEST = 1;
public const ASCENDING_EAST = 2;
public const ASCENDING_WEST = 3;
public const ASCENDING_NORTH = 4;
public const ASCENDING_SOUTH = 5;
public const CURVE_SOUTHEAST = 6;
public const CURVE_SOUTHWEST = 7;
public const CURVE_NORTHWEST = 8;
public const CURVE_NORTHEAST = 9;
protected $id = self::RAIL;

View File

@ -28,9 +28,9 @@ use pocketmine\item\Tool;
class Sandstone extends Solid{
const NORMAL = 0;
const CHISELED = 1;
const SMOOTH = 2;
public const NORMAL = 0;
public const CHISELED = 1;
public const SMOOTH = 2;
protected $id = self::SANDSTONE;

View File

@ -31,12 +31,12 @@ use pocketmine\Player;
use pocketmine\utils\Random;
class Sapling extends Flowable{
const OAK = 0;
const SPRUCE = 1;
const BIRCH = 2;
const JUNGLE = 3;
const ACACIA = 4;
const DARK_OAK = 5;
public const OAK = 0;
public const SPRUCE = 1;
public const BIRCH = 2;
public const JUNGLE = 3;
public const ACACIA = 4;
public const DARK_OAK = 5;
protected $id = self::SAPLING;

View File

@ -0,0 +1,109 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\ItemFactory;
use pocketmine\math\AxisAlignedBB;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\Banner as TileBanner;
use pocketmine\tile\Tile;
class StandingBanner extends Transparent{
protected $id = self::STANDING_BANNER;
protected $itemId = Item::BANNER;
public function __construct(int $meta = 0){
$this->meta = $meta;
}
public function getHardness() : float{
return 1;
}
public function isSolid() : bool{
return false;
}
public function getName() : string{
return "Standing Banner";
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return null;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
if($face !== Vector3::SIDE_DOWN){
if($face === Vector3::SIDE_UP and $player !== null){
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
$this->getLevel()->setBlock($blockReplace, $this, true);
}else{
$this->meta = $face;
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $this->meta), true);
}
Tile::createTile(Tile::BANNER, $this->getLevel(), TileBanner::createNBT($this, $face, $item, $player));
return true;
}
return false;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
}
return false;
}
public function getToolType() : int{
return Tool::TYPE_AXE;
}
public function getVariantBitmask() : int{
return 0;
}
public function getDrops(Item $item) : array{
$tile = $this->level->getTile($this);
$drop = ItemFactory::get(Item::BANNER, ($tile instanceof TileBanner ? $tile->getBaseColor() : 0));
if($tile instanceof TileBanner and ($patterns = $tile->namedtag->getListTag(TileBanner::TAG_PATTERNS)) !== null and $patterns->getCount() > 0){
$drop->setNamedTagEntry($patterns);
}
return [$drop];
}
}

View File

@ -28,13 +28,13 @@ use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
class Stone extends Solid{
const NORMAL = 0;
const GRANITE = 1;
const POLISHED_GRANITE = 2;
const DIORITE = 3;
const POLISHED_DIORITE = 4;
const ANDESITE = 5;
const POLISHED_ANDESITE = 6;
public const NORMAL = 0;
public const GRANITE = 1;
public const POLISHED_GRANITE = 2;
public const DIORITE = 3;
public const POLISHED_DIORITE = 4;
public const ANDESITE = 5;
public const POLISHED_ANDESITE = 6;
protected $id = self::STONE;

View File

@ -27,10 +27,10 @@ use pocketmine\item\Item;
use pocketmine\item\Tool;
class StoneBricks extends Solid{
const NORMAL = 0;
const MOSSY = 1;
const CRACKED = 2;
const CHISELED = 3;
public const NORMAL = 0;
public const MOSSY = 1;
public const CRACKED = 2;
public const CHISELED = 3;
protected $id = self::STONE_BRICKS;

View File

@ -27,14 +27,14 @@ use pocketmine\item\Item;
use pocketmine\item\Tool;
class StoneSlab extends Slab{
const STONE = 0;
const SANDSTONE = 1;
const WOODEN = 2;
const COBBLESTONE = 3;
const BRICK = 4;
const STONE_BRICK = 5;
const QUARTZ = 6;
const NETHER_BRICK = 7;
public const STONE = 0;
public const SANDSTONE = 1;
public const WOODEN = 2;
public const COBBLESTONE = 3;
public const BRICK = 4;
public const STONE_BRICK = 5;
public const QUARTZ = 6;
public const NETHER_BRICK = 7;
protected $id = self::STONE_SLAB;

View File

@ -24,8 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
class StoneSlab2 extends StoneSlab{
const TYPE_RED_SANDSTONE = 0;
const TYPE_PURPUR = 1;
public const TYPE_RED_SANDSTONE = 0;
public const TYPE_PURPUR = 1;
protected $id = self::STONE_SLAB2;

View File

@ -31,13 +31,13 @@ use pocketmine\math\Vector3;
use pocketmine\Player;
class Trapdoor extends Transparent{
const MASK_UPPER = 0x04;
const MASK_OPENED = 0x08;
const MASK_SIDE = 0x03;
const MASK_SIDE_SOUTH = 2;
const MASK_SIDE_NORTH = 3;
const MASK_SIDE_EAST = 0;
const MASK_SIDE_WEST = 1;
public const MASK_UPPER = 0x04;
public const MASK_OPENED = 0x08;
public const MASK_SIDE = 0x03;
public const MASK_SIDE_SOUTH = 2;
public const MASK_SIDE_NORTH = 3;
public const MASK_SIDE_EAST = 0;
public const MASK_SIDE_WEST = 1;
protected $id = self::TRAPDOOR;

View File

@ -32,10 +32,10 @@ use pocketmine\math\Vector3;
use pocketmine\Player;
class Vine extends Flowable{
const FLAG_SOUTH = 0x01;
const FLAG_WEST = 0x02;
const FLAG_NORTH = 0x04;
const FLAG_EAST = 0x08;
public const FLAG_SOUTH = 0x01;
public const FLAG_WEST = 0x02;
public const FLAG_NORTH = 0x04;
public const FLAG_EAST = 0x08;
protected $id = self::VINE;

View File

@ -0,0 +1,45 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\level\Level;
class WallBanner extends StandingBanner{
protected $id = self::WALL_BANNER;
public function getName() : string{
return "Wall Banner";
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){
$this->getLevel()->useBreakOn($this);
}
return Level::BLOCK_UPDATE_NORMAL;
}
return false;
}
}

View File

@ -30,10 +30,10 @@ use pocketmine\math\Vector3;
use pocketmine\Player;
class Wood extends Solid{
const OAK = 0;
const SPRUCE = 1;
const BIRCH = 2;
const JUNGLE = 3;
public const OAK = 0;
public const SPRUCE = 1;
public const BIRCH = 2;
public const JUNGLE = 3;
protected $id = self::WOOD;

View File

@ -26,8 +26,8 @@ namespace pocketmine\block;
class Wood2 extends Wood{
const ACACIA = 0;
const DARK_OAK = 1;
public const ACACIA = 0;
public const DARK_OAK = 1;
protected $id = self::WOOD2;

View File

@ -26,12 +26,12 @@ namespace pocketmine\block;
use pocketmine\item\Tool;
class WoodenFence extends Fence{
const FENCE_OAK = 0;
const FENCE_SPRUCE = 1;
const FENCE_BIRCH = 2;
const FENCE_JUNGLE = 3;
const FENCE_ACACIA = 4;
const FENCE_DARKOAK = 5;
public const FENCE_OAK = 0;
public const FENCE_SPRUCE = 1;
public const FENCE_BIRCH = 2;
public const FENCE_JUNGLE = 3;
public const FENCE_ACACIA = 4;
public const FENCE_DARKOAK = 5;
protected $id = self::FENCE;

View File

@ -168,7 +168,7 @@ abstract class Command{
}
if($this->permissionMessage === null){
$target->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission"));
$target->sendMessage($target->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
}elseif($this->permissionMessage !== ""){
$target->sendMessage(str_replace("<permission>", $this->getPermission(), $this->permissionMessage));
}

View File

@ -27,9 +27,9 @@ use pocketmine\Thread;
class CommandReader extends Thread{
const TYPE_READLINE = 0;
const TYPE_STREAM = 1;
const TYPE_PIPED = 2;
public const TYPE_READLINE = 0;
public const TYPE_STREAM = 1;
public const TYPE_PIPED = 2;
/** @var \Threaded */
protected $buffer;

View File

@ -79,7 +79,7 @@ class GamemodeCommand extends VanillaCommand{
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.self", [Server::getGamemodeString($gameMode)]));
}else{
$target->sendMessage(new TranslationContainer("gameMode.changed", [Server::getGamemodeString($gameMode)]));
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.other", [$target->getName(), Server::getGamemodeString($gameMode)]));
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.other", [Server::getGamemodeString($gameMode), $target->getName()]));
}
}

View File

@ -27,8 +27,8 @@ use pocketmine\command\Command;
use pocketmine\command\CommandSender;
abstract class VanillaCommand extends Command{
const MAX_COORD = 30000000;
const MIN_COORD = -30000000;
public const MAX_COORD = 30000000;
public const MIN_COORD = -30000000;
/**
* @param CommandSender $sender

View File

@ -25,18 +25,18 @@ namespace pocketmine\entity;
class Attribute{
const ABSORPTION = 0;
const SATURATION = 1;
const EXHAUSTION = 2;
const KNOCKBACK_RESISTANCE = 3;
const HEALTH = 4;
const MOVEMENT_SPEED = 5;
const FOLLOW_RANGE = 6;
const HUNGER = 7;
const FOOD = 7;
const ATTACK_DAMAGE = 8;
const EXPERIENCE_LEVEL = 9;
const EXPERIENCE = 10;
public const ABSORPTION = 0;
public const SATURATION = 1;
public const EXHAUSTION = 2;
public const KNOCKBACK_RESISTANCE = 3;
public const HEALTH = 4;
public const MOVEMENT_SPEED = 5;
public const FOLLOW_RANGE = 6;
public const HUNGER = 7;
public const FOOD = 7;
public const ATTACK_DAMAGE = 8;
public const EXPERIENCE_LEVEL = 9;
public const EXPERIENCE = 10;
private $id;
protected $minValue;

View File

@ -33,30 +33,30 @@ use pocketmine\Player;
use pocketmine\utils\Config;
class Effect{
const SPEED = 1;
const SLOWNESS = 2;
const HASTE = 3;
const FATIGUE = 4, MINING_FATIGUE = 4;
const STRENGTH = 5;
const INSTANT_HEALTH = 6, HEALING = 6;
const INSTANT_DAMAGE = 7, HARMING = 7;
const JUMP = 8;
const NAUSEA = 9, CONFUSION = 9;
const REGENERATION = 10;
const DAMAGE_RESISTANCE = 11;
const FIRE_RESISTANCE = 12;
const WATER_BREATHING = 13;
const INVISIBILITY = 14;
const BLINDNESS = 15;
const NIGHT_VISION = 16;
const HUNGER = 17;
const WEAKNESS = 18;
const POISON = 19;
const WITHER = 20;
const HEALTH_BOOST = 21;
const ABSORPTION = 22;
const SATURATION = 23;
const LEVITATION = 24; //TODO
public const SPEED = 1;
public const SLOWNESS = 2;
public const HASTE = 3;
public const FATIGUE = 4, MINING_FATIGUE = 4;
public const STRENGTH = 5;
public const INSTANT_HEALTH = 6, HEALING = 6;
public const INSTANT_DAMAGE = 7, HARMING = 7;
public const JUMP = 8;
public const NAUSEA = 9, CONFUSION = 9;
public const REGENERATION = 10;
public const DAMAGE_RESISTANCE = 11;
public const FIRE_RESISTANCE = 12;
public const WATER_BREATHING = 13;
public const INVISIBILITY = 14;
public const BLINDNESS = 15;
public const NIGHT_VISION = 16;
public const HUNGER = 17;
public const WEAKNESS = 18;
public const POISON = 19;
public const WITHER = 20;
public const HEALTH_BOOST = 21;
public const ABSORPTION = 22;
public const SATURATION = 23;
public const LEVITATION = 24; //TODO
/** @var Effect[] */
protected static $effects = [];

View File

@ -68,149 +68,149 @@ use pocketmine\Server;
abstract class Entity extends Location implements Metadatable, EntityIds{
const MOTION_THRESHOLD = 0.00001;
public const MOTION_THRESHOLD = 0.00001;
const NETWORK_ID = -1;
public const NETWORK_ID = -1;
const DATA_TYPE_BYTE = 0;
const DATA_TYPE_SHORT = 1;
const DATA_TYPE_INT = 2;
const DATA_TYPE_FLOAT = 3;
const DATA_TYPE_STRING = 4;
const DATA_TYPE_SLOT = 5;
const DATA_TYPE_POS = 6;
const DATA_TYPE_LONG = 7;
const DATA_TYPE_VECTOR3F = 8;
public const DATA_TYPE_BYTE = 0;
public const DATA_TYPE_SHORT = 1;
public const DATA_TYPE_INT = 2;
public const DATA_TYPE_FLOAT = 3;
public const DATA_TYPE_STRING = 4;
public const DATA_TYPE_SLOT = 5;
public const DATA_TYPE_POS = 6;
public const DATA_TYPE_LONG = 7;
public const DATA_TYPE_VECTOR3F = 8;
const DATA_FLAGS = 0;
const DATA_HEALTH = 1; //int (minecart/boat)
const DATA_VARIANT = 2; //int
const DATA_COLOR = 3, DATA_COLOUR = 3; //byte
const DATA_NAMETAG = 4; //string
const DATA_OWNER_EID = 5; //long
const DATA_TARGET_EID = 6; //long
const DATA_AIR = 7; //short
const DATA_POTION_COLOR = 8; //int (ARGB!)
const DATA_POTION_AMBIENT = 9; //byte
public const DATA_FLAGS = 0;
public const DATA_HEALTH = 1; //int (minecart/boat)
public const DATA_VARIANT = 2; //int
public const DATA_COLOR = 3, DATA_COLOUR = 3; //byte
public const DATA_NAMETAG = 4; //string
public const DATA_OWNER_EID = 5; //long
public const DATA_TARGET_EID = 6; //long
public const DATA_AIR = 7; //short
public const DATA_POTION_COLOR = 8; //int (ARGB!)
public const DATA_POTION_AMBIENT = 9; //byte
/* 10 (byte) */
const DATA_HURT_TIME = 11; //int (minecart/boat)
const DATA_HURT_DIRECTION = 12; //int (minecart/boat)
const DATA_PADDLE_TIME_LEFT = 13; //float
const DATA_PADDLE_TIME_RIGHT = 14; //float
const DATA_EXPERIENCE_VALUE = 15; //int (xp orb)
const DATA_MINECART_DISPLAY_BLOCK = 16; //int (id | (data << 16))
const DATA_MINECART_DISPLAY_OFFSET = 17; //int
const DATA_MINECART_HAS_DISPLAY = 18; //byte (must be 1 for minecart to show block inside)
public const DATA_HURT_TIME = 11; //int (minecart/boat)
public const DATA_HURT_DIRECTION = 12; //int (minecart/boat)
public const DATA_PADDLE_TIME_LEFT = 13; //float
public const DATA_PADDLE_TIME_RIGHT = 14; //float
public const DATA_EXPERIENCE_VALUE = 15; //int (xp orb)
public const DATA_MINECART_DISPLAY_BLOCK = 16; //int (id | (data << 16))
public const DATA_MINECART_DISPLAY_OFFSET = 17; //int
public const DATA_MINECART_HAS_DISPLAY = 18; //byte (must be 1 for minecart to show block inside)
//TODO: add more properties
const DATA_ENDERMAN_HELD_ITEM_ID = 23; //short
const DATA_ENDERMAN_HELD_ITEM_DAMAGE = 24; //short
const DATA_ENTITY_AGE = 25; //short
public const DATA_ENDERMAN_HELD_ITEM_ID = 23; //short
public const DATA_ENDERMAN_HELD_ITEM_DAMAGE = 24; //short
public const DATA_ENTITY_AGE = 25; //short
/* 27 (byte) player-specific flags
* 28 (int) player "index"?
* 29 (block coords) bed position */
const DATA_FIREBALL_POWER_X = 30; //float
const DATA_FIREBALL_POWER_Y = 31;
const DATA_FIREBALL_POWER_Z = 32;
public const DATA_FIREBALL_POWER_X = 30; //float
public const DATA_FIREBALL_POWER_Y = 31;
public const DATA_FIREBALL_POWER_Z = 32;
/* 33 (unknown)
* 34 (float) fishing bobber
* 35 (float) fishing bobber
* 36 (float) fishing bobber */
const DATA_POTION_AUX_VALUE = 37; //short
const DATA_LEAD_HOLDER_EID = 38; //long
const DATA_SCALE = 39; //float
const DATA_INTERACTIVE_TAG = 40; //string (button text)
const DATA_NPC_SKIN_ID = 41; //string
const DATA_URL_TAG = 42; //string
const DATA_MAX_AIR = 43; //short
const DATA_MARK_VARIANT = 44; //int
public const DATA_POTION_AUX_VALUE = 37; //short
public const DATA_LEAD_HOLDER_EID = 38; //long
public const DATA_SCALE = 39; //float
public const DATA_INTERACTIVE_TAG = 40; //string (button text)
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
/* 45 (byte) container stuff
* 46 (int) container stuff
* 47 (int) container stuff */
const DATA_BLOCK_TARGET = 48; //block coords (ender crystal)
const DATA_WITHER_INVULNERABLE_TICKS = 49; //int
const DATA_WITHER_TARGET_1 = 50; //long
const DATA_WITHER_TARGET_2 = 51; //long
const DATA_WITHER_TARGET_3 = 52; //long
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) */
const DATA_BOUNDING_BOX_WIDTH = 54; //float
const DATA_BOUNDING_BOX_HEIGHT = 55; //float
const DATA_FUSE_LENGTH = 56; //int
const DATA_RIDER_SEAT_POSITION = 57; //vector3f
const DATA_RIDER_ROTATION_LOCKED = 58; //byte
const DATA_RIDER_MAX_ROTATION = 59; //float
const DATA_RIDER_MIN_ROTATION = 60; //float
const DATA_AREA_EFFECT_CLOUD_RADIUS = 61; //float
const DATA_AREA_EFFECT_CLOUD_WAITING = 62; //int
const DATA_AREA_EFFECT_CLOUD_PARTICLE_ID = 63; //int
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 */
const DATA_SHULKER_ATTACH_FACE = 65; //byte
public const DATA_SHULKER_ATTACH_FACE = 65; //byte
/* 66 (short) shulker-related */
const DATA_SHULKER_ATTACH_POS = 67; //block coords
const DATA_TRADING_PLAYER_EID = 68; //long
public const DATA_SHULKER_ATTACH_POS = 67; //block coords
public const DATA_TRADING_PLAYER_EID = 68; //long
/* 70 (byte) command-block */
const DATA_COMMAND_BLOCK_COMMAND = 71; //string
const DATA_COMMAND_BLOCK_LAST_OUTPUT = 72; //string
const DATA_COMMAND_BLOCK_TRACK_OUTPUT = 73; //byte
const DATA_CONTROLLING_RIDER_SEAT_NUMBER = 74; //byte
const DATA_STRENGTH = 75; //int
const DATA_MAX_STRENGTH = 76; //int
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)
* 78 (int) */
const DATA_FLAG_ONFIRE = 0;
const DATA_FLAG_SNEAKING = 1;
const DATA_FLAG_RIDING = 2;
const DATA_FLAG_SPRINTING = 3;
const DATA_FLAG_ACTION = 4;
const DATA_FLAG_INVISIBLE = 5;
const DATA_FLAG_TEMPTED = 6;
const DATA_FLAG_INLOVE = 7;
const DATA_FLAG_SADDLED = 8;
const DATA_FLAG_POWERED = 9;
const DATA_FLAG_IGNITED = 10;
const DATA_FLAG_BABY = 11;
const DATA_FLAG_CONVERTING = 12;
const DATA_FLAG_CRITICAL = 13;
const DATA_FLAG_CAN_SHOW_NAMETAG = 14;
const DATA_FLAG_ALWAYS_SHOW_NAMETAG = 15;
const DATA_FLAG_IMMOBILE = 16, DATA_FLAG_NO_AI = 16;
const DATA_FLAG_SILENT = 17;
const DATA_FLAG_WALLCLIMBING = 18;
const DATA_FLAG_CAN_CLIMB = 19;
const DATA_FLAG_SWIMMER = 20;
const DATA_FLAG_CAN_FLY = 21;
const DATA_FLAG_RESTING = 22;
const DATA_FLAG_SITTING = 23;
const DATA_FLAG_ANGRY = 24;
const DATA_FLAG_INTERESTED = 25;
const DATA_FLAG_CHARGED = 26;
const DATA_FLAG_TAMED = 27;
const DATA_FLAG_LEASHED = 28;
const DATA_FLAG_SHEARED = 29;
const DATA_FLAG_GLIDING = 30;
const DATA_FLAG_ELDER = 31;
const DATA_FLAG_MOVING = 32;
const DATA_FLAG_BREATHING = 33;
const DATA_FLAG_CHESTED = 34;
const DATA_FLAG_STACKABLE = 35;
const DATA_FLAG_SHOWBASE = 36;
const DATA_FLAG_REARING = 37;
const DATA_FLAG_VIBRATING = 38;
const DATA_FLAG_IDLING = 39;
const DATA_FLAG_EVOKER_SPELL = 40;
const DATA_FLAG_CHARGE_ATTACK = 41;
const DATA_FLAG_WASD_CONTROLLED = 42;
const DATA_FLAG_CAN_POWER_JUMP = 43;
const DATA_FLAG_LINGER = 44;
const DATA_FLAG_HAS_COLLISION = 45;
const DATA_FLAG_AFFECTED_BY_GRAVITY = 46;
const DATA_FLAG_FIRE_IMMUNE = 47;
const DATA_FLAG_DANCING = 48;
public const DATA_FLAG_ONFIRE = 0;
public const DATA_FLAG_SNEAKING = 1;
public const DATA_FLAG_RIDING = 2;
public const DATA_FLAG_SPRINTING = 3;
public const DATA_FLAG_ACTION = 4;
public const DATA_FLAG_INVISIBLE = 5;
public const DATA_FLAG_TEMPTED = 6;
public const DATA_FLAG_INLOVE = 7;
public const DATA_FLAG_SADDLED = 8;
public const DATA_FLAG_POWERED = 9;
public const DATA_FLAG_IGNITED = 10;
public const DATA_FLAG_BABY = 11;
public const DATA_FLAG_CONVERTING = 12;
public const DATA_FLAG_CRITICAL = 13;
public const DATA_FLAG_CAN_SHOW_NAMETAG = 14;
public const DATA_FLAG_ALWAYS_SHOW_NAMETAG = 15;
public const DATA_FLAG_IMMOBILE = 16, DATA_FLAG_NO_AI = 16;
public const DATA_FLAG_SILENT = 17;
public const DATA_FLAG_WALLCLIMBING = 18;
public const DATA_FLAG_CAN_CLIMB = 19;
public const DATA_FLAG_SWIMMER = 20;
public const DATA_FLAG_CAN_FLY = 21;
public const DATA_FLAG_RESTING = 22;
public const DATA_FLAG_SITTING = 23;
public const DATA_FLAG_ANGRY = 24;
public const DATA_FLAG_INTERESTED = 25;
public const DATA_FLAG_CHARGED = 26;
public const DATA_FLAG_TAMED = 27;
public const DATA_FLAG_LEASHED = 28;
public const DATA_FLAG_SHEARED = 29;
public const DATA_FLAG_GLIDING = 30;
public const DATA_FLAG_ELDER = 31;
public const DATA_FLAG_MOVING = 32;
public const DATA_FLAG_BREATHING = 33;
public const DATA_FLAG_CHESTED = 34;
public const DATA_FLAG_STACKABLE = 35;
public const DATA_FLAG_SHOWBASE = 36;
public const DATA_FLAG_REARING = 37;
public const DATA_FLAG_VIBRATING = 38;
public const DATA_FLAG_IDLING = 39;
public const DATA_FLAG_EVOKER_SPELL = 40;
public const DATA_FLAG_CHARGE_ATTACK = 41;
public const DATA_FLAG_WASD_CONTROLLED = 42;
public const DATA_FLAG_CAN_POWER_JUMP = 43;
public const DATA_FLAG_LINGER = 44;
public const DATA_FLAG_HAS_COLLISION = 45;
public const DATA_FLAG_AFFECTED_BY_GRAVITY = 46;
public const DATA_FLAG_FIRE_IMMUNE = 47;
public const DATA_FLAG_DANCING = 48;
public static $entityCount = 1;
/** @var Entity[] */
@ -496,15 +496,16 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->id = Entity::$entityCount++;
$this->namedtag = $nbt;
$this->chunk = $level->getChunk($this->namedtag["Pos"][0] >> 4, $this->namedtag["Pos"][2] >> 4, true);
/** @var float[] $pos */
$pos = $this->namedtag->getListTag("Pos")->getAllValues();
$this->chunk = $level->getChunk(((int) $pos[0]) >> 4, ((int) $pos[2]) >> 4, true);
assert($this->chunk !== null);
$this->setLevel($level);
$this->server = $level->getServer();
$this->boundingBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0);
/** @var float[] $pos */
$pos = $this->namedtag->getListTag("Pos")->getAllValues();
/** @var float[] $rotation */
$rotation = $this->namedtag->getListTag("Rotation")->getAllValues();
@ -667,7 +668,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
* Sets whether the entity is able to climb climbable blocks.
* @param bool $value
*/
public function setCanClimb(bool $value){
public function setCanClimb(bool $value = true){
$this->setGenericFlag(self::DATA_FLAG_CAN_CLIMB, $value);
}
@ -1385,7 +1386,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
public function onCollideWithPlayer(Human $entityPlayer){
public function onCollideWithPlayer(Player $player){
}
@ -1454,15 +1455,15 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
return true;
}
Timings::$entityMoveTimer->startTiming();
$movX = $dx;
$movY = $dy;
$movZ = $dz;
if($this->keepMovement){
$this->boundingBox->offset($dx, $dy, $dz);
$this->setPosition($this->temporalVector->setComponents(($this->boundingBox->minX + $this->boundingBox->maxX) / 2, $this->boundingBox->minY, ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2));
$this->onGround = $this->isPlayer ? true : false;
return true;
}else{
Timings::$entityMoveTimer->startTiming();
$this->ySize *= 0.4;
/*
@ -1477,10 +1478,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
*/
$movX = $dx;
$movY = $dy;
$movZ = $dz;
$axisalignedbb = clone $this->boundingBox;
/*$sneakFlag = $this->onGround and $this instanceof Player;
@ -1574,37 +1571,35 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}else{
$this->ySize += 0.5; //FIXME: this should be the height of the block it walked up, not fixed 0.5
}
}
$this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2;
$this->y = $this->boundingBox->minY - $this->ySize;
$this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2;
$this->checkChunks();
$this->checkBlockCollision();
$this->checkGroundState($movX, $movY, $movZ, $dx, $dy, $dz);
$this->updateFallState($dy, $this->onGround);
if($movX != $dx){
$this->motionX = 0;
}
if($movY != $dy){
$this->motionY = 0;
}
if($movZ != $dz){
$this->motionZ = 0;
}
//TODO: vehicle collision events (first we need to spawn them!)
Timings::$entityMoveTimer->stopTiming();
return true;
}
$this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2;
$this->y = $this->boundingBox->minY - $this->ySize;
$this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2;
$this->checkChunks();
$this->checkBlockCollision();
$this->checkGroundState($movX, $movY, $movZ, $dx, $dy, $dz);
$this->updateFallState($dy, $this->onGround);
if($movX != $dx){
$this->motionX = 0;
}
if($movY != $dy){
$this->motionY = 0;
}
if($movZ != $dz){
$this->motionZ = 0;
}
//TODO: vehicle collision events (first we need to spawn them!)
Timings::$entityMoveTimer->stopTiming();
return true;
}
protected function checkGroundState(float $movX, float $movY, float $movZ, float $dx, float $dy, float $dz){

View File

@ -25,95 +25,95 @@ namespace pocketmine\entity;
interface EntityIds{
const CHICKEN = 10;
const COW = 11;
const PIG = 12;
const SHEEP = 13;
const WOLF = 14;
const VILLAGER = 15;
const MOOSHROOM = 16;
const SQUID = 17;
const RABBIT = 18;
const BAT = 19;
const IRON_GOLEM = 20;
const SNOW_GOLEM = 21;
const OCELOT = 22;
const HORSE = 23;
const DONKEY = 24;
const MULE = 25;
const SKELETON_HORSE = 26;
const ZOMBIE_HORSE = 27;
const POLAR_BEAR = 28;
const LLAMA = 29;
const PARROT = 30;
public const CHICKEN = 10;
public const COW = 11;
public const PIG = 12;
public const SHEEP = 13;
public const WOLF = 14;
public const VILLAGER = 15;
public const MOOSHROOM = 16;
public const SQUID = 17;
public const RABBIT = 18;
public const BAT = 19;
public const IRON_GOLEM = 20;
public const SNOW_GOLEM = 21;
public const OCELOT = 22;
public const HORSE = 23;
public const DONKEY = 24;
public const MULE = 25;
public const SKELETON_HORSE = 26;
public const ZOMBIE_HORSE = 27;
public const POLAR_BEAR = 28;
public const LLAMA = 29;
public const PARROT = 30;
const ZOMBIE = 32;
const CREEPER = 33;
const SKELETON = 34;
const SPIDER = 35;
const ZOMBIE_PIGMAN = 36;
const SLIME = 37;
const ENDERMAN = 38;
const SILVERFISH = 39;
const CAVE_SPIDER = 40;
const GHAST = 41;
const MAGMA_CUBE = 42;
const BLAZE = 43;
const ZOMBIE_VILLAGER = 44;
const WITCH = 45;
const STRAY = 46;
const HUSK = 47;
const WITHER_SKELETON = 48;
const GUARDIAN = 49;
const ELDER_GUARDIAN = 50;
const NPC = 51;
const WITHER = 52;
const ENDER_DRAGON = 53;
const SHULKER = 54;
const ENDERMITE = 55;
const LEARN_TO_CODE_MASCOT = 56;
const VINDICATOR = 57;
public const ZOMBIE = 32;
public const CREEPER = 33;
public const SKELETON = 34;
public const SPIDER = 35;
public const ZOMBIE_PIGMAN = 36;
public const SLIME = 37;
public const ENDERMAN = 38;
public const SILVERFISH = 39;
public const CAVE_SPIDER = 40;
public const GHAST = 41;
public const MAGMA_CUBE = 42;
public const BLAZE = 43;
public const ZOMBIE_VILLAGER = 44;
public const WITCH = 45;
public const STRAY = 46;
public const HUSK = 47;
public const WITHER_SKELETON = 48;
public const GUARDIAN = 49;
public const ELDER_GUARDIAN = 50;
public const NPC = 51;
public const WITHER = 52;
public const ENDER_DRAGON = 53;
public const SHULKER = 54;
public const ENDERMITE = 55;
public const LEARN_TO_CODE_MASCOT = 56;
public const VINDICATOR = 57;
const ARMOR_STAND = 61;
const TRIPOD_CAMERA = 62;
const PLAYER = 63;
const ITEM = 64;
const TNT = 65;
const FALLING_BLOCK = 66;
const MOVING_BLOCK = 67;
const XP_BOTTLE = 68;
const XP_ORB = 69;
const EYE_OF_ENDER_SIGNAL = 70;
const ENDER_CRYSTAL = 71;
const FIREWORKS_ROCKET = 72;
public const ARMOR_STAND = 61;
public const TRIPOD_CAMERA = 62;
public const PLAYER = 63;
public const ITEM = 64;
public const TNT = 65;
public const FALLING_BLOCK = 66;
public const MOVING_BLOCK = 67;
public const XP_BOTTLE = 68;
public const XP_ORB = 69;
public const EYE_OF_ENDER_SIGNAL = 70;
public const ENDER_CRYSTAL = 71;
public const FIREWORKS_ROCKET = 72;
const SHULKER_BULLET = 76;
const FISHING_HOOK = 77;
const CHALKBOARD = 78;
const DRAGON_FIREBALL = 79;
const ARROW = 80;
const SNOWBALL = 81;
const EGG = 82;
const PAINTING = 83;
const MINECART = 84;
const LARGE_FIREBALL = 85;
const SPLASH_POTION = 86;
const ENDER_PEARL = 87;
const LEASH_KNOT = 88;
const WITHER_SKULL = 89;
const BOAT = 90;
const WITHER_SKULL_DANGEROUS = 91;
const LIGHTNING_BOLT = 93;
const SMALL_FIREBALL = 94;
const AREA_EFFECT_CLOUD = 95;
const HOPPER_MINECART = 96;
const TNT_MINECART = 97;
const CHEST_MINECART = 98;
public const SHULKER_BULLET = 76;
public const FISHING_HOOK = 77;
public const CHALKBOARD = 78;
public const DRAGON_FIREBALL = 79;
public const ARROW = 80;
public const SNOWBALL = 81;
public const EGG = 82;
public const PAINTING = 83;
public const MINECART = 84;
public const LARGE_FIREBALL = 85;
public const SPLASH_POTION = 86;
public const ENDER_PEARL = 87;
public const LEASH_KNOT = 88;
public const WITHER_SKULL = 89;
public const BOAT = 90;
public const WITHER_SKULL_DANGEROUS = 91;
public const LIGHTNING_BOLT = 93;
public const SMALL_FIREBALL = 94;
public const AREA_EFFECT_CLOUD = 95;
public const HOPPER_MINECART = 96;
public const TNT_MINECART = 97;
public const CHEST_MINECART = 98;
const COMMAND_BLOCK_MINECART = 100;
const LINGERING_POTION = 101;
const LLAMA_SPIT = 102;
const EVOCATION_FANG = 103;
const EVOCATION_ILLAGER = 104;
const VEX = 105;
public const COMMAND_BLOCK_MINECART = 100;
public const LINGERING_POTION = 101;
public const LLAMA_SPIT = 102;
public const EVOCATION_FANG = 103;
public const EVOCATION_ILLAGER = 104;
public const VEX = 105;
}

View File

@ -34,7 +34,7 @@ use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\IntTag;
class FallingSand extends Entity{
const NETWORK_ID = self::FALLING_BLOCK;
public const NETWORK_ID = self::FALLING_BLOCK;
public $width = 0.98;
public $height = 0.98;

View File

@ -44,12 +44,12 @@ use pocketmine\utils\UUID;
class Human extends Creature implements ProjectileSource, InventoryHolder{
const DATA_PLAYER_FLAG_SLEEP = 1;
const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK
public const DATA_PLAYER_FLAG_SLEEP = 1;
public const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK
const DATA_PLAYER_FLAGS = 27;
public const DATA_PLAYER_FLAGS = 27;
const DATA_PLAYER_BED_POSITION = 29;
public const DATA_PLAYER_BED_POSITION = 29;
/** @var PlayerInventory */
protected $inventory;
@ -73,8 +73,11 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
protected $baseOffset = 1.62;
public function __construct(Level $level, CompoundTag $nbt){
if($this->skin === null and (!isset($nbt->Skin) or !isset($nbt->Skin->Data) or !Player::isValidSkin($nbt->Skin->Data->getValue()))){
throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
if($this->skin === null){
$skinTag = $nbt->getCompoundTag("Skin");
if($skinTag === null or !self::isValidSkin($skinTag->getString("Data", "", true))){
throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
}
}
parent::__construct($level, $nbt);

View File

@ -26,12 +26,14 @@ namespace pocketmine\entity;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent;
use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\item\Item as ItemItem;
use pocketmine\network\mcpe\protocol\AddItemEntityPacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\Player;
class Item extends Entity{
const NETWORK_ID = self::ITEM;
public const NETWORK_ID = self::ITEM;
/** @var string */
protected $owner = "";
@ -55,7 +57,7 @@ class Item extends Entity{
parent::initEntity();
$this->setMaxHealth(5);
$this->setHealth((int) $this->namedtag["Health"]);
$this->setHealth($this->namedtag->getShort("Health", (int) $this->getHealth()));
$this->age = $this->namedtag->getShort("Age", $this->age);
$this->pickupDelay = $this->namedtag->getShort("PickupDelay", $this->pickupDelay);
$this->owner = $this->namedtag->getString("Owner", $this->owner);
@ -202,4 +204,39 @@ class Item extends Entity{
$player->dataPacket($pk);
}
public function onCollideWithPlayer(Player $player){
if($this->getPickupDelay() > 0){
return;
}
$item = $this->getItem();
$playerInventory = $player->getInventory();
if(!($item instanceof ItemItem) or ($player->isSurvival() and !$playerInventory->canAddItem($item))){
return;
}
$this->server->getPluginManager()->callEvent($ev = new InventoryPickupItemEvent($playerInventory, $this));
if($ev->isCancelled()){
return;
}
switch($item->getId()){
case ItemItem::WOOD:
$player->awardAchievement("mineWood");
break;
case ItemItem::DIAMOND:
$player->awardAchievement("diamond");
break;
}
$pk = new TakeItemEntityPacket();
$pk->eid = $player->getId();
$pk->target = $this->getId();
$this->server->broadcastPacket($this->getViewers(), $pk);
$playerInventory->addItem(clone $item);
$this->flagForDespawn();
}
}

View File

@ -68,7 +68,7 @@ abstract class Living extends Entity implements Damageable{
$health = $this->getMaxHealth();
if($this->namedtag->hasTag("HealF", FloatTag::class)){
$health = new FloatTag("Health", (float) $this->namedtag["HealF"]);
$health = new FloatTag("Health", $this->namedtag->getFloat("HealF"));
$this->namedtag->removeTag("HealF");
}elseif($this->namedtag->hasTag("Health")){
$healthTag = $this->namedtag->getTag("Health");
@ -550,7 +550,7 @@ abstract class Living extends Entity implements Damageable{
* @param int $ticks
*/
public function setMaxAirSupplyTicks(int $ticks){
$this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, $ticks);
$this->setDataProperty(self::DATA_MAX_AIR, self::DATA_TYPE_SHORT, $ticks);
}
/**

View File

@ -30,7 +30,7 @@ use pocketmine\nbt\tag\ShortTag;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
class PrimedTNT extends Entity implements Explosive{
const NETWORK_ID = self::TNT;
public const NETWORK_ID = self::TNT;
public $width = 0.98;
public $height = 0.98;

View File

@ -31,7 +31,7 @@ use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\EntityEventPacket;
class Squid extends WaterAnimal{
const NETWORK_ID = self::SQUID;
public const NETWORK_ID = self::SQUID;
public $width = 0.95;
public $height = 0.95;

View File

@ -24,13 +24,13 @@ declare(strict_types=1);
namespace pocketmine\entity;
class Villager extends Creature implements NPC, Ageable{
const PROFESSION_FARMER = 0;
const PROFESSION_LIBRARIAN = 1;
const PROFESSION_PRIEST = 2;
const PROFESSION_BLACKSMITH = 3;
const PROFESSION_BUTCHER = 4;
public const PROFESSION_FARMER = 0;
public const PROFESSION_LIBRARIAN = 1;
public const PROFESSION_PRIEST = 2;
public const PROFESSION_BLACKSMITH = 3;
public const PROFESSION_BUTCHER = 4;
const NETWORK_ID = self::VILLAGER;
public const NETWORK_ID = self::VILLAGER;
public $width = 0.6;
public $height = 1.8;

View File

@ -29,7 +29,7 @@ use pocketmine\item\ItemFactory;
use pocketmine\Player;
class Zombie extends Monster{
const NETWORK_ID = self::ZOMBIE;
public const NETWORK_ID = self::ZOMBIE;
public $width = 0.6;
public $height = 1.8;

View File

@ -24,11 +24,16 @@ declare(strict_types=1);
namespace pocketmine\entity\projectile;
use pocketmine\entity\Entity;
use pocketmine\event\inventory\InventoryPickupArrowEvent;
use pocketmine\item\ItemFactory;
use pocketmine\item\Item as ItemItem;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\Player;
class Arrow extends Projectile{
const NETWORK_ID = self::ARROW;
public const NETWORK_ID = self::ARROW;
public $width = 0.25;
public $height = 0.25;
@ -78,4 +83,30 @@ class Arrow extends Projectile{
return $hasUpdate;
}
public function onCollideWithPlayer(Player $player){
if(!$this->hadCollision){
return;
}
$item = ItemFactory::get(ItemItem::ARROW, 0, 1);
$playerInventory = $player->getInventory();
if($player->isSurvival() and !$playerInventory->canAddItem($item)){
return;
}
$this->server->getPluginManager()->callEvent($ev = new InventoryPickupArrowEvent($playerInventory, $this));
if($ev->isCancelled()){
return;
}
$pk = new TakeItemEntityPacket();
$pk->eid = $player->getId();
$pk->target = $this->getId();
$this->server->broadcastPacket($this->getViewers(), $pk);
$playerInventory->addItem(clone $item);
$this->flagForDespawn();
}
}

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\entity\projectile;
class Egg extends Throwable{
const NETWORK_ID = self::EGG;
public const NETWORK_ID = self::EGG;
//TODO: spawn chickens on collision
}

View File

@ -37,7 +37,7 @@ use pocketmine\nbt\tag\CompoundTag;
abstract class Projectile extends Entity{
const DATA_SHOOTER_ID = 17;
public const DATA_SHOOTER_ID = 17;
protected $damage = 0;

View File

@ -24,6 +24,6 @@ declare(strict_types=1);
namespace pocketmine\entity\projectile;
class Snowball extends Throwable{
const NETWORK_ID = self::SNOWBALL;
public const NETWORK_ID = self::SNOWBALL;
}

View File

@ -37,29 +37,29 @@ abstract class EventPriority{
* Event call is of very low importance and should be ran first, to allow
* other plugins to further customise the outcome
*/
const LOWEST = 5;
public const LOWEST = 5;
/**
* Event call is of low importance
*/
const LOW = 4;
public const LOW = 4;
/**
* Event call is neither important or unimportant, and may be ran normally
*/
const NORMAL = 3;
public const NORMAL = 3;
/**
* Event call is of high importance
*/
const HIGH = 2;
public const HIGH = 2;
/**
* Event call is critical and must have the final say in what happens
* to the event
*/
const HIGHEST = 1;
public const HIGHEST = 1;
/**
* Event is listened to purely for monitoring the outcome of an event.
*
* No modifications to the event should be made under this priority
*/
const MONITOR = 0;
public const MONITOR = 0;
}

View File

@ -32,29 +32,29 @@ use pocketmine\event\Cancellable;
class EntityDamageEvent extends EntityEvent implements Cancellable{
public static $handlerList = null;
const MODIFIER_BASE = 0;
const MODIFIER_ARMOR = 1;
const MODIFIER_STRENGTH = 2;
const MODIFIER_WEAKNESS = 3;
const MODIFIER_RESISTANCE = 4;
const MODIFIER_ABSORPTION = 5;
public const MODIFIER_BASE = 0;
public const MODIFIER_ARMOR = 1;
public const MODIFIER_STRENGTH = 2;
public const MODIFIER_WEAKNESS = 3;
public const MODIFIER_RESISTANCE = 4;
public const MODIFIER_ABSORPTION = 5;
const CAUSE_CONTACT = 0;
const CAUSE_ENTITY_ATTACK = 1;
const CAUSE_PROJECTILE = 2;
const CAUSE_SUFFOCATION = 3;
const CAUSE_FALL = 4;
const CAUSE_FIRE = 5;
const CAUSE_FIRE_TICK = 6;
const CAUSE_LAVA = 7;
const CAUSE_DROWNING = 8;
const CAUSE_BLOCK_EXPLOSION = 9;
const CAUSE_ENTITY_EXPLOSION = 10;
const CAUSE_VOID = 11;
const CAUSE_SUICIDE = 12;
const CAUSE_MAGIC = 13;
const CAUSE_CUSTOM = 14;
const CAUSE_STARVATION = 15;
public const CAUSE_CONTACT = 0;
public const CAUSE_ENTITY_ATTACK = 1;
public const CAUSE_PROJECTILE = 2;
public const CAUSE_SUFFOCATION = 3;
public const CAUSE_FALL = 4;
public const CAUSE_FIRE = 5;
public const CAUSE_FIRE_TICK = 6;
public const CAUSE_LAVA = 7;
public const CAUSE_DROWNING = 8;
public const CAUSE_BLOCK_EXPLOSION = 9;
public const CAUSE_ENTITY_EXPLOSION = 10;
public const CAUSE_VOID = 11;
public const CAUSE_SUICIDE = 12;
public const CAUSE_MAGIC = 13;
public const CAUSE_CUSTOM = 14;
public const CAUSE_STARVATION = 15;
/** @var int */
private $cause;

View File

@ -29,11 +29,11 @@ use pocketmine\event\Cancellable;
class EntityRegainHealthEvent extends EntityEvent implements Cancellable{
public static $handlerList = null;
const CAUSE_REGEN = 0;
const CAUSE_EATING = 1;
const CAUSE_MAGIC = 2;
const CAUSE_CUSTOM = 3;
const CAUSE_SATURATION = 4;
public const CAUSE_REGEN = 0;
public const CAUSE_EATING = 1;
public const CAUSE_MAGIC = 2;
public const CAUSE_CUSTOM = 3;
public const CAUSE_SATURATION = 4;
/** @var float */
private $amount;

View File

@ -36,7 +36,7 @@ class PlayerAnimationEvent extends PlayerEvent implements Cancellable{
* @deprecated This is dependent on the protocol and should not be here.
* Use the constants in {@link pocketmine\network\mcpe\protocol\AnimatePacket} instead.
*/
const ARM_SWING = 1;
public const ARM_SWING = 1;
/** @var int */
private $animationType;

View File

@ -30,11 +30,11 @@ use pocketmine\Player;
class PlayerEditBookEvent extends PlayerEvent implements Cancellable{
public static $handlerList = null;
const ACTION_REPLACE_PAGE = 0;
const ACTION_ADD_PAGE = 1;
const ACTION_DELETE_PAGE = 2;
const ACTION_SWAP_PAGES = 3;
const ACTION_SIGN_BOOK = 4;
public const ACTION_REPLACE_PAGE = 0;
public const ACTION_ADD_PAGE = 1;
public const ACTION_DELETE_PAGE = 2;
public const ACTION_SWAP_PAGES = 3;
public const ACTION_SIGN_BOOK = 4;
/** @var WritableBook */
private $oldBook;

View File

@ -30,17 +30,17 @@ use pocketmine\event\entity\EntityEvent;
class PlayerExhaustEvent extends EntityEvent implements Cancellable{
public static $handlerList = null;
const CAUSE_ATTACK = 1;
const CAUSE_DAMAGE = 2;
const CAUSE_MINING = 3;
const CAUSE_HEALTH_REGEN = 4;
const CAUSE_POTION = 5;
const CAUSE_WALKING = 6;
const CAUSE_SPRINTING = 7;
const CAUSE_SWIMMING = 8;
const CAUSE_JUMPING = 9;
const CAUSE_SPRINT_JUMPING = 10;
const CAUSE_CUSTOM = 11;
public const CAUSE_ATTACK = 1;
public const CAUSE_DAMAGE = 2;
public const CAUSE_MINING = 3;
public const CAUSE_HEALTH_REGEN = 4;
public const CAUSE_POTION = 5;
public const CAUSE_WALKING = 6;
public const CAUSE_SPRINTING = 7;
public const CAUSE_SWIMMING = 8;
public const CAUSE_JUMPING = 9;
public const CAUSE_SPRINT_JUMPING = 10;
public const CAUSE_CUSTOM = 11;
/** @var float */
private $amount;

View File

@ -37,11 +37,11 @@ use pocketmine\Player;
class PlayerInteractEvent extends PlayerEvent implements Cancellable{
public static $handlerList = null;
const LEFT_CLICK_BLOCK = 0;
const RIGHT_CLICK_BLOCK = 1;
const LEFT_CLICK_AIR = 2;
const RIGHT_CLICK_AIR = 3;
const PHYSICAL = 4;
public const LEFT_CLICK_BLOCK = 0;
public const RIGHT_CLICK_BLOCK = 1;
public const LEFT_CLICK_AIR = 2;
public const RIGHT_CLICK_AIR = 3;
public const PHYSICAL = 4;
/** @var Block */
protected $blockTouched;

View File

@ -31,7 +31,7 @@ use pocketmine\utils\Binary;
class QueryRegenerateEvent extends ServerEvent{
public static $handlerList = null;
const GAME_ID = "MINECRAFTPE";
public const GAME_ID = "MINECRAFTPE";
/** @var int */
private $timeout;

View File

@ -30,7 +30,7 @@ use pocketmine\item\Item;
use pocketmine\Player;
interface Inventory{
const MAX_STACK = 64;
public const MAX_STACK = 64;
/**
* @return int

View File

@ -26,14 +26,14 @@ namespace pocketmine\inventory;
use pocketmine\utils\UUID;
class MultiRecipe{
const TYPE_REPAIR_ITEM = "00000000-0000-0000-0000-000000000001";
const TYPE_MAP_EXTENDING = "D392B075-4BA1-40AE-8789-AF868D56F6CE";
const TYPE_MAP_CLONING = "85939755-BA10-4D9D-A4CC-EFB7A8E943C4";
const TYPE_MAP_UPGRADING = "AECD2294-4B94-434B-8667-4499BB2C9327";
const TYPE_BOOK_CLONING = "D1CA6B84-338E-4F2F-9C6B-76CC8B4BD98D";
const TYPE_BANNER_DUPLICATE = "B5C5D105-75A2-4076-AF2B-923EA2BF4BF0";
const TYPE_BANNER_ADD_PATTERN = "D81AAEAF-E172-4440-9225-868DF030D27B";
const TYPE_FIREWORKS = "00000000-0000-0000-0000-000000000002";
public const TYPE_REPAIR_ITEM = "00000000-0000-0000-0000-000000000001";
public const TYPE_MAP_EXTENDING = "D392B075-4BA1-40AE-8789-AF868D56F6CE";
public const TYPE_MAP_CLONING = "85939755-BA10-4D9D-A4CC-EFB7A8E943C4";
public const TYPE_MAP_UPGRADING = "AECD2294-4B94-434B-8667-4499BB2C9327";
public const TYPE_BOOK_CLONING = "D1CA6B84-338E-4F2F-9C6B-76CC8B4BD98D";
public const TYPE_BANNER_DUPLICATE = "B5C5D105-75A2-4076-AF2B-923EA2BF4BF0";
public const TYPE_BANNER_ADD_PATTERN = "D81AAEAF-E172-4440-9225-868DF030D27B";
public const TYPE_FIREWORKS = "00000000-0000-0000-0000-000000000002";
private $uuid;

View File

@ -31,11 +31,11 @@ class CreativeInventoryAction extends InventoryAction{
/**
* Player put an item into the creative window to destroy it.
*/
const TYPE_DELETE_ITEM = 0;
public const TYPE_DELETE_ITEM = 0;
/**
* Player took an item from the creative window.
*/
const TYPE_CREATE_ITEM = 1;
public const TYPE_CREATE_ITEM = 1;
protected $actionType;

View File

@ -24,9 +24,35 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\nbt\tag\IntTag;
use pocketmine\utils\Binary;
use pocketmine\utils\Color;
abstract class Armor extends Item{
public const TAG_CUSTOM_COLOR = "customColor"; //TAG_Int
public function getMaxStackSize() : int{
return 1;
}
/**
* Returns the dyed colour of this armour piece. This generally only applies to leather armour.
* @return Color|null
*/
public function getCustomColor() : ?Color{
if($this->getNamedTag()->hasTag(self::TAG_CUSTOM_COLOR, IntTag::class)){
return Color::fromARGB(Binary::unsignInt($this->getNamedTag()->getInt(self::TAG_CUSTOM_COLOR)));
}
return null;
}
/**
* Sets the dyed colour of this armour piece. This generally only applies to leather armour.
* @param Color $color
*/
public function setCustomColor(Color $color) : void{
$this->setNamedTagEntry(new IntTag(self::TAG_CUSTOM_COLOR, Binary::signInt($color->toARGB())));
}
}

View File

@ -0,0 +1,251 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\tile\Banner as TileBanner;
class Banner extends Item{
public const TAG_BASE = TileBanner::TAG_BASE;
public const TAG_PATTERNS = TileBanner::TAG_PATTERNS;
public const TAG_PATTERN_COLOR = TileBanner::TAG_PATTERN_COLOR;
public const TAG_PATTERN_NAME = TileBanner::TAG_PATTERN_NAME;
public function __construct(int $meta = 0){
$this->block = BlockFactory::get(Block::STANDING_BANNER);
parent::__construct(self::BANNER, $meta, "Banner");
}
public function getMaxStackSize() : int{
return 16;
}
/**
* Returns the color of the banner base.
*
* @return int
*/
public function getBaseColor() : int{
return $this->getNamedTag()->getInt(self::TAG_BASE, 0);
}
/**
* Sets the color of the banner base.
* Banner items have to be resent to see the changes in the inventory.
*
* @param int $color
*/
public function setBaseColor(int $color) : void{
$namedTag = $this->getNamedTag();
$namedTag->setInt(self::TAG_BASE, $color & 0x0f);
$this->setNamedTag($namedTag);
}
/**
* Applies a new pattern on the banner with the given color.
* Banner items have to be resent to see the changes in the inventory.
*
* @param string $pattern
* @param int $color
*
* @return int ID of pattern.
*/
public function addPattern(string $pattern, int $color) : int{
$patternId = 0;
if($this->getPatternCount() !== 0){
$patternId = max($this->getPatternIds()) + 1;
}
$patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS);
assert($patternsTag !== null);
$patternsTag[$patternId] = new CompoundTag("", [
new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f),
new StringTag(self::TAG_PATTERN_NAME, $pattern)
]);
$this->setNamedTagEntry($patternsTag);
return $patternId;
}
/**
* Returns whether a pattern with the given ID exists on the banner or not.
*
* @param int $patternId
*
* @return bool
*/
public function patternExists(int $patternId) : bool{
$this->correctNBT();
return isset($this->getNamedTag()->getListTag(self::TAG_PATTERNS)[$patternId]);
}
/**
* Returns the data of a pattern with the given ID.
*
* @param int $patternId
*
* @return array
*/
public function getPatternData(int $patternId) : array{
if(!$this->patternExists($patternId)){
return [];
}
$patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS);
assert($patternsTag !== null);
$pattern = $patternsTag[$patternId];
assert($pattern instanceof CompoundTag);
return [
self::TAG_PATTERN_COLOR => $pattern->getInt(self::TAG_PATTERN_COLOR),
self::TAG_PATTERN_NAME => $pattern->getString(self::TAG_PATTERN_NAME)
];
}
/**
* Changes the pattern of a previously existing pattern.
* Banner items have to be resent to see the changes in the inventory.
*
* @param int $patternId
* @param string $pattern
* @param int $color
*
* @return bool indicating success.
*/
public function changePattern(int $patternId, string $pattern, int $color) : bool{
if(!$this->patternExists($patternId)){
return false;
}
$patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS);
assert($patternsTag !== null);
$patternsTag[$patternId] = new CompoundTag("", [
new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f),
new StringTag(self::TAG_PATTERN_NAME, $pattern)
]);
$this->setNamedTagEntry($patternsTag);
return true;
}
/**
* Deletes a pattern from the banner with the given ID.
* Banner items have to be resent to see the changes in the inventory.
*
* @param int $patternId
*
* @return bool indicating whether the pattern existed or not.
*/
public function deletePattern(int $patternId) : bool{
if(!$this->patternExists($patternId)){
return false;
}
$patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS);
if($patternsTag instanceof ListTag){
unset($patternsTag[$patternId]);
$this->setNamedTagEntry($patternsTag);
}
return true;
}
/**
* Deletes the top most pattern of the banner.
* Banner items have to be resent to see the changes in the inventory.
*
* @return bool indicating whether the banner was empty or not.
*/
public function deleteTopPattern() : bool{
$keys = $this->getPatternIds();
if(empty($keys)){
return false;
}
return $this->deletePattern(max($keys));
}
/**
* Deletes the bottom pattern of the banner.
* Banner items have to be resent to see the changes in the inventory.
*
* @return bool indicating whether the banner was empty or not.
*/
public function deleteBottomPattern() : bool{
$keys = $this->getPatternIds();
if(empty($keys)){
return false;
}
return $this->deletePattern(min($keys));
}
/**
* Returns an array containing all pattern IDs
*
* @return array
*/
public function getPatternIds() : array{
$this->correctNBT();
$keys = array_keys((array) ($this->getNamedTag()->getListTag(self::TAG_PATTERNS) ?? []));
return array_filter($keys, function($key){
return is_numeric($key);
}, ARRAY_FILTER_USE_KEY);
}
/**
* Returns the total count of patterns on this banner.
*
* @return int
*/
public function getPatternCount() : int{
return count($this->getPatternIds());
}
public function correctNBT() : void{
$tag = $this->getNamedTag();
if(!$tag->hasTag(self::TAG_BASE, IntTag::class)){
$tag->setInt(self::TAG_BASE, 0);
}
if(!$tag->hasTag(self::TAG_PATTERNS, ListTag::class)){
$tag->setTag(new ListTag(self::TAG_PATTERNS));
}
$this->setNamedTag($tag);
}
public function getFuelTime() : int{
return 300;
}
}

View File

@ -32,8 +32,7 @@ abstract class Durable extends Item{
* @return bool
*/
public function isUnbreakable() : bool{
$tag = $this->getNamedTagEntry("Unbreakable");
return $tag !== null and $tag->getValue() !== 0;
return $this->getNamedTag()->getByte("Unbreakable", 0) !== 0;
}
/**

View File

@ -26,10 +26,10 @@ namespace pocketmine\item;
use pocketmine\entity\Effect;
class Fish extends Food{
const FISH_FISH = 0;
const FISH_SALMON = 1;
const FISH_CLOWNFISH = 2;
const FISH_PUFFERFISH = 3;
public const FISH_FISH = 0;
public const FISH_SALMON = 1;
public const FISH_CLOWNFISH = 2;
public const FISH_PUFFERFISH = 3;
public function __construct(int $meta = 0){
$name = "Raw Fish";

View File

@ -45,12 +45,12 @@ use pocketmine\utils\Binary;
use pocketmine\utils\Config;
class Item implements ItemIds, \JsonSerializable{
const TAG_ENCH = "ench";
const TAG_DISPLAY = "display";
const TAG_BLOCK_ENTITY_TAG = "BlockEntityTag";
public const TAG_ENCH = "ench";
public const TAG_DISPLAY = "display";
public const TAG_BLOCK_ENTITY_TAG = "BlockEntityTag";
const TAG_DISPLAY_NAME = "Name";
const TAG_DISPLAY_LORE = "Lore";
public const TAG_DISPLAY_NAME = "Name";
public const TAG_DISPLAY_LORE = "Lore";
/** @var NBT */
@ -369,7 +369,7 @@ class Item implements ItemIds, \JsonSerializable{
/** @var CompoundTag $entry */
foreach($ench as $k => $entry){
if($entry->getShort("id") === $enchantment->getId()){
$ench->{$k} = new CompoundTag("", [
$ench[$k] = new CompoundTag("", [
new ShortTag("id", $enchantment->getId()),
new ShortTag("lvl", $enchantment->getLevel())
]);
@ -380,7 +380,7 @@ class Item implements ItemIds, \JsonSerializable{
}
if(!$found){
$ench->{count($ench)} = new CompoundTag("", [
$ench[count($ench)] = new CompoundTag("", [
new ShortTag("id", $enchantment->getId()),
new ShortTag("lvl", $enchantment->getLevel())
]);
@ -512,18 +512,18 @@ class Item implements ItemIds, \JsonSerializable{
* @return NamedTag|null
*/
public function getNamedTagEntry(string $name) : ?NamedTag{
return $this->getNamedTag()->{$name} ?? null;
return $this->getNamedTag()->getTag($name);
}
public function setNamedTagEntry(NamedTag $new) : void{
$tag = $this->getNamedTag();
$tag->{$new->getName()} = $new;
$tag->setTag($new);
$this->setNamedTag($tag);
}
public function removeNamedTagEntry(string $name) : void{
$tag = $this->getNamedTag();
unset($tag->{$name});
$tag->removeTag($name);
$this->setNamedTag($tag);
}

View File

@ -225,7 +225,7 @@ class ItemFactory{
//TODO: COMMAND_BLOCK_MINECART
//TODO: ELYTRA
self::registerItem(new Item(Item::SHULKER_SHELL, 0, "Shulker Shell"));
//TODO: BANNER
self::registerItem(new Banner());
//TODO: TOTEM

View File

@ -27,219 +27,219 @@ use pocketmine\block\BlockIds;
interface ItemIds extends BlockIds{
const IRON_SHOVEL = 256;
const IRON_PICKAXE = 257;
const IRON_AXE = 258;
const FLINT_AND_STEEL = 259, FLINT_STEEL = 259;
const APPLE = 260;
const BOW = 261;
const ARROW = 262;
const COAL = 263;
const DIAMOND = 264;
const IRON_INGOT = 265;
const GOLD_INGOT = 266;
const IRON_SWORD = 267;
const WOODEN_SWORD = 268;
const WOODEN_SHOVEL = 269;
const WOODEN_PICKAXE = 270;
const WOODEN_AXE = 271;
const STONE_SWORD = 272;
const STONE_SHOVEL = 273;
const STONE_PICKAXE = 274;
const STONE_AXE = 275;
const DIAMOND_SWORD = 276;
const DIAMOND_SHOVEL = 277;
const DIAMOND_PICKAXE = 278;
const DIAMOND_AXE = 279;
const STICK = 280;
const BOWL = 281;
const MUSHROOM_STEW = 282;
const GOLDEN_SWORD = 283, GOLD_SWORD = 283;
const GOLDEN_SHOVEL = 284, GOLD_SHOVEL = 284;
const GOLDEN_PICKAXE = 285, GOLD_PICKAXE = 285;
const GOLDEN_AXE = 286, GOLD_AXE = 286;
const STRING = 287;
const FEATHER = 288;
const GUNPOWDER = 289;
const WOODEN_HOE = 290;
const STONE_HOE = 291;
const IRON_HOE = 292;
const DIAMOND_HOE = 293;
const GOLDEN_HOE = 294, GOLD_HOE = 294;
const SEEDS = 295, WHEAT_SEEDS = 295;
const WHEAT = 296;
const BREAD = 297;
const LEATHER_CAP = 298, LEATHER_HELMET = 298;
const LEATHER_CHESTPLATE = 299, LEATHER_TUNIC = 299;
const LEATHER_LEGGINGS = 300, LEATHER_PANTS = 300;
const LEATHER_BOOTS = 301;
const CHAINMAIL_HELMET = 302, CHAIN_HELMET = 302;
const CHAINMAIL_CHESTPLATE = 303, CHAIN_CHESTPLATE = 303;
const CHAINMAIL_LEGGINGS = 304, CHAIN_LEGGINGS = 304;
const CHAINMAIL_BOOTS = 305, CHAIN_BOOTS = 305;
const IRON_HELMET = 306;
const IRON_CHESTPLATE = 307;
const IRON_LEGGINGS = 308;
const IRON_BOOTS = 309;
const DIAMOND_HELMET = 310;
const DIAMOND_CHESTPLATE = 311;
const DIAMOND_LEGGINGS = 312;
const DIAMOND_BOOTS = 313;
const GOLDEN_HELMET = 314, GOLD_HELMET = 314;
const GOLDEN_CHESTPLATE = 315, GOLD_CHESTPLATE = 315;
const GOLDEN_LEGGINGS = 316, GOLD_LEGGINGS = 316;
const GOLDEN_BOOTS = 317, GOLD_BOOTS = 317;
const FLINT = 318;
const PORKCHOP = 319, RAW_PORKCHOP = 319;
const COOKED_PORKCHOP = 320;
const PAINTING = 321;
const GOLDEN_APPLE = 322;
const SIGN = 323;
const OAK_DOOR = 324, WOODEN_DOOR = 324;
const BUCKET = 325;
public const IRON_SHOVEL = 256;
public const IRON_PICKAXE = 257;
public const IRON_AXE = 258;
public const FLINT_AND_STEEL = 259, FLINT_STEEL = 259;
public const APPLE = 260;
public const BOW = 261;
public const ARROW = 262;
public const COAL = 263;
public const DIAMOND = 264;
public const IRON_INGOT = 265;
public const GOLD_INGOT = 266;
public const IRON_SWORD = 267;
public const WOODEN_SWORD = 268;
public const WOODEN_SHOVEL = 269;
public const WOODEN_PICKAXE = 270;
public const WOODEN_AXE = 271;
public const STONE_SWORD = 272;
public const STONE_SHOVEL = 273;
public const STONE_PICKAXE = 274;
public const STONE_AXE = 275;
public const DIAMOND_SWORD = 276;
public const DIAMOND_SHOVEL = 277;
public const DIAMOND_PICKAXE = 278;
public const DIAMOND_AXE = 279;
public const STICK = 280;
public const BOWL = 281;
public const MUSHROOM_STEW = 282;
public const GOLDEN_SWORD = 283, GOLD_SWORD = 283;
public const GOLDEN_SHOVEL = 284, GOLD_SHOVEL = 284;
public const GOLDEN_PICKAXE = 285, GOLD_PICKAXE = 285;
public const GOLDEN_AXE = 286, GOLD_AXE = 286;
public const STRING = 287;
public const FEATHER = 288;
public const GUNPOWDER = 289;
public const WOODEN_HOE = 290;
public const STONE_HOE = 291;
public const IRON_HOE = 292;
public const DIAMOND_HOE = 293;
public const GOLDEN_HOE = 294, GOLD_HOE = 294;
public const SEEDS = 295, WHEAT_SEEDS = 295;
public const WHEAT = 296;
public const BREAD = 297;
public const LEATHER_CAP = 298, LEATHER_HELMET = 298;
public const LEATHER_CHESTPLATE = 299, LEATHER_TUNIC = 299;
public const LEATHER_LEGGINGS = 300, LEATHER_PANTS = 300;
public const LEATHER_BOOTS = 301;
public const CHAINMAIL_HELMET = 302, CHAIN_HELMET = 302;
public const CHAINMAIL_CHESTPLATE = 303, CHAIN_CHESTPLATE = 303;
public const CHAINMAIL_LEGGINGS = 304, CHAIN_LEGGINGS = 304;
public const CHAINMAIL_BOOTS = 305, CHAIN_BOOTS = 305;
public const IRON_HELMET = 306;
public const IRON_CHESTPLATE = 307;
public const IRON_LEGGINGS = 308;
public const IRON_BOOTS = 309;
public const DIAMOND_HELMET = 310;
public const DIAMOND_CHESTPLATE = 311;
public const DIAMOND_LEGGINGS = 312;
public const DIAMOND_BOOTS = 313;
public const GOLDEN_HELMET = 314, GOLD_HELMET = 314;
public const GOLDEN_CHESTPLATE = 315, GOLD_CHESTPLATE = 315;
public const GOLDEN_LEGGINGS = 316, GOLD_LEGGINGS = 316;
public const GOLDEN_BOOTS = 317, GOLD_BOOTS = 317;
public const FLINT = 318;
public const PORKCHOP = 319, RAW_PORKCHOP = 319;
public const COOKED_PORKCHOP = 320;
public const PAINTING = 321;
public const GOLDEN_APPLE = 322;
public const SIGN = 323;
public const OAK_DOOR = 324, WOODEN_DOOR = 324;
public const BUCKET = 325;
const MINECART = 328;
const SADDLE = 329;
const IRON_DOOR = 330;
const REDSTONE = 331, REDSTONE_DUST = 331;
const SNOWBALL = 332;
const BOAT = 333;
const LEATHER = 334;
public const MINECART = 328;
public const SADDLE = 329;
public const IRON_DOOR = 330;
public const REDSTONE = 331, REDSTONE_DUST = 331;
public const SNOWBALL = 332;
public const BOAT = 333;
public const LEATHER = 334;
const BRICK = 336;
const CLAY = 337, CLAY_BALL = 337;
const REEDS = 338, SUGARCANE = 338;
const PAPER = 339;
const BOOK = 340;
const SLIMEBALL = 341, SLIME_BALL = 341;
const CHEST_MINECART = 342, MINECART_WITH_CHEST = 342;
public const BRICK = 336;
public const CLAY = 337, CLAY_BALL = 337;
public const REEDS = 338, SUGARCANE = 338;
public const PAPER = 339;
public const BOOK = 340;
public const SLIMEBALL = 341, SLIME_BALL = 341;
public const CHEST_MINECART = 342, MINECART_WITH_CHEST = 342;
const EGG = 344;
const COMPASS = 345;
const FISHING_ROD = 346;
const CLOCK = 347;
const GLOWSTONE_DUST = 348;
const FISH = 349, RAW_FISH = 349;
const COOKED_FISH = 350;
const DYE = 351;
const BONE = 352;
const SUGAR = 353;
const CAKE = 354;
const BED = 355;
const REPEATER = 356;
const COOKIE = 357;
const FILLED_MAP = 358;
const SHEARS = 359;
const MELON = 360, MELON_SLICE = 360;
const PUMPKIN_SEEDS = 361;
const MELON_SEEDS = 362;
const BEEF = 363, RAW_BEEF = 363;
const COOKED_BEEF = 364, STEAK = 364;
const CHICKEN = 365, RAW_CHICKEN = 365;
const COOKED_CHICKEN = 366;
const ROTTEN_FLESH = 367;
const ENDER_PEARL = 368;
const BLAZE_ROD = 369;
const GHAST_TEAR = 370;
const GOLDEN_NUGGET = 371, GOLD_NUGGET = 371;
const NETHER_WART = 372;
const POTION = 373;
const GLASS_BOTTLE = 374;
const SPIDER_EYE = 375;
const FERMENTED_SPIDER_EYE = 376;
const BLAZE_POWDER = 377;
const MAGMA_CREAM = 378;
const BREWING_STAND = 379;
const CAULDRON = 380;
const ENDER_EYE = 381;
const GLISTERING_MELON = 382, SPECKLED_MELON = 382;
const SPAWN_EGG = 383;
const BOTTLE_O_ENCHANTING = 384, EXPERIENCE_BOTTLE = 384;
const FIREBALL = 385, FIRE_CHARGE = 385;
const WRITABLE_BOOK = 386;
const WRITTEN_BOOK = 387;
const EMERALD = 388;
const FRAME = 389, ITEM_FRAME = 389;
const FLOWER_POT = 390;
const CARROT = 391;
const POTATO = 392;
const BAKED_POTATO = 393;
const POISONOUS_POTATO = 394;
const EMPTYMAP = 395, EMPTY_MAP = 395, MAP = 395;
const GOLDEN_CARROT = 396;
const MOB_HEAD = 397, SKULL = 397;
const CARROTONASTICK = 398, CARROT_ON_A_STICK = 398;
const NETHERSTAR = 399, NETHER_STAR = 399;
const PUMPKIN_PIE = 400;
const FIREWORKS = 401;
const FIREWORKSCHARGE = 402, FIREWORKS_CHARGE = 402;
const ENCHANTED_BOOK = 403;
const COMPARATOR = 404;
const NETHERBRICK = 405, NETHER_BRICK = 405;
const NETHER_QUARTZ = 406, QUARTZ = 406;
const MINECART_WITH_TNT = 407, TNT_MINECART = 407;
const HOPPER_MINECART = 408, MINECART_WITH_HOPPER = 408;
const PRISMARINE_SHARD = 409;
const HOPPER = 410;
const RABBIT = 411, RAW_RABBIT = 411;
const COOKED_RABBIT = 412;
const RABBIT_STEW = 413;
const RABBIT_FOOT = 414;
const RABBIT_HIDE = 415;
const HORSEARMORLEATHER = 416, HORSE_ARMOR_LEATHER = 416, LEATHER_HORSE_ARMOR = 416;
const HORSEARMORIRON = 417, HORSE_ARMOR_IRON = 417, IRON_HORSE_ARMOR = 417;
const GOLD_HORSE_ARMOR = 418, HORSEARMORGOLD = 418, HORSE_ARMOR_GOLD = 418;
const DIAMOND_HORSE_ARMOR = 419, HORSEARMORDIAMOND = 419, HORSE_ARMOR_DIAMOND = 419;
const LEAD = 420;
const NAMETAG = 421, NAME_TAG = 421;
const PRISMARINE_CRYSTALS = 422;
const MUTTONRAW = 423, MUTTON_RAW = 423, RAW_MUTTON = 423;
const COOKED_MUTTON = 424, MUTTONCOOKED = 424, MUTTON_COOKED = 424;
const ARMOR_STAND = 425;
const END_CRYSTAL = 426;
const SPRUCE_DOOR = 427;
const BIRCH_DOOR = 428;
const JUNGLE_DOOR = 429;
const ACACIA_DOOR = 430;
const DARK_OAK_DOOR = 431;
const CHORUS_FRUIT = 432;
const CHORUS_FRUIT_POPPED = 433;
public const EGG = 344;
public const COMPASS = 345;
public const FISHING_ROD = 346;
public const CLOCK = 347;
public const GLOWSTONE_DUST = 348;
public const FISH = 349, RAW_FISH = 349;
public const COOKED_FISH = 350;
public const DYE = 351;
public const BONE = 352;
public const SUGAR = 353;
public const CAKE = 354;
public const BED = 355;
public const REPEATER = 356;
public const COOKIE = 357;
public const FILLED_MAP = 358;
public const SHEARS = 359;
public const MELON = 360, MELON_SLICE = 360;
public const PUMPKIN_SEEDS = 361;
public const MELON_SEEDS = 362;
public const BEEF = 363, RAW_BEEF = 363;
public const COOKED_BEEF = 364, STEAK = 364;
public const CHICKEN = 365, RAW_CHICKEN = 365;
public const COOKED_CHICKEN = 366;
public const ROTTEN_FLESH = 367;
public const ENDER_PEARL = 368;
public const BLAZE_ROD = 369;
public const GHAST_TEAR = 370;
public const GOLDEN_NUGGET = 371, GOLD_NUGGET = 371;
public const NETHER_WART = 372;
public const POTION = 373;
public const GLASS_BOTTLE = 374;
public const SPIDER_EYE = 375;
public const FERMENTED_SPIDER_EYE = 376;
public const BLAZE_POWDER = 377;
public const MAGMA_CREAM = 378;
public const BREWING_STAND = 379;
public const CAULDRON = 380;
public const ENDER_EYE = 381;
public const GLISTERING_MELON = 382, SPECKLED_MELON = 382;
public const SPAWN_EGG = 383;
public const BOTTLE_O_ENCHANTING = 384, EXPERIENCE_BOTTLE = 384;
public const FIREBALL = 385, FIRE_CHARGE = 385;
public const WRITABLE_BOOK = 386;
public const WRITTEN_BOOK = 387;
public const EMERALD = 388;
public const FRAME = 389, ITEM_FRAME = 389;
public const FLOWER_POT = 390;
public const CARROT = 391;
public const POTATO = 392;
public const BAKED_POTATO = 393;
public const POISONOUS_POTATO = 394;
public const EMPTYMAP = 395, EMPTY_MAP = 395, MAP = 395;
public const GOLDEN_CARROT = 396;
public const MOB_HEAD = 397, SKULL = 397;
public const CARROTONASTICK = 398, CARROT_ON_A_STICK = 398;
public const NETHERSTAR = 399, NETHER_STAR = 399;
public const PUMPKIN_PIE = 400;
public const FIREWORKS = 401;
public const FIREWORKSCHARGE = 402, FIREWORKS_CHARGE = 402;
public const ENCHANTED_BOOK = 403;
public const COMPARATOR = 404;
public const NETHERBRICK = 405, NETHER_BRICK = 405;
public const NETHER_QUARTZ = 406, QUARTZ = 406;
public const MINECART_WITH_TNT = 407, TNT_MINECART = 407;
public const HOPPER_MINECART = 408, MINECART_WITH_HOPPER = 408;
public const PRISMARINE_SHARD = 409;
public const HOPPER = 410;
public const RABBIT = 411, RAW_RABBIT = 411;
public const COOKED_RABBIT = 412;
public const RABBIT_STEW = 413;
public const RABBIT_FOOT = 414;
public const RABBIT_HIDE = 415;
public const HORSEARMORLEATHER = 416, HORSE_ARMOR_LEATHER = 416, LEATHER_HORSE_ARMOR = 416;
public const HORSEARMORIRON = 417, HORSE_ARMOR_IRON = 417, IRON_HORSE_ARMOR = 417;
public const GOLD_HORSE_ARMOR = 418, HORSEARMORGOLD = 418, HORSE_ARMOR_GOLD = 418;
public const DIAMOND_HORSE_ARMOR = 419, HORSEARMORDIAMOND = 419, HORSE_ARMOR_DIAMOND = 419;
public const LEAD = 420;
public const NAMETAG = 421, NAME_TAG = 421;
public const PRISMARINE_CRYSTALS = 422;
public const MUTTONRAW = 423, MUTTON_RAW = 423, RAW_MUTTON = 423;
public const COOKED_MUTTON = 424, MUTTONCOOKED = 424, MUTTON_COOKED = 424;
public const ARMOR_STAND = 425;
public const END_CRYSTAL = 426;
public const SPRUCE_DOOR = 427;
public const BIRCH_DOOR = 428;
public const JUNGLE_DOOR = 429;
public const ACACIA_DOOR = 430;
public const DARK_OAK_DOOR = 431;
public const CHORUS_FRUIT = 432;
public const CHORUS_FRUIT_POPPED = 433;
const DRAGON_BREATH = 437;
const SPLASH_POTION = 438;
public const DRAGON_BREATH = 437;
public const SPLASH_POTION = 438;
const LINGERING_POTION = 441;
public const LINGERING_POTION = 441;
const COMMAND_BLOCK_MINECART = 443, MINECART_WITH_COMMAND_BLOCK = 443;
const ELYTRA = 444;
const SHULKER_SHELL = 445;
const BANNER = 446;
public const COMMAND_BLOCK_MINECART = 443, MINECART_WITH_COMMAND_BLOCK = 443;
public const ELYTRA = 444;
public const SHULKER_SHELL = 445;
public const BANNER = 446;
const TOTEM = 450;
public const TOTEM = 450;
const IRON_NUGGET = 452;
public const IRON_NUGGET = 452;
const BEETROOT = 457;
const BEETROOT_SEEDS = 458;
const BEETROOT_SOUP = 459;
const RAW_SALMON = 460, SALMON = 460;
const CLOWNFISH = 461;
const PUFFERFISH = 462;
const COOKED_SALMON = 463;
public const BEETROOT = 457;
public const BEETROOT_SEEDS = 458;
public const BEETROOT_SOUP = 459;
public const RAW_SALMON = 460, SALMON = 460;
public const CLOWNFISH = 461;
public const PUFFERFISH = 462;
public const COOKED_SALMON = 463;
const APPLEENCHANTED = 466, APPLE_ENCHANTED = 466, ENCHANTED_GOLDEN_APPLE = 466;
public const APPLEENCHANTED = 466, APPLE_ENCHANTED = 466, ENCHANTED_GOLDEN_APPLE = 466;
const RECORD_13 = 500;
const RECORD_CAT = 501;
const RECORD_BLOCKS = 502;
const RECORD_CHIRP = 503;
const RECORD_FAR = 504;
const RECORD_MALL = 505;
const RECORD_MELLOHI = 506;
const RECORD_STAL = 507;
const RECORD_STRAD = 508;
const RECORD_WARD = 509;
const RECORD_11 = 510;
const RECORD_WAIT = 511;
public const RECORD_13 = 500;
public const RECORD_CAT = 501;
public const RECORD_BLOCKS = 502;
public const RECORD_CHIRP = 503;
public const RECORD_FAR = 504;
public const RECORD_MALL = 505;
public const RECORD_MELLOHI = 506;
public const RECORD_STAL = 507;
public const RECORD_STRAD = 508;
public const RECORD_WARD = 509;
public const RECORD_11 = 510;
public const RECORD_WAIT = 511;
}

View File

@ -27,18 +27,18 @@ use pocketmine\block\Block;
use pocketmine\entity\Entity;
abstract class Tool extends Durable{
const TIER_WOODEN = 1;
const TIER_GOLD = 2;
const TIER_STONE = 3;
const TIER_IRON = 4;
const TIER_DIAMOND = 5;
public const TIER_WOODEN = 1;
public const TIER_GOLD = 2;
public const TIER_STONE = 3;
public const TIER_IRON = 4;
public const TIER_DIAMOND = 5;
const TYPE_NONE = 0;
const TYPE_SWORD = 1;
const TYPE_SHOVEL = 2;
const TYPE_PICKAXE = 3;
const TYPE_AXE = 4;
const TYPE_SHEARS = 5;
public const TYPE_NONE = 0;
public const TYPE_SWORD = 1;
public const TYPE_SHOVEL = 2;
public const TYPE_PICKAXE = 3;
public const TYPE_AXE = 4;
public const TYPE_SHEARS = 5;
public function getMaxStackSize() : int{
return 1;

View File

@ -30,7 +30,9 @@ use pocketmine\nbt\tag\StringTag;
class WritableBook extends Item{
const TAG_PAGES = "pages"; //TAG_List<TAG_Compound>
public const TAG_PAGES = "pages"; //TAG_List<TAG_Compound>
public const TAG_PAGE_TEXT = "text"; //TAG_String
public const TAG_PAGE_PHOTONAME = "photoname"; //TAG_String - TODO
public function __construct(int $meta = 0){
parent::__construct(self::WRITABLE_BOOK, $meta, "Book & Quill");
@ -44,8 +46,7 @@ class WritableBook extends Item{
* @return bool
*/
public function pageExists(int $pageId) : bool{
$pages = $this->getNamedTag()->getListTag(self::TAG_PAGES);
return $pages !== null and isset($pages[$pageId]);
return isset($this->getPages()[$pageId]);
}
/**
@ -63,7 +64,7 @@ class WritableBook extends Item{
$page = $pages[$pageId] ?? null;
if($page instanceof CompoundTag){
return $page->getString("text", "");
return $page->getString(self::TAG_PAGE_TEXT, "");
}
return null;
@ -88,7 +89,7 @@ class WritableBook extends Item{
/** @var CompoundTag[]|ListTag $pages */
$pages = $namedTag->getListTag(self::TAG_PAGES);
assert($pages instanceof ListTag);
$pages[$pageId]->setString("text", $pageText);
$pages[$pageId]->setString(self::TAG_PAGE_TEXT, $pageText);
$this->setNamedTag($namedTag);
@ -105,22 +106,19 @@ class WritableBook extends Item{
if($pageId < 0){
throw new \InvalidArgumentException("Page number \"$pageId\" is out of range");
}
$namedTag = $this->getNamedTag();
/** @var CompoundTag[]|ListTag $pages */
$pages = $namedTag->getListTag(self::TAG_PAGES) ?? new ListTag(self::TAG_PAGES, [], NBT::TAG_Compound);
$pages = $this->getPages();
for($id = 0; $id <= $pageId; $id++){
if(!$this->pageExists($id)){
if(!isset($pages[$id])){
$pages[$id] = new CompoundTag("", [
new StringTag("text", ""),
new StringTag("photoname", "")
new StringTag(self::TAG_PAGE_TEXT, ""),
new StringTag(self::TAG_PAGE_PHOTONAME, "")
]);
}
}
$namedTag->setTag($pages);
$this->setNamedTag($namedTag);
$this->setPages($pages);
}
/**
@ -131,14 +129,10 @@ class WritableBook extends Item{
* @return bool indicating success
*/
public function deletePage(int $pageId) : bool{
if(!$this->pageExists($pageId)){
return false;
}
$pages = $this->getPages();
unset($pages[$pageId]);
$namedTag = $this->getNamedTag();
unset($namedTag->getListTag(self::TAG_PAGES)[$pageId]);
$this->pushPages($pageId, $namedTag);
$this->setNamedTag($namedTag);
$this->setPages(array_values($pages));
return true;
}
@ -152,14 +146,17 @@ class WritableBook extends Item{
* @return bool indicating success
*/
public function insertPage(int $pageId, string $pageText = "") : bool{
$namedTag = $this->getNamedTag();
if(!isset($namedTag->pages) or !($namedTag->pages instanceof ListTag)){
$namedTag->pages = new ListTag("pages", []);
}
$this->pushPages($pageId, $namedTag, false);
$pages = $this->getPages();
$this->setPages(array_merge(
array_slice($pages, 0, $pageId),
[new CompoundTag("", [
new StringTag(self::TAG_PAGE_TEXT, $pageText),
new StringTag(self::TAG_PAGE_PHOTONAME, "")
])],
array_slice($pages, $pageId)
));
$namedTag->pages->{$pageId}->text->setValue($pageText);
$this->setNamedTag($namedTag);
return true;
}
@ -188,52 +185,27 @@ class WritableBook extends Item{
return 1;
}
/**
* @param int $pageId
* @param CompoundTag $namedTag
* @param bool $downwards
*
* @return bool
*/
private function pushPages(int $pageId, CompoundTag $namedTag, bool $downwards = true) : bool{
$pages = $this->getPages();
if(empty($pages)){
return false;
}
$pagesTag = $namedTag->getListTag(self::TAG_PAGES);
assert($pagesTag !== null);
$type = $downwards ? -1 : 1;
foreach($pages as $key => $page){
if(($key <= $pageId and $downwards) or ($key < $pageId and !$downwards)){
continue;
}
if($downwards){
unset($pagesTag[$key]);
}
$pagesTag[$key + $type] = new CompoundTag("", [
new StringTag("text", $page->text->getValue()),
new StringTag("photoname", "")
]);
}
return true;
}
/**
* Returns an array containing all pages of this book.
*
* @return CompoundTag[]
*/
public function getPages() : array{
$namedTag = $this->getNamedTag();
if(!isset($namedTag->pages)){
$pages = $this->getNamedTag()->getListTag(self::TAG_PAGES);
if($pages === null){
return [];
}
return array_filter((array) $namedTag->pages, function(string $key){
return is_numeric($key);
}, ARRAY_FILTER_USE_KEY);
return $pages->getValue();
}
/**
*
* @param CompoundTag[] $pages
*/
public function setPages(array $pages) : void{
$nbt = $this->getNamedTag();
$nbt->setTag(new ListTag(self::TAG_PAGES, $pages, NBT::TAG_Compound));
$this->setNamedTag($nbt);
}
}

View File

@ -25,14 +25,14 @@ namespace pocketmine\item;
class WrittenBook extends WritableBook{
const GENERATION_ORIGINAL = 0;
const GENERATION_COPY = 1;
const GENERATION_COPY_OF_COPY = 2;
const GENERATION_TATTERED = 3;
public const GENERATION_ORIGINAL = 0;
public const GENERATION_COPY = 1;
public const GENERATION_COPY_OF_COPY = 2;
public const GENERATION_TATTERED = 3;
const TAG_GENERATION = "generation"; //TAG_Int
const TAG_AUTHOR = "author"; //TAG_String
const TAG_TITLE = "title"; //TAG_String
public const TAG_GENERATION = "generation"; //TAG_Int
public const TAG_AUTHOR = "author"; //TAG_String
public const TAG_TITLE = "title"; //TAG_String
public function __construct(int $meta = 0){
Item::__construct(self::WRITTEN_BOOK, $meta, "Written Book");

View File

@ -26,62 +26,62 @@ namespace pocketmine\item\enchantment;
class Enchantment{
const PROTECTION = 0;
const FIRE_PROTECTION = 1;
const FEATHER_FALLING = 2;
const BLAST_PROTECTION = 3;
const PROJECTILE_PROTECTION = 4;
const THORNS = 5;
const RESPIRATION = 6;
const DEPTH_STRIDER = 7;
const AQUA_AFFINITY = 8;
const SHARPNESS = 9;
const SMITE = 10;
const BANE_OF_ARTHROPODS = 11;
const KNOCKBACK = 12;
const FIRE_ASPECT = 13;
const LOOTING = 14;
const EFFICIENCY = 15;
const SILK_TOUCH = 16;
const UNBREAKING = 17;
const FORTUNE = 18;
const POWER = 19;
const PUNCH = 20;
const FLAME = 21;
const INFINITY = 22;
const LUCK_OF_THE_SEA = 23;
const LURE = 24;
const FROST_WALKER = 25;
const MENDING = 26;
public const PROTECTION = 0;
public const FIRE_PROTECTION = 1;
public const FEATHER_FALLING = 2;
public const BLAST_PROTECTION = 3;
public const PROJECTILE_PROTECTION = 4;
public const THORNS = 5;
public const RESPIRATION = 6;
public const DEPTH_STRIDER = 7;
public const AQUA_AFFINITY = 8;
public const SHARPNESS = 9;
public const SMITE = 10;
public const BANE_OF_ARTHROPODS = 11;
public const KNOCKBACK = 12;
public const FIRE_ASPECT = 13;
public const LOOTING = 14;
public const EFFICIENCY = 15;
public const SILK_TOUCH = 16;
public const UNBREAKING = 17;
public const FORTUNE = 18;
public const POWER = 19;
public const PUNCH = 20;
public const FLAME = 21;
public const INFINITY = 22;
public const LUCK_OF_THE_SEA = 23;
public const LURE = 24;
public const FROST_WALKER = 25;
public const MENDING = 26;
const RARITY_COMMON = 0;
const RARITY_UNCOMMON = 1;
const RARITY_RARE = 2;
const RARITY_MYTHIC = 3;
public const RARITY_COMMON = 0;
public const RARITY_UNCOMMON = 1;
public const RARITY_RARE = 2;
public const RARITY_MYTHIC = 3;
const ACTIVATION_EQUIP = 0;
const ACTIVATION_HELD = 1;
const ACTIVATION_SELF = 2;
public const ACTIVATION_EQUIP = 0;
public const ACTIVATION_HELD = 1;
public const ACTIVATION_SELF = 2;
const SLOT_NONE = 0;
const SLOT_ALL = 0b11111111111111;
const SLOT_ARMOR = 0b1111;
const SLOT_HEAD = 0b1;
const SLOT_TORSO = 0b10;
const SLOT_LEGS = 0b100;
const SLOT_FEET = 0b1000;
const SLOT_SWORD = 0b10000;
const SLOT_BOW = 0b100000;
const SLOT_TOOL = 0b111000000;
const SLOT_HOE = 0b1000000;
const SLOT_SHEARS = 0b10000000;
const SLOT_FLINT_AND_STEEL = 0b10000000;
const SLOT_DIG = 0b111000000000;
const SLOT_AXE = 0b1000000000;
const SLOT_PICKAXE = 0b10000000000;
const SLOT_SHOVEL = 0b10000000000;
const SLOT_FISHING_ROD = 0b100000000000;
const SLOT_CARROT_STICK = 0b1000000000000;
public const SLOT_NONE = 0;
public const SLOT_ALL = 0b11111111111111;
public const SLOT_ARMOR = 0b1111;
public const SLOT_HEAD = 0b1;
public const SLOT_TORSO = 0b10;
public const SLOT_LEGS = 0b100;
public const SLOT_FEET = 0b1000;
public const SLOT_SWORD = 0b10000;
public const SLOT_BOW = 0b100000;
public const SLOT_TOOL = 0b111000000;
public const SLOT_HOE = 0b1000000;
public const SLOT_SHEARS = 0b10000000;
public const SLOT_FLINT_AND_STEEL = 0b10000000;
public const SLOT_DIG = 0b111000000000;
public const SLOT_AXE = 0b1000000000;
public const SLOT_PICKAXE = 0b10000000000;
public const SLOT_SHOVEL = 0b10000000000;
public const SLOT_FISHING_ROD = 0b100000000000;
public const SLOT_CARROT_STICK = 0b1000000000000;
/** @var Enchantment[] */
protected static $enchantments;

View File

@ -29,7 +29,7 @@ use pocketmine\utils\MainLogger;
class BaseLang{
const FALLBACK_LANGUAGE = "eng";
public const FALLBACK_LANGUAGE = "eng";
public static function getLanguageList(string $path = "") : array{
if($path === ""){

@ -1 +1 @@
Subproject commit 21a589bebf984ce16f6c18289ddf1ef94b1ba885
Subproject commit a907c227b0801791ec967dbcc240682f0eceec0d

View File

@ -93,26 +93,26 @@ class Level implements ChunkManager, Metadatable{
private static $levelIdCounter = 1;
private static $chunkLoaderCounter = 1;
const Y_MASK = 0xFF;
const Y_MAX = 0x100; //256
public const Y_MASK = 0xFF;
public const Y_MAX = 0x100; //256
const BLOCK_UPDATE_NORMAL = 1;
const BLOCK_UPDATE_RANDOM = 2;
const BLOCK_UPDATE_SCHEDULED = 3;
const BLOCK_UPDATE_WEAK = 4;
const BLOCK_UPDATE_TOUCH = 5;
public const BLOCK_UPDATE_NORMAL = 1;
public const BLOCK_UPDATE_RANDOM = 2;
public const BLOCK_UPDATE_SCHEDULED = 3;
public const BLOCK_UPDATE_WEAK = 4;
public const BLOCK_UPDATE_TOUCH = 5;
const TIME_DAY = 0;
const TIME_SUNSET = 12000;
const TIME_NIGHT = 14000;
const TIME_SUNRISE = 23000;
public const TIME_DAY = 0;
public const TIME_SUNSET = 12000;
public const TIME_NIGHT = 14000;
public const TIME_SUNRISE = 23000;
const TIME_FULL = 24000;
public const TIME_FULL = 24000;
const DIFFICULTY_PEACEFUL = 0;
const DIFFICULTY_EASY = 1;
const DIFFICULTY_NORMAL = 2;
const DIFFICULTY_HARD = 3;
public const DIFFICULTY_PEACEFUL = 0;
public const DIFFICULTY_EASY = 1;
public const DIFFICULTY_NORMAL = 2;
public const DIFFICULTY_HARD = 3;
/** @var Tile[] */
private $tiles = [];
@ -352,7 +352,8 @@ class Level implements ChunkManager, Metadatable{
$this->chunkPopulationQueueSize = (int) $this->server->getProperty("chunk-generation.population-queue-size", 2);
$this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", true);
$dontTickBlocks = $this->server->getProperty("chunk-ticking.disable-block-ticking", []);
$dontTickBlocks = array_fill_keys($this->server->getProperty("chunk-ticking.disable-block-ticking", []), true);
$this->randomTickBlocks = new \SplFixedArray(256);
foreach($this->randomTickBlocks as $id => $null){
$block = BlockFactory::get($id); //Make sure it's a copy
@ -732,11 +733,9 @@ class Level implements ChunkManager, Metadatable{
$this->timings->tileEntityTick->startTiming();
Timings::$tickTileEntityTimer->startTiming();
//Update tiles that need update
if(count($this->updateTiles) > 0){
foreach($this->updateTiles as $id => $tile){
if($tile->onUpdate() !== true){
unset($this->updateTiles[$id]);
}
foreach($this->updateTiles as $id => $tile){
if($tile->onUpdate() !== true){
unset($this->updateTiles[$id]);
}
}
Timings::$tickTileEntityTimer->stopTiming();
@ -2642,15 +2641,7 @@ class Level implements ChunkManager, Metadatable{
try{
if($chunk !== null){
if($trySave and $this->getAutoSave() and $chunk->isGenerated()){
$entities = 0;
foreach($chunk->getEntities() as $e){
if($e instanceof Player){
continue;
}
++$entities;
}
if($chunk->hasChanged() or count($chunk->getTiles()) > 0 or $entities > 0){
if($chunk->hasChanged() or count($chunk->getTiles()) > 0 or count($chunk->getSavableEntities()) > 0){
$this->provider->setChunk($x, $z, $chunk);
$this->provider->saveChunk($x, $z);
}
@ -2704,15 +2695,13 @@ class Level implements ChunkManager, Metadatable{
$max = $this->provider->getWorldHeight();
$v = $spawn->floor();
$chunk = $this->getChunk($v->x >> 4, $v->z >> 4, false);
$x = $v->x & 0x0f;
$z = $v->z & 0x0f;
$x = (int) $v->x;
$z = (int) $v->z;
if($chunk !== null){
$y = (int) min($max - 2, $v->y);
$wasAir = ($chunk->getBlockId($x, $y - 1, $z) === 0);
$wasAir = ($chunk->getBlockId($x & 0x0f, $y - 1, $z & 0x0f) === 0);
for(; $y > 0; --$y){
$b = $chunk->getFullBlock($x, $y, $z);
$block = BlockFactory::get($b >> 4, $b & 0x0f);
if($this->isFullBlock($block)){
if($this->isFullBlock($this->getBlockAt($x, $y, $z))){
if($wasAir){
$y++;
break;
@ -2723,12 +2712,8 @@ class Level implements ChunkManager, Metadatable{
}
for(; $y >= 0 and $y < $max; ++$y){
$b = $chunk->getFullBlock($x, $y + 1, $z);
$block = BlockFactory::get($b >> 4, $b & 0x0f);
if(!$this->isFullBlock($block)){
$b = $chunk->getFullBlock($x, $y, $z);
$block = BlockFactory::get($b >> 4, $b & 0x0f);
if(!$this->isFullBlock($block)){
if(!$this->isFullBlock($this->getBlockAt($x, $y + 1, $z))){
if(!$this->isFullBlock($this->getBlockAt($x, $y, $z))){
return new Position($spawn->x, $y === (int) $spawn->y ? $spawn->y : $y, $spawn->z, $this);
}
}else{

View File

@ -27,8 +27,8 @@ use pocketmine\entity\Entity;
use pocketmine\math\Vector3;
class MovingObjectPosition{
const TYPE_BLOCK_COLLISION = 0;
const TYPE_ENTITY_COLLISION = 1;
public const TYPE_BLOCK_COLLISION = 0;
public const TYPE_ENTITY_COLLISION = 1;
/** @var int */
public $typeOfHit;

View File

@ -30,6 +30,7 @@ use pocketmine\block\BlockFactory;
use pocketmine\entity\Entity;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\tile\Spawnable;
use pocketmine\tile\Tile;
@ -37,7 +38,7 @@ use pocketmine\utils\BinaryStream;
class Chunk{
const MAX_SUBCHUNKS = 16;
public const MAX_SUBCHUNKS = 16;
protected $x;
protected $z;
@ -666,6 +667,13 @@ class Chunk{
return $this->entities;
}
/**
* @return Entity[]
*/
public function getSavableEntities() : array{
return array_filter($this->entities, function(Entity $entity) : bool{ return $entity->canSaveWithChunk() and !$entity->isClosed(); });
}
/**
* @return Tile[]
*/
@ -729,7 +737,7 @@ class Chunk{
$level->timings->syncChunkLoadEntitiesTimer->startTiming();
foreach($this->NBTentities as $nbt){
if($nbt instanceof CompoundTag){
if(!isset($nbt->id)){
if(!$nbt->hasTag("id")){ //allow mixed types (because of leveldb)
$changed = true;
continue;
}
@ -740,7 +748,7 @@ class Chunk{
}
try{
$entity = Entity::createEntity($nbt["id"], $level, $nbt);
$entity = Entity::createEntity($nbt->getTag("id")->getValue(), $level, $nbt);
if(!($entity instanceof Entity)){
$changed = true;
continue;
@ -757,17 +765,17 @@ class Chunk{
$level->timings->syncChunkLoadTileEntitiesTimer->startTiming();
foreach($this->NBTtiles as $nbt){
if($nbt instanceof CompoundTag){
if(!isset($nbt->id)){
if(!$nbt->hasTag(Tile::TAG_ID, StringTag::class)){
$changed = true;
continue;
}
if(($nbt["x"] >> 4) !== $this->x or ($nbt["z"] >> 4) !== $this->z){
if(($nbt->getInt(Tile::TAG_X) >> 4) !== $this->x or ($nbt->getInt(Tile::TAG_Z) >> 4) !== $this->z){
$changed = true;
continue; //Fixes tiles allocated in wrong chunks.
}
if(Tile::createTile($nbt["id"], $level, $nbt) === null){
if(Tile::createTile($nbt->getString(Tile::TAG_ID), $level, $nbt) === null){
$changed = true;
continue;
}
@ -1003,11 +1011,6 @@ class Chunk{
return $chunk;
}
//TODO: get rid of this
public static function getEmptyChunk(int $x, int $z) : Chunk{
return new Chunk($x, $z);
}
/**
* Creates a block hash from chunk block coordinates. Used for extra data keys in chunk packets.
* @internal

View File

@ -44,32 +44,35 @@ use pocketmine\utils\MainLogger;
class LevelDB extends BaseLevelProvider{
//According to Tomasso, these aren't supposed to be readable anymore. Thankfully he didn't change the readable ones...
const TAG_DATA_2D = "\x2d";
const TAG_DATA_2D_LEGACY = "\x2e";
const TAG_SUBCHUNK_PREFIX = "\x2f";
const TAG_LEGACY_TERRAIN = "0";
const TAG_BLOCK_ENTITY = "1";
const TAG_ENTITY = "2";
const TAG_PENDING_TICK = "3";
const TAG_BLOCK_EXTRA_DATA = "4";
const TAG_BIOME_STATE = "5";
const TAG_STATE_FINALISATION = "6";
public const TAG_DATA_2D = "\x2d";
public const TAG_DATA_2D_LEGACY = "\x2e";
public const TAG_SUBCHUNK_PREFIX = "\x2f";
public const TAG_LEGACY_TERRAIN = "0";
public const TAG_BLOCK_ENTITY = "1";
public const TAG_ENTITY = "2";
public const TAG_PENDING_TICK = "3";
public const TAG_BLOCK_EXTRA_DATA = "4";
public const TAG_BIOME_STATE = "5";
public const TAG_STATE_FINALISATION = "6";
const FINALISATION_NEEDS_INSTATICKING = 0;
const FINALISATION_NEEDS_POPULATION = 1;
const FINALISATION_DONE = 2;
public const TAG_BORDER_BLOCKS = "8";
public const TAG_HARDCODED_SPAWNERS = "9";
const TAG_VERSION = "v";
public const FINALISATION_NEEDS_INSTATICKING = 0;
public const FINALISATION_NEEDS_POPULATION = 1;
public const FINALISATION_DONE = 2;
const ENTRY_FLAT_WORLD_LAYERS = "game_flatworldlayers";
public const TAG_VERSION = "v";
const GENERATOR_LIMITED = 0;
const GENERATOR_INFINITE = 1;
const GENERATOR_FLAT = 2;
public const ENTRY_FLAT_WORLD_LAYERS = "game_flatworldlayers";
const CURRENT_STORAGE_VERSION = 5; //Current MCPE level format version
const CURRENT_LEVEL_CHUNK_VERSION = 4;
const CURRENT_LEVEL_SUBCHUNK_VERSION = 0;
public const GENERATOR_LIMITED = 0;
public const GENERATOR_INFINITE = 1;
public const GENERATOR_FLAT = 2;
public const CURRENT_STORAGE_VERSION = 6; //Current MCPE level format version
public const CURRENT_LEVEL_CHUNK_VERSION = 7;
public const CURRENT_LEVEL_SUBCHUNK_VERSION = 0;
/** @var Chunk[] */
protected $chunks = [];
@ -77,7 +80,15 @@ class LevelDB extends BaseLevelProvider{
/** @var \LevelDB */
protected $db;
private static function checkForLevelDBExtension(){
if(!extension_loaded('leveldb')){
throw new LevelException("The leveldb PHP extension is required to use this world format");
}
}
public function __construct(Level $level, string $path){
self::checkForLevelDBExtension();
$this->level = $level;
$this->path = $path;
if(!file_exists($this->path)){
@ -92,12 +103,17 @@ class LevelDB extends BaseLevelProvider{
throw new LevelException("Invalid level.dat");
}
if(!defined('LEVELDB_ZLIB_RAW_COMPRESSION')){
throw new LevelException("Given version of php-leveldb doesn't support zlib raw compression");
}
$this->db = new \LevelDB($this->path . "/db", [
"compression" => LEVELDB_ZLIB_COMPRESSION
"compression" => LEVELDB_ZLIB_RAW_COMPRESSION
]);
if($this->levelData->getInt("StorageVersion", INT32_MAX, true) > self::CURRENT_STORAGE_VERSION){
throw new LevelException("Specified LevelDB world format version is not supported by " . \pocketmine\NAME);
$version = $this->levelData->getInt("StorageVersion", INT32_MAX, true);
if($version > self::CURRENT_STORAGE_VERSION){
throw new LevelException("Specified LevelDB world format version ($version) is not supported by " . \pocketmine\NAME);
}
if(!$this->levelData->hasTag("generatorName", StringTag::class)){
@ -145,6 +161,8 @@ class LevelDB extends BaseLevelProvider{
}
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []){
self::checkForLevelDBExtension();
if(!file_exists($path)){
mkdir($path, 0777, true);
}
@ -206,7 +224,7 @@ class LevelDB extends BaseLevelProvider{
$db = new \LevelDB($path . "/db", [
"compression" => LEVELDB_ZLIB_COMPRESSION
"compression" => LEVELDB_ZLIB_RAW_COMPRESSION
]);
if($generatorType === self::GENERATOR_FLAT and isset($options["preset"])){
@ -280,7 +298,7 @@ class LevelDB extends BaseLevelProvider{
$this->level->timings->syncChunkLoadDataTimer->startTiming();
$chunk = $this->readChunk($chunkX, $chunkZ);
if($chunk === null and $create){
$chunk = Chunk::getEmptyChunk($chunkX, $chunkZ);
$chunk = new Chunk($chunkX, $chunkZ);
}
$this->level->timings->syncChunkLoadDataTimer->stopTiming();
@ -318,6 +336,7 @@ class LevelDB extends BaseLevelProvider{
$binaryStream = new BinaryStream();
switch($chunkVersion){
case 7: //MCPE 1.2 (???)
case 4: //MCPE 1.1
//TODO: check beds
case 3: //MCPE 1.0
@ -518,11 +537,9 @@ class LevelDB extends BaseLevelProvider{
/** @var CompoundTag[] $entities */
$entities = [];
foreach($chunk->getEntities() as $entity){
if($entity->canSaveWithChunk() and !$entity->isClosed()){
$entity->saveNBT();
$entities[] = $entity->namedtag;
}
foreach($chunk->getSavableEntities() as $entity){
$entity->saveNBT();
$entities[] = $entity->namedtag;
}
$this->writeTags($entities, $index . self::TAG_ENTITY);

View File

@ -36,7 +36,7 @@ use pocketmine\utils\MainLogger;
class Anvil extends McRegion{
const REGION_FILE_EXTENSION = "mca";
public const REGION_FILE_EXTENSION = "mca";
public function nbtSerialize(Chunk $chunk) : string{
$nbt = new CompoundTag("Level", []);
@ -66,11 +66,9 @@ class Anvil extends McRegion{
$entities = [];
foreach($chunk->getEntities() as $entity){
if($entity->canSaveWithChunk() and !$entity->isClosed()){
$entity->saveNBT();
$entities[] = $entity->namedtag;
}
foreach($chunk->getSavableEntities() as $entity){
$entity->saveNBT();
$entities[] = $entity->namedtag;
}
$nbt->setTag(new ListTag("Entities", $entities, NBT::TAG_Compound));

View File

@ -38,7 +38,7 @@ use pocketmine\utils\MainLogger;
class McRegion extends BaseLevelProvider{
const REGION_FILE_EXTENSION = "mcr";
public const REGION_FILE_EXTENSION = "mcr";
/** @var RegionLoader[] */
protected $regions = [];
@ -87,11 +87,9 @@ class McRegion extends BaseLevelProvider{
$entities = [];
foreach($chunk->getEntities() as $entity){
if($entity->canSaveWithChunk() and !$entity->isClosed()){
$entity->saveNBT();
$entities[] = $entity->namedtag;
}
foreach($chunk->getSavableEntities() as $entity){
$entity->saveNBT();
$entities[] = $entity->namedtag;
}
$nbt->setTag(new ListTag("Entities", $entities, NBT::TAG_Compound));
@ -121,19 +119,17 @@ class McRegion extends BaseLevelProvider{
try{
$nbt->readCompressed($data);
$chunk = $nbt->getData();
$chunk = $nbt->getData()->getCompoundTag("Level");
if(!isset($chunk->Level) or !($chunk->Level instanceof CompoundTag)){
throw new ChunkException("Invalid NBT format");
if($chunk === null){
throw new ChunkException("Invalid NBT format, 'Level' key not found");
}
$chunk = $chunk->Level;
$subChunks = [];
$fullIds = isset($chunk->Blocks) ? $chunk->Blocks->getValue() : str_repeat("\x00", 32768);
$fullData = isset($chunk->Data) ? $chunk->Data->getValue() : str_repeat("\x00", 16384);
$fullSkyLight = isset($chunk->SkyLight) ? $chunk->SkyLight->getValue() : str_repeat("\xff", 16384);
$fullBlockLight = isset($chunk->BlockLight) ? $chunk->BlockLight->getValue() : str_repeat("\x00", 16384);
$fullIds = $chunk->hasTag("Blocks", ByteArrayTag::class) ? $chunk->getByteArray("Blocks") : str_repeat("\x00", 32768);
$fullData = $chunk->hasTag("Data", ByteArrayTag::class) ? $chunk->getByteArray("Data") : str_repeat("\x00", 16384);
$fullSkyLight = $chunk->hasTag("SkyLight", ByteArrayTag::class) ? $chunk->getByteArray("SkyLight") : str_repeat("\xff", 16384);
$fullBlockLight = $chunk->hasTag("BlockLight", ByteArrayTag::class) ? $chunk->getByteArray("BlockLight") : str_repeat("\x00", 16384);
for($y = 0; $y < 8; ++$y){
$offset = ($y << 4);
@ -163,34 +159,32 @@ class McRegion extends BaseLevelProvider{
$subChunks[$y] = new SubChunk($ids, $data, $skyLight, $blockLight);
}
if(isset($chunk->BiomeColors)){
$biomeIds = ChunkUtils::convertBiomeColors($chunk->BiomeColors->getValue()); //Convert back to original format
}elseif(isset($chunk->Biomes)){
$biomeIds = $chunk->Biomes->getValue();
if($chunk->hasTag("BiomeColors", IntArrayTag::class)){
$biomeIds = ChunkUtils::convertBiomeColors($chunk->getIntArray("BiomeColors")); //Convert back to original format
}elseif($chunk->hasTag("Biomes", ByteArrayTag::class)){
$biomeIds = $chunk->getByteArray("Biomes");
}else{
$biomeIds = "";
}
$heightMap = [];
if(isset($chunk->HeightMap)){
if($chunk->HeightMap instanceof ByteArrayTag){
$heightMap = array_values(unpack("C*", $chunk->HeightMap->getValue()));
}elseif($chunk->HeightMap instanceof IntArrayTag){
$heightMap = $chunk->HeightMap->getValue(); #blameshoghicp
}
if($chunk->hasTag("HeightMap", ByteArrayTag::class)){
$heightMap = array_values(unpack("C*", $chunk->getByteArray("HeightMap")));
}elseif($chunk->hasTag("HeightMap", IntArrayTag::class)){
$heightMap = $chunk->getIntArray("HeightMap"); #blameshoghicp
}
$result = new Chunk(
$chunk["xPos"],
$chunk["zPos"],
$chunk->getInt("xPos"),
$chunk->getInt("zPos"),
$subChunks,
isset($chunk->Entities) ? $chunk->Entities->getValue() : [],
isset($chunk->TileEntities) ? $chunk->TileEntities->getValue() : [],
$chunk->hasTag("Entities", ListTag::class) ? $chunk->getListTag("Entities")->getValue() : [],
$chunk->hasTag("TileEntities", ListTag::class) ? $chunk->getListTag("TileEntities")->getValue() : [],
$biomeIds,
$heightMap
);
$result->setLightPopulated(isset($chunk->LightPopulated) ? ((bool) $chunk->LightPopulated->getValue()) : false);
$result->setPopulated(isset($chunk->TerrainPopulated) ? ((bool) $chunk->TerrainPopulated->getValue()) : false);
$result->setLightPopulated($chunk->getByte("LightPopulated", 0) !== 0);
$result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0);
$result->setGenerated(true);
return $result;
}catch(\Throwable $e){
@ -347,7 +341,7 @@ class McRegion extends BaseLevelProvider{
/** @noinspection PhpStrictTypeCheckingInspection */
$chunk = $this->getRegion($regionX, $regionZ)->readChunk($chunkX - $regionX * 32, $chunkZ - $regionZ * 32);
if($chunk === null and $create){
$chunk = $this->getEmptyChunk($chunkX, $chunkZ);
$chunk = new Chunk($chunkX, $chunkZ);
}
$this->level->timings->syncChunkLoadDataTimer->stopTiming();
@ -422,16 +416,6 @@ class McRegion extends BaseLevelProvider{
$z = $chunkZ >> 5;
}
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return Chunk
*/
public function getEmptyChunk(int $chunkX, int $chunkZ) : Chunk{
return Chunk::getEmptyChunk($chunkX, $chunkZ);
}
/**
* @param int $x
* @param int $z

View File

@ -33,7 +33,7 @@ use pocketmine\nbt\tag\CompoundTag;
*/
class PMAnvil extends Anvil{
const REGION_FILE_EXTENSION = "mcapm";
public const REGION_FILE_EXTENSION = "mcapm";
protected function serializeSubChunk(SubChunk $subChunk) : CompoundTag{
return new CompoundTag("", [

View File

@ -29,13 +29,13 @@ use pocketmine\utils\Binary;
use pocketmine\utils\MainLogger;
class RegionLoader{
const VERSION = 1;
const COMPRESSION_GZIP = 1;
const COMPRESSION_ZLIB = 2;
public const VERSION = 1;
public const COMPRESSION_GZIP = 1;
public const COMPRESSION_ZLIB = 2;
const MAX_SECTOR_LENGTH = 256 << 12; //256 sectors, (1 MiB)
const REGION_HEADER_LENGTH = 8192; //4096 location table + 4096 timestamps
const MAX_REGION_FILE_SIZE = 32 * 32 * self::MAX_SECTOR_LENGTH + self::REGION_HEADER_LENGTH; //32 * 32 1MiB chunks + header size
public const MAX_SECTOR_LENGTH = 256 << 12; //256 sectors, (1 MiB)
public const REGION_HEADER_LENGTH = 8192; //4096 location table + 4096 timestamps
public const MAX_REGION_FILE_SIZE = 32 * 32 * self::MAX_SECTOR_LENGTH + self::REGION_HEADER_LENGTH; //32 * 32 1MiB chunks + header size
public static $COMPRESSION_LEVEL = 7;

View File

@ -78,7 +78,7 @@ class PopulationTask extends AsyncTask{
$zz = -1 + (int) ($i / 3);
$ck = $this->{"chunk$i"};
if($ck === null){
$chunks[$i] = Chunk::getEmptyChunk($chunk->getX() + $xx, $chunk->getZ() + $zz);
$chunks[$i] = new Chunk($chunk->getX() + $xx, $chunk->getZ() + $zz);
}else{
$chunks[$i] = Chunk::fastDeserialize($ck);
}

View File

@ -40,27 +40,27 @@ use pocketmine\utils\Random;
abstract class Biome{
const OCEAN = 0;
const PLAINS = 1;
const DESERT = 2;
const MOUNTAINS = 3;
const FOREST = 4;
const TAIGA = 5;
const SWAMP = 6;
const RIVER = 7;
public const OCEAN = 0;
public const PLAINS = 1;
public const DESERT = 2;
public const MOUNTAINS = 3;
public const FOREST = 4;
public const TAIGA = 5;
public const SWAMP = 6;
public const RIVER = 7;
const HELL = 8;
public const HELL = 8;
const ICE_PLAINS = 12;
public const ICE_PLAINS = 12;
const SMALL_MOUNTAINS = 20;
public const SMALL_MOUNTAINS = 20;
const BIRCH_FOREST = 27;
public const BIRCH_FOREST = 27;
const MAX_BIOMES = 256;
public const MAX_BIOMES = 256;
/** @var Biome[] */
private static $biomes = [];

View File

@ -29,8 +29,8 @@ use pocketmine\level\generator\populator\Tree;
class ForestBiome extends GrassyBiome{
const TYPE_NORMAL = 0;
const TYPE_BIRCH = 1;
public const TYPE_NORMAL = 0;
public const TYPE_BIRCH = 1;
public $type;

View File

@ -28,47 +28,47 @@ use pocketmine\network\mcpe\protocol\DataPacket;
abstract class Particle extends Vector3{
const TYPE_BUBBLE = 1;
const TYPE_CRITICAL = 2;
const TYPE_BLOCK_FORCE_FIELD = 3;
const TYPE_SMOKE = 4;
const TYPE_EXPLODE = 5;
const TYPE_EVAPORATION = 6;
const TYPE_FLAME = 7;
const TYPE_LAVA = 8;
const TYPE_LARGE_SMOKE = 9;
const TYPE_REDSTONE = 10;
const TYPE_RISING_RED_DUST = 11;
const TYPE_ITEM_BREAK = 12;
const TYPE_SNOWBALL_POOF = 13;
const TYPE_HUGE_EXPLODE = 14;
const TYPE_HUGE_EXPLODE_SEED = 15;
const TYPE_MOB_FLAME = 16;
const TYPE_HEART = 17;
const TYPE_TERRAIN = 18;
const TYPE_SUSPENDED_TOWN = 19, TYPE_TOWN_AURA = 19;
const TYPE_PORTAL = 20;
const TYPE_SPLASH = 21, TYPE_WATER_SPLASH = 21;
const TYPE_WATER_WAKE = 22;
const TYPE_DRIP_WATER = 23;
const TYPE_DRIP_LAVA = 24;
const TYPE_FALLING_DUST = 25, TYPE_DUST = 25;
const TYPE_MOB_SPELL = 26;
const TYPE_MOB_SPELL_AMBIENT = 27;
const TYPE_MOB_SPELL_INSTANTANEOUS = 28;
const TYPE_INK = 29;
const TYPE_SLIME = 30;
const TYPE_RAIN_SPLASH = 31;
const TYPE_VILLAGER_ANGRY = 32;
const TYPE_VILLAGER_HAPPY = 33;
const TYPE_ENCHANTMENT_TABLE = 34;
const TYPE_TRACKING_EMITTER = 35;
const TYPE_NOTE = 36;
const TYPE_WITCH_SPELL = 37;
const TYPE_CARROT = 38;
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
const TYPE_END_ROD = 40;
const TYPE_DRAGONS_BREATH = 41;
public const TYPE_END_ROD = 40;
public const TYPE_DRAGONS_BREATH = 41;
/**
* @return DataPacket|DataPacket[]

View File

@ -25,12 +25,12 @@ namespace pocketmine\math;
class Vector3{
const SIDE_DOWN = 0;
const SIDE_UP = 1;
const SIDE_NORTH = 2;
const SIDE_SOUTH = 3;
const SIDE_WEST = 4;
const SIDE_EAST = 5;
public const SIDE_DOWN = 0;
public const SIDE_UP = 1;
public const SIDE_NORTH = 2;
public const SIDE_SOUTH = 3;
public const SIDE_WEST = 4;
public const SIDE_EAST = 5;
public $x;
public $y;

View File

@ -53,20 +53,20 @@ use pocketmine\utils\Binary;
*/
class NBT{
const LITTLE_ENDIAN = 0;
const BIG_ENDIAN = 1;
const TAG_End = 0;
const TAG_Byte = 1;
const TAG_Short = 2;
const TAG_Int = 3;
const TAG_Long = 4;
const TAG_Float = 5;
const TAG_Double = 6;
const TAG_ByteArray = 7;
const TAG_String = 8;
const TAG_List = 9;
const TAG_Compound = 10;
const TAG_IntArray = 11;
public const LITTLE_ENDIAN = 0;
public const BIG_ENDIAN = 1;
public const TAG_End = 0;
public const TAG_Byte = 1;
public const TAG_Short = 2;
public const TAG_Int = 3;
public const TAG_Long = 4;
public const TAG_Float = 5;
public const TAG_Double = 6;
public const TAG_ByteArray = 7;
public const TAG_String = 8;
public const TAG_List = 9;
public const TAG_Compound = 10;
public const TAG_IntArray = 11;
public $buffer;
public $offset;

View File

@ -39,15 +39,25 @@ class CompoundTag extends NamedTag implements \ArrayAccess{
parent::__construct($name, $value);
}
/**
* @return int
*/
public function getCount(){
$count = 0;
return count($this->getValue());
}
/**
* @return NamedTag[]
*/
public function &getValue(){
$result = [];
foreach($this as $tag){
if($tag instanceof Tag){
++$count;
if($tag instanceof NamedTag){
$result[$tag->getName()] = $tag;
}
}
return $count;
return $result;
}
/**

View File

@ -109,6 +109,11 @@ class ListTag extends NamedTag implements \ArrayAccess, \Countable{
return isset($this->{$offset});
}
/**
* @param int $offset
*
* @return CompoundTag|ListTag|mixed
*/
public function offsetGet($offset){
if(isset($this->{$offset}) and $this->{$offset} instanceof Tag){
if($this->{$offset} instanceof \ArrayAccess){

View File

@ -169,7 +169,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
}
public function handlePlayerHotbar(PlayerHotbarPacket $packet) : bool{
return $this->player->handlePlayerHotbar($packet);
return true; //this packet is useless
}
public function handleCraftingEvent(CraftingEventPacket $packet) : bool{

View File

@ -30,7 +30,7 @@ use pocketmine\Server;
class VerifyLoginTask extends AsyncTask{
const MOJANG_ROOT_PUBLIC_KEY = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V";
public const MOJANG_ROOT_PUBLIC_KEY = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V";
/** @var LoginPacket */
private $packet;

View File

@ -28,7 +28,7 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
class AddBehaviorTreePacket extends DataPacket{
const NETWORK_ID = ProtocolInfo::ADD_BEHAVIOR_TREE_PACKET;
public const NETWORK_ID = ProtocolInfo::ADD_BEHAVIOR_TREE_PACKET;
/** @var string */
public $unknownString1;

View File

@ -31,7 +31,7 @@ use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\EntityLink;
class AddEntityPacket extends DataPacket{
const NETWORK_ID = ProtocolInfo::ADD_ENTITY_PACKET;
public const NETWORK_ID = ProtocolInfo::ADD_ENTITY_PACKET;
/** @var int|null */
public $entityUniqueId = null; //TODO

Some files were not shown because too many files have changed in this diff Show More