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 # Travis files
test_data/* test_data/*
# Doxygen
Documentation/*

View File

@ -21,7 +21,7 @@
"ext-yaml": ">=2.0.0", "ext-yaml": ">=2.0.0",
"ext-zip": "*", "ext-zip": "*",
"ext-zlib": ">=1.2.11", "ext-zlib": ">=1.2.11",
"pmmp/raklib": "^0.9.0", "pmmp/raklib": "dev-master#2b76936eb4a5b053128fe98050f33993cb3d8016",
"pmmp/pocketmine-spl": "^0.0.2" "pmmp/pocketmine-spl": "^0.0.2"
}, },
"autoload": { "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", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "55bdbaf13ac4ea71f0705f03f715172d", "content-hash": "2ef1e62099624431c885378a43b84cca",
"packages": [ "packages": [
{ {
"name": "pmmp/pocketmine-spl", "name": "pmmp/pocketmine-spl",
@ -40,16 +40,16 @@
}, },
{ {
"name": "pmmp/raklib", "name": "pmmp/raklib",
"version": "0.9.0", "version": "dev-master",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/RakLib.git", "url": "https://github.com/pmmp/RakLib.git",
"reference": "08470471eb16b4325fa02415fd12c5060eba9c34" "reference": "2b76936eb4a5b053128fe98050f33993cb3d8016"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/08470471eb16b4325fa02415fd12c5060eba9c34", "url": "https://api.github.com/repos/pmmp/RakLib/zipball/2b76936eb4a5b053128fe98050f33993cb3d8016",
"reference": "08470471eb16b4325fa02415fd12c5060eba9c34", "reference": "2b76936eb4a5b053128fe98050f33993cb3d8016",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -70,10 +70,10 @@
], ],
"description": "A RakNet server implementation written in PHP", "description": "A RakNet server implementation written in PHP",
"support": { "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" "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": [], "packages-dev": [],
@ -81,7 +81,8 @@
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": { "stability-flags": {
"php": 5, "php": 5,
"ext-pthreads": 20 "ext-pthreads": 20,
"pmmp/raklib": 20
}, },
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": 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(){ 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(){ 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{ public function hasPlayedBefore() : bool{

View File

@ -39,8 +39,6 @@ use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\inventory\InventoryCloseEvent; 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\cheat\PlayerIllegalMoveEvent;
use pocketmine\event\player\PlayerAchievementAwardedEvent; use pocketmine\event\player\PlayerAchievementAwardedEvent;
use pocketmine\event\player\PlayerAnimationEvent; use pocketmine\event\player\PlayerAnimationEvent;
@ -97,6 +95,7 @@ use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\PlayerNetworkSessionAdapter; use pocketmine\network\mcpe\PlayerNetworkSessionAdapter;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket; 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\SetSpawnPositionPacket;
use pocketmine\network\mcpe\protocol\SetTitlePacket; use pocketmine\network\mcpe\protocol\SetTitlePacket;
use pocketmine\network\mcpe\protocol\StartGamePacket; use pocketmine\network\mcpe\protocol\StartGamePacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\network\mcpe\protocol\TextPacket; use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\TransferPacket; use pocketmine\network\mcpe\protocol\TransferPacket;
use pocketmine\network\mcpe\protocol\types\CommandData; use pocketmine\network\mcpe\protocol\types\CommandData;
@ -165,11 +163,11 @@ use pocketmine\utils\UUID;
*/ */
class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
const SURVIVAL = 0; public const SURVIVAL = 0;
const CREATIVE = 1; public const CREATIVE = 1;
const ADVENTURE = 2; public const ADVENTURE = 2;
const SPECTATOR = 3; public const SPECTATOR = 3;
const VIEW = Player::SPECTATOR; public const VIEW = Player::SPECTATOR;
/** /**
* Checks a supplied username and checks it is valid. * Checks a supplied username and checks it is valid.
@ -204,7 +202,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public $playedBefore; public $playedBefore;
public $spawned = false; public $spawned = false;
public $loggedIn = false; public $loggedIn = false;
public $joined = false;
public $gamemode; public $gamemode;
public $lastBreak; public $lastBreak;
/** @var bool */ /** @var bool */
@ -229,8 +226,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public $achievements = []; public $achievements = [];
public $craftingType = 0; //0 = 2x2 crafting, 1 = 3x3 crafting, 2 = stonecutter
/** @var PlayerCursorInventory */ /** @var PlayerCursorInventory */
protected $cursorInventory; protected $cursorInventory;
@ -312,7 +307,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
* @return TranslationContainer|string * @return TranslationContainer|string
*/ */
public function getLeaveMessage(){ public function getLeaveMessage(){
if($this->joined){ if($this->spawned){
return new TranslationContainer(TextFormat::YELLOW . "%multiplayer.player.left", [ return new TranslationContainer(TextFormat::YELLOW . "%multiplayer.player.left", [
$this->getDisplayName() $this->getDisplayName()
]); ]);
@ -400,11 +395,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
} }
public function getFirstPlayed(){ 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(){ 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{ public function hasPlayedBefore() : bool{
@ -1013,8 +1008,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if($this->getHealth() <= 0){ if($this->getHealth() <= 0){
$this->sendRespawnPacket($this->getSpawn()); $this->sendRespawnPacket($this->getSpawn());
} }
$this->joined = true;
} }
protected function sendRespawnPacket(Vector3 $pos){ protected function sendRespawnPacket(Vector3 $pos){
@ -1319,8 +1312,10 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->allowFlight = $this->isCreative(); $this->allowFlight = $this->isCreative();
if($this->isSpectator()){ if($this->isSpectator()){
$this->flying = true; $this->flying = true;
$this->keepMovement = true;
$this->despawnFromAll(); $this->despawnFromAll();
}else{ }else{
$this->keepMovement = $this->allowMovementCheats;
if($this->isSurvival()){ if($this->isSurvival()){
$this->flying = false; $this->flying = false;
} }
@ -1337,11 +1332,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
} }
$this->sendSettings(); $this->sendSettings();
$this->inventory->sendContents($this);
$this->inventory->sendContents($this->getViewers());
$this->inventory->sendHeldItem($this->hasSpawned);
$this->inventory->sendCreativeContents(); $this->inventory->sendCreativeContents();
return true; return true;
@ -1450,11 +1440,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$bb->minY = $this->y - 0.2; $bb->minY = $this->y - 0.2;
$bb->maxY = $this->y + 0.2; $bb->maxY = $this->y + 0.2;
if(count($this->level->getCollisionBlocks($bb, true)) > 0){ $this->onGround = count($this->level->getCollisionBlocks($bb, true)) > 0;
$this->onGround = true;
}else{
$this->onGround = false;
}
} }
$this->isCollided = $this->onGround; $this->isCollided = $this->onGround;
} }
@ -1473,57 +1459,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
continue; continue;
} }
if($entity instanceof Arrow and $entity->hadCollision){ $entity->onCollideWithPlayer($this);
$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();
}
}
}
} }
} }
@ -1796,7 +1732,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->orderChunks(); $this->orderChunks();
} }
if(count($this->loadQueue) > 0 or !$this->spawned){ if(count($this->loadQueue) > 0){
$this->sendNextChunk(); $this->sendNextChunk();
} }
@ -1836,6 +1772,100 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->addDefaultWindows(); $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{ public function onVerifyCompleted(LoginPacket $packet, bool $isValid, bool $isAuthenticated) : void{
if($this->closed){ if($this->closed){
return; return;
@ -1873,13 +1903,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
protected function processLogin(){ protected function processLogin(){
foreach($this->server->getLoggedInPlayers() as $p){ foreach($this->server->getLoggedInPlayers() as $p){
if($p !== $this and $p->iusername === $this->iusername){ 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");
return;
}
}elseif($p->loggedIn and $this->getUniqueId()->equals($p->getUniqueId())){
if($p->kick("logged in from another location") === false){ if($p->kick("logged in from another location") === false){
$this->close($this->getLeaveMessage(), "Logged in from another location"); $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->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->namedtag->setString("NameTag", $this->username);
$this->gamemode = $this->namedtag->getInt("playerGameType", self::SURVIVAL) & 0x03; $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->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->setLevel($this->server->getDefaultLevel());
$this->namedtag["Level"] = $this->level->getName(); $this->namedtag->setString("Level", $this->level->getName());
$this->namedtag["Pos"][0] = $this->level->getSpawnLocation()->x; $spawnLocation = $this->level->getSpawnLocation();
$this->namedtag["Pos"][1] = $this->level->getSpawnLocation()->y; $this->namedtag->setTag(new ListTag("Pos", [
$this->namedtag["Pos"][2] = $this->level->getSpawnLocation()->z; new DoubleTag("", $spawnLocation->x),
new DoubleTag("", $spawnLocation->y),
new DoubleTag("", $spawnLocation->z)
]));
}else{ }else{
$this->setLevel($level); $this->setLevel($level);
} }
@ -1936,6 +1964,51 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->dataPacket($pk); $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(){ protected function completeLoginSequence(){
parent::__construct($this->level, $this->namedtag); parent::__construct($this->level, $this->namedtag);
$this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason")); $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->level->sendTime($this);
$this->sendAttributes(true); $this->sendAttributes(true);
$this->setNameTagVisible(true); $this->setNameTagVisible();
$this->setNameTagAlwaysVisible(true); $this->setNameTagAlwaysVisible();
$this->setCanClimb(true); $this->setCanClimb();
$this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logIn", [ $this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logIn", [
TextFormat::AQUA . $this->username . TextFormat::WHITE, TextFormat::AQUA . $this->username . TextFormat::WHITE,
@ -2017,138 +2090,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->server->onPlayerCompleteLoginSequence($this); $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 * Sends a chat message as this player. If the message begins with a / (forward-slash) it will be treated
* as a command. * as a command.
@ -2708,6 +2649,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
case PlayerActionPacket::ACTION_STOP_BREAK: case PlayerActionPacket::ACTION_STOP_BREAK:
$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_BLOCK_STOP_BREAK); $this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_BLOCK_STOP_BREAK);
break; break;
case PlayerActionPacket::ACTION_START_SLEEPING:
//unused
break;
case PlayerActionPacket::ACTION_STOP_SLEEPING: case PlayerActionPacket::ACTION_STOP_SLEEPING:
$this->stopSleep(); $this->stopSleep();
break; break;
@ -2881,16 +2825,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
return false; 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{ public function handleAdventureSettings(AdventureSettingsPacket $packet) : bool{
if($packet->entityUniqueId !== $this->getId()){ if($packet->entityUniqueId !== $this->getId()){
return false; //TODO return false; //TODO
@ -3188,17 +3122,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public function kick(string $reason = "", bool $isAdmin = true) : bool{ public function kick(string $reason = "", bool $isAdmin = true) : bool{
$this->server->getPluginManager()->callEvent($ev = new PlayerKickEvent($this, $reason, $this->getLeaveMessage())); $this->server->getPluginManager()->callEvent($ev = new PlayerKickEvent($this, $reason, $this->getLeaveMessage()));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$message = $reason;
if($isAdmin){ if($isAdmin){
if(!$this->isBanned()){ if(!$this->isBanned()){
$message = "Kicked by admin." . ($reason !== "" ? " Reason: " . $reason : ""); $message = "Kicked by admin." . ($reason !== "" ? " Reason: " . $reason : "");
}else{
$message = $reason;
} }
}else{ }else{
if($reason === ""){ if($reason === ""){
$message = "disconnectionScreen.noReason"; $message = "disconnectionScreen.noReason";
}else{
$message = $reason;
} }
} }
$this->close($ev->getQuitMessage(), $message); $this->close($ev->getQuitMessage(), $message);
@ -3392,20 +3323,19 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->stopSleep(); $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{ try{
$this->save(); $this->save();
}catch(\Throwable $e){ }catch(\Throwable $e){
$this->server->getLogger()->critical("Failed to save player data for " . $this->getName()); $this->server->getLogger()->critical("Failed to save player data for " . $this->getName());
$this->server->getLogger()->logException($e); $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()){ if($this->isValid()){
foreach($this->usedChunks as $index => $d){ foreach($this->usedChunks as $index => $d){
@ -3682,10 +3612,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}elseif($this->getLastDamageCause() === $source and $this->spawned){ }elseif($this->getLastDamageCause() === $source and $this->spawned){
$this->broadcastEntityEvent(EntityEventPacket::HURT_ANIMATION, null, [$this]); $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){ public function sendPosition(Vector3 $pos, float $yaw = null, float $pitch = null, int $mode = MovePlayerPacket::MODE_NORMAL, array $targets = null){
@ -3787,7 +3721,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if($this->craftingGrid instanceof BigCraftingGrid){ if($this->craftingGrid instanceof BigCraftingGrid){
$this->craftingGrid = new CraftingGrid($this); $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'); define('pocketmine\COMPOSER_AUTOLOADER_PATH', \pocketmine\PATH . 'vendor/autoload.php');
if(is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){ function composer_error_die($message){
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH); echo "[CRITICAL] $message" . PHP_EOL;
}else{ echo "[CRITICAL] Please install/update Composer dependencies or use provided builds." . PHP_EOL;
echo "[CRITICAL] Composer autoloader not found" . PHP_EOL;
echo "[CRITICAL] Please initialize composer dependencies before running." . PHP_EOL;
exit(1); 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 = new \BaseClassLoader();
$autoloader->addPath(\pocketmine\PATH . "src"); $autoloader->addPath(\pocketmine\PATH . "src");
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl"); $autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
$autoloader->register(false); $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?!?! set_time_limit(0); //Who set it to 30 seconds?!?!
ini_set("allow_url_fopen", '1'); ini_set("allow_url_fopen", '1');
@ -464,8 +466,8 @@ namespace pocketmine {
if(extension_loaded("leveldb")){ if(extension_loaded("leveldb")){
$leveldb_version = phpversion("leveldb"); $leveldb_version = phpversion("leveldb");
if(version_compare($leveldb_version, "0.2.0") < 0){ if(version_compare($leveldb_version, "0.2.1") < 0){
$logger->critical("php-leveldb >= 0.2.0 is required, while you have $leveldb_version"); $logger->critical("php-leveldb >= 0.2.1 is required, while you have $leveldb_version");
++$errors; ++$errors;
} }
} }

View File

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

View File

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

View File

@ -35,8 +35,8 @@ use pocketmine\tile\Tile;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
class Bed extends Transparent{ class Bed extends Transparent{
const BITFLAG_OCCUPIED = 0x04; public const BITFLAG_OCCUPIED = 0x04;
const BITFLAG_HEAD = 0x08; public const BITFLAG_HEAD = 0x08;
protected $id = self::BED_BLOCK; protected $id = self::BED_BLOCK;
@ -142,7 +142,7 @@ class Bed extends Transparent{
return true; return true;
}elseif($player->distanceSquared($this) > 4 and $player->distanceSquared($other) > 4){ }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; return true;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -58,17 +58,6 @@ class ItemFrame extends Flowable{
return true; 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){ public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){ if($type === Level::BLOCK_UPDATE_NORMAL){
$sides = [ $sides = [
@ -109,4 +98,18 @@ class ItemFrame extends Flowable{
public function getVariantBitmask() : int{ public function getVariantBitmask() : int{
return 0; 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; use pocketmine\Player;
class Leaves extends Transparent{ class Leaves extends Transparent{
const OAK = 0; public const OAK = 0;
const SPRUCE = 1; public const SPRUCE = 1;
const BIRCH = 2; public const BIRCH = 2;
const JUNGLE = 3; public const JUNGLE = 3;
const ACACIA = 0; public const ACACIA = 0;
const DARK_OAK = 1; public const DARK_OAK = 1;
protected $id = self::LEAVES; protected $id = self::LEAVES;
protected $woodType = self::WOOD; protected $woodType = self::WOOD;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,12 +31,12 @@ use pocketmine\Player;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class Sapling extends Flowable{ class Sapling extends Flowable{
const OAK = 0; public const OAK = 0;
const SPRUCE = 1; public const SPRUCE = 1;
const BIRCH = 2; public const BIRCH = 2;
const JUNGLE = 3; public const JUNGLE = 3;
const ACACIA = 4; public const ACACIA = 4;
const DARK_OAK = 5; public const DARK_OAK = 5;
protected $id = self::SAPLING; 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; use pocketmine\item\Tool;
class Stone extends Solid{ class Stone extends Solid{
const NORMAL = 0; public const NORMAL = 0;
const GRANITE = 1; public const GRANITE = 1;
const POLISHED_GRANITE = 2; public const POLISHED_GRANITE = 2;
const DIORITE = 3; public const DIORITE = 3;
const POLISHED_DIORITE = 4; public const POLISHED_DIORITE = 4;
const ANDESITE = 5; public const ANDESITE = 5;
const POLISHED_ANDESITE = 6; public const POLISHED_ANDESITE = 6;
protected $id = self::STONE; protected $id = self::STONE;

View File

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

View File

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

View File

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

View File

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

View File

@ -32,10 +32,10 @@ use pocketmine\math\Vector3;
use pocketmine\Player; use pocketmine\Player;
class Vine extends Flowable{ class Vine extends Flowable{
const FLAG_SOUTH = 0x01; public const FLAG_SOUTH = 0x01;
const FLAG_WEST = 0x02; public const FLAG_WEST = 0x02;
const FLAG_NORTH = 0x04; public const FLAG_NORTH = 0x04;
const FLAG_EAST = 0x08; public const FLAG_EAST = 0x08;
protected $id = self::VINE; 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; use pocketmine\Player;
class Wood extends Solid{ class Wood extends Solid{
const OAK = 0; public const OAK = 0;
const SPRUCE = 1; public const SPRUCE = 1;
const BIRCH = 2; public const BIRCH = 2;
const JUNGLE = 3; public const JUNGLE = 3;
protected $id = self::WOOD; protected $id = self::WOOD;

View File

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

View File

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

View File

@ -168,7 +168,7 @@ abstract class Command{
} }
if($this->permissionMessage === null){ 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 !== ""){ }elseif($this->permissionMessage !== ""){
$target->sendMessage(str_replace("<permission>", $this->getPermission(), $this->permissionMessage)); $target->sendMessage(str_replace("<permission>", $this->getPermission(), $this->permissionMessage));
} }

View File

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

View File

@ -79,7 +79,7 @@ class GamemodeCommand extends VanillaCommand{
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.self", [Server::getGamemodeString($gameMode)])); Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.self", [Server::getGamemodeString($gameMode)]));
}else{ }else{
$target->sendMessage(new TranslationContainer("gameMode.changed", [Server::getGamemodeString($gameMode)])); $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; use pocketmine\command\CommandSender;
abstract class VanillaCommand extends Command{ abstract class VanillaCommand extends Command{
const MAX_COORD = 30000000; public const MAX_COORD = 30000000;
const MIN_COORD = -30000000; public const MIN_COORD = -30000000;
/** /**
* @param CommandSender $sender * @param CommandSender $sender

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -44,12 +44,12 @@ use pocketmine\utils\UUID;
class Human extends Creature implements ProjectileSource, InventoryHolder{ class Human extends Creature implements ProjectileSource, InventoryHolder{
const DATA_PLAYER_FLAG_SLEEP = 1; public const DATA_PLAYER_FLAG_SLEEP = 1;
const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK 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 */ /** @var PlayerInventory */
protected $inventory; protected $inventory;
@ -73,9 +73,12 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
protected $baseOffset = 1.62; protected $baseOffset = 1.62;
public function __construct(Level $level, CompoundTag $nbt){ 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()))){ 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"); throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
} }
}
parent::__construct($level, $nbt); parent::__construct($level, $nbt);
} }

View File

@ -26,12 +26,14 @@ namespace pocketmine\entity;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ItemDespawnEvent; use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent; use pocketmine\event\entity\ItemSpawnEvent;
use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\item\Item as ItemItem; use pocketmine\item\Item as ItemItem;
use pocketmine\network\mcpe\protocol\AddItemEntityPacket; use pocketmine\network\mcpe\protocol\AddItemEntityPacket;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\Player; use pocketmine\Player;
class Item extends Entity{ class Item extends Entity{
const NETWORK_ID = self::ITEM; public const NETWORK_ID = self::ITEM;
/** @var string */ /** @var string */
protected $owner = ""; protected $owner = "";
@ -55,7 +57,7 @@ class Item extends Entity{
parent::initEntity(); parent::initEntity();
$this->setMaxHealth(5); $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->age = $this->namedtag->getShort("Age", $this->age);
$this->pickupDelay = $this->namedtag->getShort("PickupDelay", $this->pickupDelay); $this->pickupDelay = $this->namedtag->getShort("PickupDelay", $this->pickupDelay);
$this->owner = $this->namedtag->getString("Owner", $this->owner); $this->owner = $this->namedtag->getString("Owner", $this->owner);
@ -202,4 +204,39 @@ class Item extends Entity{
$player->dataPacket($pk); $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(); $health = $this->getMaxHealth();
if($this->namedtag->hasTag("HealF", FloatTag::class)){ 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"); $this->namedtag->removeTag("HealF");
}elseif($this->namedtag->hasTag("Health")){ }elseif($this->namedtag->hasTag("Health")){
$healthTag = $this->namedtag->getTag("Health"); $healthTag = $this->namedtag->getTag("Health");
@ -550,7 +550,7 @@ abstract class Living extends Entity implements Damageable{
* @param int $ticks * @param int $ticks
*/ */
public function setMaxAirSupplyTicks(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; use pocketmine\network\mcpe\protocol\LevelEventPacket;
class PrimedTNT extends Entity implements Explosive{ class PrimedTNT extends Entity implements Explosive{
const NETWORK_ID = self::TNT; public const NETWORK_ID = self::TNT;
public $width = 0.98; public $width = 0.98;
public $height = 0.98; public $height = 0.98;

View File

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

View File

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

View File

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

View File

@ -24,11 +24,16 @@ declare(strict_types=1);
namespace pocketmine\entity\projectile; namespace pocketmine\entity\projectile;
use pocketmine\entity\Entity; 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\level\Level;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\TakeItemEntityPacket;
use pocketmine\Player;
class Arrow extends Projectile{ class Arrow extends Projectile{
const NETWORK_ID = self::ARROW; public const NETWORK_ID = self::ARROW;
public $width = 0.25; public $width = 0.25;
public $height = 0.25; public $height = 0.25;
@ -78,4 +83,30 @@ class Arrow extends Projectile{
return $hasUpdate; 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; namespace pocketmine\entity\projectile;
class Egg extends Throwable{ class Egg extends Throwable{
const NETWORK_ID = self::EGG; public const NETWORK_ID = self::EGG;
//TODO: spawn chickens on collision //TODO: spawn chickens on collision
} }

View File

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

View File

@ -24,6 +24,6 @@ declare(strict_types=1);
namespace pocketmine\entity\projectile; namespace pocketmine\entity\projectile;
class Snowball extends Throwable{ 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 * Event call is of very low importance and should be ran first, to allow
* other plugins to further customise the outcome * other plugins to further customise the outcome
*/ */
const LOWEST = 5; public const LOWEST = 5;
/** /**
* Event call is of low importance * 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 * 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 * 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 * Event call is critical and must have the final say in what happens
* to the event * to the event
*/ */
const HIGHEST = 1; public const HIGHEST = 1;
/** /**
* Event is listened to purely for monitoring the outcome of an event. * Event is listened to purely for monitoring the outcome of an event.
* *
* No modifications to the event should be made under this priority * 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{ class EntityDamageEvent extends EntityEvent implements Cancellable{
public static $handlerList = null; public static $handlerList = null;
const MODIFIER_BASE = 0; public const MODIFIER_BASE = 0;
const MODIFIER_ARMOR = 1; public const MODIFIER_ARMOR = 1;
const MODIFIER_STRENGTH = 2; public const MODIFIER_STRENGTH = 2;
const MODIFIER_WEAKNESS = 3; public const MODIFIER_WEAKNESS = 3;
const MODIFIER_RESISTANCE = 4; public const MODIFIER_RESISTANCE = 4;
const MODIFIER_ABSORPTION = 5; public const MODIFIER_ABSORPTION = 5;
const CAUSE_CONTACT = 0; public const CAUSE_CONTACT = 0;
const CAUSE_ENTITY_ATTACK = 1; public const CAUSE_ENTITY_ATTACK = 1;
const CAUSE_PROJECTILE = 2; public const CAUSE_PROJECTILE = 2;
const CAUSE_SUFFOCATION = 3; public const CAUSE_SUFFOCATION = 3;
const CAUSE_FALL = 4; public const CAUSE_FALL = 4;
const CAUSE_FIRE = 5; public const CAUSE_FIRE = 5;
const CAUSE_FIRE_TICK = 6; public const CAUSE_FIRE_TICK = 6;
const CAUSE_LAVA = 7; public const CAUSE_LAVA = 7;
const CAUSE_DROWNING = 8; public const CAUSE_DROWNING = 8;
const CAUSE_BLOCK_EXPLOSION = 9; public const CAUSE_BLOCK_EXPLOSION = 9;
const CAUSE_ENTITY_EXPLOSION = 10; public const CAUSE_ENTITY_EXPLOSION = 10;
const CAUSE_VOID = 11; public const CAUSE_VOID = 11;
const CAUSE_SUICIDE = 12; public const CAUSE_SUICIDE = 12;
const CAUSE_MAGIC = 13; public const CAUSE_MAGIC = 13;
const CAUSE_CUSTOM = 14; public const CAUSE_CUSTOM = 14;
const CAUSE_STARVATION = 15; public const CAUSE_STARVATION = 15;
/** @var int */ /** @var int */
private $cause; private $cause;

View File

@ -29,11 +29,11 @@ use pocketmine\event\Cancellable;
class EntityRegainHealthEvent extends EntityEvent implements Cancellable{ class EntityRegainHealthEvent extends EntityEvent implements Cancellable{
public static $handlerList = null; public static $handlerList = null;
const CAUSE_REGEN = 0; public const CAUSE_REGEN = 0;
const CAUSE_EATING = 1; public const CAUSE_EATING = 1;
const CAUSE_MAGIC = 2; public const CAUSE_MAGIC = 2;
const CAUSE_CUSTOM = 3; public const CAUSE_CUSTOM = 3;
const CAUSE_SATURATION = 4; public const CAUSE_SATURATION = 4;
/** @var float */ /** @var float */
private $amount; 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. * @deprecated This is dependent on the protocol and should not be here.
* Use the constants in {@link pocketmine\network\mcpe\protocol\AnimatePacket} instead. * Use the constants in {@link pocketmine\network\mcpe\protocol\AnimatePacket} instead.
*/ */
const ARM_SWING = 1; public const ARM_SWING = 1;
/** @var int */ /** @var int */
private $animationType; private $animationType;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,9 +24,35 @@ declare(strict_types=1);
namespace pocketmine\item; namespace pocketmine\item;
use pocketmine\nbt\tag\IntTag;
use pocketmine\utils\Binary;
use pocketmine\utils\Color;
abstract class Armor extends Item{ abstract class Armor extends Item{
public const TAG_CUSTOM_COLOR = "customColor"; //TAG_Int
public function getMaxStackSize() : int{ public function getMaxStackSize() : int{
return 1; 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 * @return bool
*/ */
public function isUnbreakable() : bool{ public function isUnbreakable() : bool{
$tag = $this->getNamedTagEntry("Unbreakable"); return $this->getNamedTag()->getByte("Unbreakable", 0) !== 0;
return $tag !== null and $tag->getValue() !== 0;
} }
/** /**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -40,27 +40,27 @@ use pocketmine\utils\Random;
abstract class Biome{ abstract class Biome{
const OCEAN = 0; public const OCEAN = 0;
const PLAINS = 1; public const PLAINS = 1;
const DESERT = 2; public const DESERT = 2;
const MOUNTAINS = 3; public const MOUNTAINS = 3;
const FOREST = 4; public const FOREST = 4;
const TAIGA = 5; public const TAIGA = 5;
const SWAMP = 6; public const SWAMP = 6;
const RIVER = 7; 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[] */ /** @var Biome[] */
private static $biomes = []; private static $biomes = [];

View File

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

View File

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

View File

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

View File

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

View File

@ -39,15 +39,25 @@ class CompoundTag extends NamedTag implements \ArrayAccess{
parent::__construct($name, $value); parent::__construct($name, $value);
} }
/**
* @return int
*/
public function getCount(){ public function getCount(){
$count = 0; return count($this->getValue());
}
/**
* @return NamedTag[]
*/
public function &getValue(){
$result = [];
foreach($this as $tag){ foreach($this as $tag){
if($tag instanceof Tag){ if($tag instanceof NamedTag){
++$count; $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}); return isset($this->{$offset});
} }
/**
* @param int $offset
*
* @return CompoundTag|ListTag|mixed
*/
public function offsetGet($offset){ public function offsetGet($offset){
if(isset($this->{$offset}) and $this->{$offset} instanceof Tag){ if(isset($this->{$offset}) and $this->{$offset} instanceof Tag){
if($this->{$offset} instanceof \ArrayAccess){ if($this->{$offset} instanceof \ArrayAccess){

View File

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

View File

@ -30,7 +30,7 @@ use pocketmine\Server;
class VerifyLoginTask extends AsyncTask{ 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 */ /** @var LoginPacket */
private $packet; private $packet;

View File

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

View File

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

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