mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-22 08:44:01 +00:00
Merge branch 'master' into mcpe-1.2.5
This commit is contained in:
commit
73cd195e76
7
.gitmodules
vendored
7
.gitmodules
vendored
@ -1,10 +1,3 @@
|
||||
[submodule "src/raklib"]
|
||||
path = src/raklib
|
||||
url = https://github.com/pmmp/RakLib.git
|
||||
branch = master
|
||||
[submodule "src/spl"]
|
||||
path = src/spl
|
||||
url = https://github.com/pmmp/PocketMine-SPL.git
|
||||
[submodule "src/pocketmine/lang/locale"]
|
||||
path = src/pocketmine/lang/locale
|
||||
url = https://github.com/pmmp/PocketMine-Language.git
|
||||
|
@ -5,7 +5,7 @@
|
||||
"homepage": "https://pmmp.io",
|
||||
"license": "LGPL-3.0",
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"php": ">=7.2.0RC3",
|
||||
"ext-bcmath": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-hash": "*",
|
||||
@ -20,14 +20,23 @@
|
||||
"ext-spl": "*",
|
||||
"ext-yaml": ">=2.0.0",
|
||||
"ext-zip": "*",
|
||||
"ext-zlib": ">=1.2.11"
|
||||
"ext-zlib": ">=1.2.11",
|
||||
"pmmp/raklib": "^0.9.0",
|
||||
"pmmp/pocketmine-spl": "^0.0.2"
|
||||
},
|
||||
"autoload": {
|
||||
"exclude-from-classmap": [
|
||||
"src/spl/stubs"
|
||||
],
|
||||
"psr-0": {
|
||||
"": ["src", "src/spl"]
|
||||
"": ["src"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/RakLib"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/PocketMine-SPL"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
77
composer.lock
generated
77
composer.lock
generated
@ -4,18 +4,89 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "d4fecad9dce5314493052c870c8cf059",
|
||||
"packages": [],
|
||||
"content-hash": "55bdbaf13ac4ea71f0705f03f715172d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "pmmp/pocketmine-spl",
|
||||
"version": "0.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/PocketMine-SPL.git",
|
||||
"reference": "065b631d63e2c4ddb3141f63a07a9ecbab8357d1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/PocketMine-SPL/zipball/065b631d63e2c4ddb3141f63a07a9ecbab8357d1",
|
||||
"reference": "065b631d63e2c4ddb3141f63a07a9ecbab8357d1",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"exclude-from-classmap": [
|
||||
"stubs"
|
||||
],
|
||||
"classmap": [
|
||||
"./"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"LGPL-3.0"
|
||||
],
|
||||
"description": "Standard library files required by PocketMine-MP and related projects",
|
||||
"support": {
|
||||
"source": "https://github.com/pmmp/PocketMine-SPL/tree/0.0.2"
|
||||
},
|
||||
"time": "2017-11-14T18:56:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pmmp/raklib",
|
||||
"version": "0.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/RakLib.git",
|
||||
"reference": "08470471eb16b4325fa02415fd12c5060eba9c34"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/08470471eb16b4325fa02415fd12c5060eba9c34",
|
||||
"reference": "08470471eb16b4325fa02415fd12c5060eba9c34",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-bcmath": "*",
|
||||
"ext-pthreads": ">=3.1.7dev",
|
||||
"ext-sockets": "*",
|
||||
"php": ">=7.2.0RC3",
|
||||
"pmmp/pocketmine-spl": "^0.0.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"./"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"GPL-3.0"
|
||||
],
|
||||
"description": "A RakNet server implementation written in PHP",
|
||||
"support": {
|
||||
"source": "https://github.com/pmmp/RakLib/tree/0.9.0",
|
||||
"issues": "https://github.com/pmmp/RakLib/issues"
|
||||
},
|
||||
"time": "2017-11-14T19:03:14+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"php": 5,
|
||||
"ext-pthreads": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=7.2",
|
||||
"php": ">=7.2.0RC3",
|
||||
"ext-bcmath": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-hash": "*",
|
||||
|
@ -97,9 +97,7 @@ use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\LongTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\network\mcpe\PlayerNetworkSessionAdapter;
|
||||
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\AnimatePacket;
|
||||
@ -1331,7 +1329,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$this->resetFallDistance();
|
||||
|
||||
$this->namedtag->playerGameType = new IntTag("playerGameType", $this->gamemode);
|
||||
$this->namedtag->setInt("playerGameType", $this->gamemode);
|
||||
if(!$client){ //Gamemode changed by server, do not send for client changes
|
||||
$this->sendGamemode();
|
||||
}else{
|
||||
@ -1893,15 +1891,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$this->namedtag = $this->server->getOfflinePlayerData($this->username);
|
||||
|
||||
$this->playedBefore = ($this->namedtag["lastPlayed"] - $this->namedtag["firstPlayed"]) > 1; // microtime(true) - microtime(true) may have less than one millisecond difference
|
||||
if(!isset($this->namedtag->NameTag)){
|
||||
$this->namedtag->NameTag = new StringTag("NameTag", $this->username);
|
||||
}else{
|
||||
$this->namedtag["NameTag"] = $this->username;
|
||||
}
|
||||
$this->gamemode = $this->namedtag["playerGameType"] & 0x03;
|
||||
$this->namedtag->setString("NameTag", $this->username);
|
||||
|
||||
$this->gamemode = $this->namedtag->getInt("playerGameType", self::SURVIVAL) & 0x03;
|
||||
if($this->server->getForceGamemode()){
|
||||
$this->gamemode = $this->server->getGamemode();
|
||||
$this->namedtag->playerGameType = new IntTag("playerGameType", $this->gamemode);
|
||||
$this->namedtag->setInt("playerGameType", $this->gamemode);
|
||||
}
|
||||
|
||||
$this->allowFlight = $this->isCreative();
|
||||
@ -1918,12 +1913,13 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$this->achievements = [];
|
||||
|
||||
$achievements = $this->namedtag->getCompoundTag("Achievements") ?? [];
|
||||
/** @var ByteTag $achievement */
|
||||
foreach($this->namedtag->Achievements as $achievement){
|
||||
foreach($achievements as $achievement){
|
||||
$this->achievements[$achievement->getName()] = $achievement->getValue() !== 0;
|
||||
}
|
||||
|
||||
$this->namedtag->lastPlayed = new LongTag("lastPlayed", (int) floor(microtime(true) * 1000));
|
||||
$this->namedtag->setLong("lastPlayed", (int) floor(microtime(true) * 1000));
|
||||
if($this->server->getAutoSave()){
|
||||
$this->server->saveOfflinePlayerData($this->username, $this->namedtag, true);
|
||||
}
|
||||
@ -1950,8 +1946,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
if(!$this->hasValidSpawnPosition()){
|
||||
if(isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName((string) $this->namedtag["SpawnLevel"])) instanceof Level){
|
||||
$this->spawnPosition = new WeakPosition($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level);
|
||||
if(($level = $this->server->getLevelByName($this->namedtag->getString("SpawnLevel", ""))) instanceof Level){
|
||||
$this->spawnPosition = new WeakPosition($this->namedtag->getInt("SpawnX"), $this->namedtag->getInt("SpawnY"), $this->namedtag->getInt("SpawnZ"), $level);
|
||||
}else{
|
||||
$this->spawnPosition = WeakPosition::fromObject($this->level->getSafeSpawn());
|
||||
}
|
||||
@ -3499,22 +3495,24 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
parent::saveNBT();
|
||||
|
||||
if($this->isValid()){
|
||||
$this->namedtag->Level = new StringTag("Level", $this->level->getFolderName());
|
||||
$this->namedtag->setString("Level", $this->level->getFolderName());
|
||||
}
|
||||
|
||||
if($this->hasValidSpawnPosition()){
|
||||
$this->namedtag->SpawnLevel = new StringTag("SpawnLevel", $this->spawnPosition->getLevel()->getFolderName());
|
||||
$this->namedtag->SpawnX = new IntTag("SpawnX", (int) $this->spawnPosition->x);
|
||||
$this->namedtag->SpawnY = new IntTag("SpawnY", (int) $this->spawnPosition->y);
|
||||
$this->namedtag->SpawnZ = new IntTag("SpawnZ", (int) $this->spawnPosition->z);
|
||||
$this->namedtag->setString("SpawnLevel", $this->spawnPosition->getLevel()->getFolderName());
|
||||
$this->namedtag->setInt("SpawnX", (int) $this->spawnPosition->x);
|
||||
$this->namedtag->setInt("SpawnY", (int) $this->spawnPosition->y);
|
||||
$this->namedtag->setInt("SpawnZ", (int) $this->spawnPosition->z);
|
||||
}
|
||||
|
||||
$achievements = new CompoundTag("Achievements");
|
||||
foreach($this->achievements as $achievement => $status){
|
||||
$this->namedtag->Achievements[$achievement] = new ByteTag($achievement, $status === true ? 1 : 0);
|
||||
$achievements->setByte($achievement, $status === true ? 1 : 0);
|
||||
}
|
||||
$this->namedtag->setTag($achievements);
|
||||
|
||||
$this->namedtag["playerGameType"] = $this->gamemode;
|
||||
$this->namedtag["lastPlayed"] = (int) floor(microtime(true) * 1000);
|
||||
$this->namedtag->setInt("playerGameType", $this->gamemode);
|
||||
$this->namedtag->setLong("lastPlayed", (int) floor(microtime(true) * 1000));
|
||||
|
||||
if($this->username != "" and $this->namedtag instanceof CompoundTag){
|
||||
$this->server->saveOfflinePlayerData($this->username, $this->namedtag, $async);
|
||||
|
@ -129,30 +129,16 @@ namespace pocketmine {
|
||||
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
$requiredSplVer = "0.0.1";
|
||||
if(!is_file(\pocketmine\PATH . "src/spl/version.php")){
|
||||
echo "[CRITICAL] Cannot find PocketMine-SPL or incompatible version." . PHP_EOL;
|
||||
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
|
||||
exit(1);
|
||||
}elseif(version_compare($requiredSplVer, require(\pocketmine\PATH . "src/spl/version.php")) > 0){
|
||||
echo "[CRITICAL] Incompatible PocketMine-SPL submodule version ($requiredSplVer is required)." . PHP_EOL;
|
||||
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
define('pocketmine\COMPOSER_AUTOLOADER_PATH', \pocketmine\PATH . 'vendor/autoload.php');
|
||||
|
||||
if(is_file(\pocketmine\PATH . "vendor/autoload.php")){
|
||||
require_once(\pocketmine\PATH . "vendor/autoload.php");
|
||||
if(is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
|
||||
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
|
||||
}else{
|
||||
echo "[CRITICAL] Composer autoloader not found" . PHP_EOL;
|
||||
echo "[CRITICAL] Please initialize composer dependencies before running." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!class_exists("ClassLoader", false)){
|
||||
require_once(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
||||
require_once(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||
}
|
||||
|
||||
/*
|
||||
* We now use the Composer autoloader, but this autoloader is still used by RakLib and for loading plugins.
|
||||
*/
|
||||
|
@ -77,10 +77,8 @@ class BurningFurnace extends Solid{
|
||||
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
|
||||
}
|
||||
|
||||
if(isset($furnace->namedtag->Lock) and $furnace->namedtag->Lock instanceof StringTag){
|
||||
if($furnace->namedtag->Lock->getValue() !== $item->getCustomName()){
|
||||
return true;
|
||||
}
|
||||
if($furnace->namedtag->hasTag("Lock", StringTag::class) and $furnace->namedtag->getString("Lock") !== $item->getCustomName()){
|
||||
return true;
|
||||
}
|
||||
|
||||
$player->addWindow($furnace->getInventory());
|
||||
|
@ -126,7 +126,7 @@ class Chest extends Transparent{
|
||||
if(
|
||||
!$this->getSide(Vector3::SIDE_UP)->isTransparent() or
|
||||
($chest->isPaired() and !$chest->getPair()->getBlock()->getSide(Vector3::SIDE_UP)->isTransparent()) or
|
||||
(isset($chest->namedtag->Lock) and $chest->namedtag->Lock instanceof StringTag and $chest->namedtag->Lock->getValue() !== $item->getCustomName())
|
||||
($chest->namedtag->hasTag("Lock", StringTag::class) and $chest->namedtag->getString("Lock") !== $item->getCustomName())
|
||||
){
|
||||
return true;
|
||||
}
|
||||
|
@ -51,12 +51,10 @@ use pocketmine\math\Vector2;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\metadata\Metadatable;
|
||||
use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\DoubleTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\protocol\AddEntityPacket;
|
||||
use pocketmine\network\mcpe\protocol\EntityEventPacket;
|
||||
@ -504,53 +502,36 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
$this->server = $level->getServer();
|
||||
|
||||
$this->boundingBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0);
|
||||
$this->setPositionAndRotation(
|
||||
$this->temporalVector->setComponents(
|
||||
$this->namedtag["Pos"][0],
|
||||
$this->namedtag["Pos"][1],
|
||||
$this->namedtag["Pos"][2]
|
||||
),
|
||||
$this->namedtag->Rotation[0],
|
||||
$this->namedtag->Rotation[1]
|
||||
);
|
||||
|
||||
if(isset($this->namedtag->Motion)){
|
||||
$this->setMotion($this->temporalVector->setComponents($this->namedtag["Motion"][0], $this->namedtag["Motion"][1], $this->namedtag["Motion"][2]));
|
||||
}else{
|
||||
$this->setMotion($this->temporalVector->setComponents(0, 0, 0));
|
||||
/** @var float[] $pos */
|
||||
$pos = $this->namedtag->getListTag("Pos")->getAllValues();
|
||||
/** @var float[] $rotation */
|
||||
$rotation = $this->namedtag->getListTag("Rotation")->getAllValues();
|
||||
|
||||
$this->setPositionAndRotation($this->temporalVector->setComponents(...$pos), ...$rotation);
|
||||
|
||||
/** @var float[] $motion */
|
||||
$motion = [0, 0, 0];
|
||||
if($this->namedtag->hasTag("Motion", ListTag::class)){
|
||||
$motion = $this->namedtag->getListTag("Motion")->getAllValues();
|
||||
}
|
||||
|
||||
$this->setMotion($this->temporalVector->setComponents(...$motion));
|
||||
|
||||
$this->resetLastMovements();
|
||||
|
||||
assert(!is_nan($this->x) and !is_infinite($this->x) and !is_nan($this->y) and !is_infinite($this->y) and !is_nan($this->z) and !is_infinite($this->z));
|
||||
|
||||
if(!isset($this->namedtag->FallDistance)){
|
||||
$this->namedtag->FallDistance = new FloatTag("FallDistance", 0);
|
||||
}
|
||||
$this->fallDistance = $this->namedtag["FallDistance"];
|
||||
$this->fallDistance = $this->namedtag->getFloat("FallDistance", 0);
|
||||
|
||||
if(!isset($this->namedtag->Fire)){
|
||||
$this->namedtag->Fire = new ShortTag("Fire", 0);
|
||||
}
|
||||
$this->fireTicks = (int) $this->namedtag["Fire"];
|
||||
$this->fireTicks = $this->namedtag->getShort("Fire", 0);
|
||||
if($this->isOnFire()){
|
||||
$this->setGenericFlag(self::DATA_FLAG_ONFIRE);
|
||||
}
|
||||
|
||||
if(!isset($this->namedtag->Air)){
|
||||
$this->namedtag->Air = new ShortTag("Air", 300);
|
||||
}
|
||||
$this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, $this->namedtag["Air"], false);
|
||||
|
||||
if(!isset($this->namedtag->OnGround)){
|
||||
$this->namedtag->OnGround = new ByteTag("OnGround", 0);
|
||||
}
|
||||
$this->onGround = $this->namedtag["OnGround"] !== 0;
|
||||
|
||||
if(!isset($this->namedtag->Invulnerable)){
|
||||
$this->namedtag->Invulnerable = new ByteTag("Invulnerable", 0);
|
||||
}
|
||||
$this->invulnerable = $this->namedtag["Invulnerable"] !== 0;
|
||||
$this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, $this->namedtag->getShort("Air", 300), false);
|
||||
$this->onGround = $this->namedtag->getByte("OnGround", 0) !== 0;
|
||||
$this->invulnerable = $this->namedtag->getByte("Invulnerable", 0) !== 0;
|
||||
|
||||
$this->attributeMap = new AttributeMap();
|
||||
$this->addAttributes();
|
||||
@ -816,49 +797,46 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
|
||||
public function saveNBT(){
|
||||
if(!($this instanceof Player)){
|
||||
$this->namedtag->id = new StringTag("id", $this->getSaveId());
|
||||
$this->namedtag->setString("id", $this->getSaveId(), true);
|
||||
|
||||
if($this->getNameTag() !== ""){
|
||||
$this->namedtag->CustomName = new StringTag("CustomName", $this->getNameTag());
|
||||
$this->namedtag->CustomNameVisible = new ByteTag("CustomNameVisible", $this->isNameTagVisible() ? 1 : 0);
|
||||
$this->namedtag->setString("CustomName", $this->getNameTag());
|
||||
$this->namedtag->setByte("CustomNameVisible", $this->isNameTagVisible() ? 1 : 0);
|
||||
}else{
|
||||
unset($this->namedtag->CustomName);
|
||||
unset($this->namedtag->CustomNameVisible);
|
||||
$this->namedtag->removeTag("CustomName", "CustomNameVisible");
|
||||
}
|
||||
}
|
||||
|
||||
$this->namedtag->Pos = new ListTag("Pos", [
|
||||
$this->namedtag->setTag(new ListTag("Pos", [
|
||||
new DoubleTag("", $this->x),
|
||||
new DoubleTag("", $this->y),
|
||||
new DoubleTag("", $this->z)
|
||||
]);
|
||||
]));
|
||||
|
||||
$this->namedtag->Motion = new ListTag("Motion", [
|
||||
$this->namedtag->setTag(new ListTag("Motion", [
|
||||
new DoubleTag("", $this->motionX),
|
||||
new DoubleTag("", $this->motionY),
|
||||
new DoubleTag("", $this->motionZ)
|
||||
]);
|
||||
]));
|
||||
|
||||
$this->namedtag->Rotation = new ListTag("Rotation", [
|
||||
$this->namedtag->setTag(new ListTag("Rotation", [
|
||||
new FloatTag("", $this->yaw),
|
||||
new FloatTag("", $this->pitch)
|
||||
]);
|
||||
]));
|
||||
|
||||
$this->namedtag->FallDistance = new FloatTag("FallDistance", $this->fallDistance);
|
||||
$this->namedtag->Fire = new ShortTag("Fire", $this->fireTicks);
|
||||
$this->namedtag->Air = new ShortTag("Air", $this->getDataProperty(self::DATA_AIR));
|
||||
$this->namedtag->OnGround = new ByteTag("OnGround", $this->onGround ? 1 : 0);
|
||||
$this->namedtag->Invulnerable = new ByteTag("Invulnerable", $this->invulnerable ? 1 : 0);
|
||||
$this->namedtag->setFloat("FallDistance", $this->fallDistance);
|
||||
$this->namedtag->setShort("Fire", $this->fireTicks);
|
||||
$this->namedtag->setShort("Air", $this->getDataProperty(self::DATA_AIR));
|
||||
$this->namedtag->setByte("OnGround", $this->onGround ? 1 : 0);
|
||||
$this->namedtag->setByte("Invulnerable", $this->invulnerable ? 1 : 0);
|
||||
}
|
||||
|
||||
protected function initEntity(){
|
||||
assert($this->namedtag instanceof CompoundTag);
|
||||
|
||||
if(isset($this->namedtag->CustomName)){
|
||||
$this->setNameTag($this->namedtag["CustomName"]);
|
||||
if(isset($this->namedtag->CustomNameVisible)){
|
||||
$this->setNameTagVisible($this->namedtag["CustomNameVisible"] > 0);
|
||||
}
|
||||
if($this->namedtag->hasTag("CustomName", StringTag::class)){
|
||||
$this->setNameTag($this->namedtag->getString("CustomName"));
|
||||
$this->setNameTagVisible($this->namedtag->getByte("CustomNameVisible", 1) !== 0);
|
||||
}
|
||||
|
||||
$this->scheduleUpdate();
|
||||
@ -1709,6 +1687,8 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
$radius = $this->width / 2;
|
||||
$this->boundingBox->setBounds($pos->x - $radius, $pos->y, $pos->z - $radius, $pos->x + $radius, $pos->y + $this->height, $pos->z + $radius);
|
||||
|
||||
$this->blocksAround = null;
|
||||
|
||||
$this->checkChunks();
|
||||
|
||||
return true;
|
||||
|
@ -53,17 +53,13 @@ class FallingSand extends Entity{
|
||||
parent::initEntity();
|
||||
|
||||
$blockId = 0;
|
||||
$damage = 0;
|
||||
|
||||
if(isset($this->namedtag->TileID)){
|
||||
$blockId = (int) $this->namedtag["TileID"];
|
||||
}elseif(isset($this->namedtag->Tile)){
|
||||
$blockId = (int) $this->namedtag["Tile"];
|
||||
$this->namedtag["TileID"] = new IntTag("TileID", $blockId);
|
||||
}
|
||||
|
||||
if(isset($this->namedtag->Data)){
|
||||
$damage = (int) $this->namedtag["Data"];
|
||||
//TODO: 1.8+ save format
|
||||
if($this->namedtag->hasTag("TileID", IntTag::class)){
|
||||
$blockId = $this->namedtag->getInt("TileID");
|
||||
}elseif($this->namedtag->hasTag("Tile", ByteTag::class)){
|
||||
$blockId = $this->namedtag->getByte("Tile");
|
||||
$this->namedtag->removeTag("Tile");
|
||||
}
|
||||
|
||||
if($blockId === 0){
|
||||
@ -71,6 +67,8 @@ class FallingSand extends Entity{
|
||||
return;
|
||||
}
|
||||
|
||||
$damage = $this->namedtag->getByte("Data", 0);
|
||||
|
||||
$this->block = BlockFactory::get($blockId, $damage);
|
||||
|
||||
$this->setDataProperty(self::DATA_VARIANT, self::DATA_TYPE_INT, $this->block->getId() | ($this->block->getDamage() << 8));
|
||||
@ -132,7 +130,7 @@ class FallingSand extends Entity{
|
||||
}
|
||||
|
||||
public function saveNBT(){
|
||||
$this->namedtag->TileID = new IntTag("TileID", $this->block->getId());
|
||||
$this->namedtag->Data = new ByteTag("Data", $this->block->getDamage());
|
||||
$this->namedtag->setInt("TileID", $this->block->getId(), true);
|
||||
$this->namedtag->setByte("Data", $this->block->getDamage());
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ use pocketmine\item\Item as ItemItem;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
@ -311,14 +310,15 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
* For Human entities which are not players, sets their properties such as nametag, skin and UUID from NBT.
|
||||
*/
|
||||
protected function initHumanData(){
|
||||
if(isset($this->namedtag->NameTag)){
|
||||
$this->setNameTag($this->namedtag["NameTag"]);
|
||||
if($this->namedtag->hasTag("NameTag", StringTag::class)){
|
||||
$this->setNameTag($this->namedtag->getString("NameTag"));
|
||||
}
|
||||
|
||||
if(isset($this->namedtag->Skin) and $this->namedtag->Skin instanceof CompoundTag){
|
||||
$skin = $this->namedtag->getCompoundTag("Skin");
|
||||
if($skin !== null){
|
||||
$this->setSkin(new Skin(
|
||||
$this->namedtag->Skin["Name"],
|
||||
$this->namedtag->Skin["Data"]
|
||||
$skin->getString("Name"),
|
||||
$skin->getString("Data")
|
||||
));
|
||||
}
|
||||
|
||||
@ -333,71 +333,39 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
$this->inventory = new PlayerInventory($this);
|
||||
$this->initHumanData();
|
||||
|
||||
if(isset($this->namedtag->Inventory) and $this->namedtag->Inventory instanceof ListTag){
|
||||
foreach($this->namedtag->Inventory as $i => $item){
|
||||
if($item["Slot"] >= 0 and $item["Slot"] < 9){ //Hotbar
|
||||
$inventoryTag = $this->namedtag->getListTag("Inventory");
|
||||
if($inventoryTag !== null){
|
||||
/** @var CompoundTag $item */
|
||||
foreach($inventoryTag as $i => $item){
|
||||
$slot = $item->getByte("Slot");
|
||||
if($slot >= 0 and $slot < 9){ //Hotbar
|
||||
//Old hotbar saving stuff, remove it (useless now)
|
||||
unset($this->namedtag->Inventory->{$i});
|
||||
}elseif($item["Slot"] >= 100 and $item["Slot"] < 104){ //Armor
|
||||
$this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, ItemItem::nbtDeserialize($item));
|
||||
unset($inventoryTag[$i]);
|
||||
}elseif($slot >= 100 and $slot < 104){ //Armor
|
||||
$this->inventory->setItem($this->inventory->getSize() + $slot - 100, ItemItem::nbtDeserialize($item));
|
||||
}else{
|
||||
$this->inventory->setItem($item["Slot"] - 9, ItemItem::nbtDeserialize($item));
|
||||
$this->inventory->setItem($slot - 9, ItemItem::nbtDeserialize($item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($this->namedtag->SelectedInventorySlot) and $this->namedtag->SelectedInventorySlot instanceof IntTag){
|
||||
$this->inventory->setHeldItemIndex($this->namedtag->SelectedInventorySlot->getValue(), false);
|
||||
}else{
|
||||
$this->inventory->setHeldItemIndex(0, false);
|
||||
}
|
||||
$this->inventory->setHeldItemIndex($this->namedtag->getInt("SelectedInventorySlot", 0), false);
|
||||
|
||||
parent::initEntity();
|
||||
|
||||
if(!isset($this->namedtag->foodLevel) or !($this->namedtag->foodLevel instanceof IntTag)){
|
||||
$this->namedtag->foodLevel = new IntTag("foodLevel", (int) $this->getFood());
|
||||
}else{
|
||||
$this->setFood((float) $this->namedtag["foodLevel"]);
|
||||
}
|
||||
$this->setFood((float) $this->namedtag->getInt("foodLevel", (int) $this->getFood(), true));
|
||||
$this->setExhaustion($this->namedtag->getFloat("foodExhaustionLevel", $this->getExhaustion(), true));
|
||||
$this->setSaturation($this->namedtag->getFloat("foodSaturationLevel", $this->getSaturation(), true));
|
||||
$this->foodTickTimer = $this->namedtag->getInt("foodTickTimer", $this->foodTickTimer, true);
|
||||
|
||||
if(!isset($this->namedtag->foodExhaustionLevel) or !($this->namedtag->foodExhaustionLevel instanceof FloatTag)){
|
||||
$this->namedtag->foodExhaustionLevel = new FloatTag("foodExhaustionLevel", $this->getExhaustion());
|
||||
}else{
|
||||
$this->setExhaustion((float) $this->namedtag["foodExhaustionLevel"]);
|
||||
}
|
||||
$this->setXpLevel($this->namedtag->getInt("XpLevel", $this->getXpLevel(), true));
|
||||
$this->setXpProgress($this->namedtag->getFloat("XpP", $this->getXpProgress(), true));
|
||||
$this->totalXp = $this->namedtag->getInt("XpTotal", $this->totalXp, true);
|
||||
|
||||
if(!isset($this->namedtag->foodSaturationLevel) or !($this->namedtag->foodSaturationLevel instanceof FloatTag)){
|
||||
$this->namedtag->foodSaturationLevel = new FloatTag("foodSaturationLevel", $this->getSaturation());
|
||||
if($this->namedtag->hasTag("XpSeed", IntTag::class)){
|
||||
$this->xpSeed = $this->namedtag->getInt("XpSeed");
|
||||
}else{
|
||||
$this->setSaturation((float) $this->namedtag["foodSaturationLevel"]);
|
||||
}
|
||||
|
||||
if(!isset($this->namedtag->foodTickTimer) or !($this->namedtag->foodTickTimer instanceof IntTag)){
|
||||
$this->namedtag->foodTickTimer = new IntTag("foodTickTimer", $this->foodTickTimer);
|
||||
}else{
|
||||
$this->foodTickTimer = $this->namedtag["foodTickTimer"];
|
||||
}
|
||||
|
||||
if(!isset($this->namedtag->XpLevel) or !($this->namedtag->XpLevel instanceof IntTag)){
|
||||
$this->namedtag->XpLevel = new IntTag("XpLevel", $this->getXpLevel());
|
||||
}else{
|
||||
$this->setXpLevel((int) $this->namedtag["XpLevel"]);
|
||||
}
|
||||
|
||||
if(!isset($this->namedtag->XpP) or !($this->namedtag->XpP instanceof FloatTag)){
|
||||
$this->namedtag->XpP = new FloatTag("XpP", $this->getXpProgress());
|
||||
}
|
||||
|
||||
if(!isset($this->namedtag->XpTotal) or !($this->namedtag->XpTotal instanceof IntTag)){
|
||||
$this->namedtag->XpTotal = new IntTag("XpTotal", $this->totalXp);
|
||||
}else{
|
||||
$this->totalXp = $this->namedtag["XpTotal"];
|
||||
}
|
||||
|
||||
if(!isset($this->namedtag->XpSeed) or !($this->namedtag->XpSeed instanceof IntTag)){
|
||||
$this->namedtag->XpSeed = new IntTag("XpSeed", $this->xpSeed ?? ($this->xpSeed = mt_rand(-0x80000000, 0x7fffffff)));
|
||||
}else{
|
||||
$this->xpSeed = $this->namedtag["XpSeed"];
|
||||
$this->xpSeed = random_int(INT32_MIN, INT32_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,19 +447,25 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
public function saveNBT(){
|
||||
parent::saveNBT();
|
||||
|
||||
$this->namedtag->foodLevel = new IntTag("foodLevel", (int) $this->getFood());
|
||||
$this->namedtag->foodExhaustionLevel = new FloatTag("foodExhaustionLevel", $this->getExhaustion());
|
||||
$this->namedtag->foodSaturationLevel = new FloatTag("foodSaturationLevel", $this->getSaturation());
|
||||
$this->namedtag->foodTickTimer = new IntTag("foodTickTimer", $this->foodTickTimer);
|
||||
$this->namedtag->setInt("foodLevel", (int) $this->getFood(), true);
|
||||
$this->namedtag->setFloat("foodExhaustionLevel", $this->getExhaustion(), true);
|
||||
$this->namedtag->setFloat("foodSaturationLevel", $this->getSaturation(), true);
|
||||
$this->namedtag->setInt("foodTickTimer", $this->foodTickTimer);
|
||||
|
||||
$this->namedtag->Inventory = new ListTag("Inventory", [], NBT::TAG_Compound);
|
||||
$this->namedtag->setInt("XpLevel", $this->getXpLevel());
|
||||
$this->namedtag->setFloat("XpP", $this->getXpProgress());
|
||||
$this->namedtag->setInt("XpTotal", $this->totalXp);
|
||||
$this->namedtag->setInt("XpSeed", $this->xpSeed);
|
||||
|
||||
$inventoryTag = new ListTag("Inventory", [], NBT::TAG_Compound);
|
||||
$this->namedtag->setTag($inventoryTag);
|
||||
if($this->inventory !== null){
|
||||
//Normal inventory
|
||||
$slotCount = $this->inventory->getSize() + $this->inventory->getHotbarSize();
|
||||
for($slot = $this->inventory->getHotbarSize(); $slot < $slotCount; ++$slot){
|
||||
$item = $this->inventory->getItem($slot - 9);
|
||||
if(!$item->isNull()){
|
||||
$this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot);
|
||||
$inventoryTag[$slot] = $item->nbtSerialize($slot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,19 +473,19 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
for($slot = 100; $slot < 104; ++$slot){
|
||||
$item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100);
|
||||
if(!$item->isNull()){
|
||||
$this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot);
|
||||
$inventoryTag[$slot] = $item->nbtSerialize($slot);
|
||||
}
|
||||
}
|
||||
|
||||
$this->namedtag->SelectedInventorySlot = new IntTag("SelectedInventorySlot", $this->inventory->getHeldItemIndex());
|
||||
$this->namedtag->setInt("SelectedInventorySlot", $this->inventory->getHeldItemIndex());
|
||||
}
|
||||
|
||||
if($this->skin !== null){
|
||||
$this->namedtag->Skin = new CompoundTag("Skin", [
|
||||
$this->namedtag->setTag(new CompoundTag("Skin", [
|
||||
//TODO: save cape & geometry
|
||||
new StringTag("Data", $this->skin->getSkinData()),
|
||||
new StringTag("Name", $this->skin->getSkinId())
|
||||
]);
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,9 +27,6 @@ use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\ItemDespawnEvent;
|
||||
use pocketmine\event\entity\ItemSpawnEvent;
|
||||
use pocketmine\item\Item as ItemItem;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\protocol\AddItemEntityPacket;
|
||||
use pocketmine\Player;
|
||||
|
||||
@ -59,28 +56,19 @@ class Item extends Entity{
|
||||
|
||||
$this->setMaxHealth(5);
|
||||
$this->setHealth((int) $this->namedtag["Health"]);
|
||||
if(isset($this->namedtag->Age)){
|
||||
$this->age = $this->namedtag["Age"];
|
||||
}
|
||||
if(isset($this->namedtag->PickupDelay)){
|
||||
$this->pickupDelay = $this->namedtag["PickupDelay"];
|
||||
}
|
||||
if(isset($this->namedtag->Owner)){
|
||||
$this->owner = $this->namedtag["Owner"];
|
||||
}
|
||||
if(isset($this->namedtag->Thrower)){
|
||||
$this->thrower = $this->namedtag["Thrower"];
|
||||
}
|
||||
$this->age = $this->namedtag->getShort("Age", $this->age);
|
||||
$this->pickupDelay = $this->namedtag->getShort("PickupDelay", $this->pickupDelay);
|
||||
$this->owner = $this->namedtag->getString("Owner", $this->owner);
|
||||
$this->thrower = $this->namedtag->getString("Thrower", $this->thrower);
|
||||
|
||||
|
||||
if(!isset($this->namedtag->Item)){
|
||||
$itemTag = $this->namedtag->getCompoundTag("Item");
|
||||
if($itemTag === null){
|
||||
$this->close();
|
||||
return;
|
||||
}
|
||||
|
||||
assert($this->namedtag->Item instanceof CompoundTag);
|
||||
|
||||
$this->item = ItemItem::nbtDeserialize($this->namedtag->Item);
|
||||
$this->item = ItemItem::nbtDeserialize($itemTag);
|
||||
|
||||
|
||||
$this->server->getPluginManager()->callEvent(new ItemSpawnEvent($this));
|
||||
@ -139,15 +127,15 @@ class Item extends Entity{
|
||||
|
||||
public function saveNBT(){
|
||||
parent::saveNBT();
|
||||
$this->namedtag->Item = $this->item->nbtSerialize(-1, "Item");
|
||||
$this->namedtag->Health = new ShortTag("Health", (int) $this->getHealth());
|
||||
$this->namedtag->Age = new ShortTag("Age", $this->age);
|
||||
$this->namedtag->PickupDelay = new ShortTag("PickupDelay", $this->pickupDelay);
|
||||
$this->namedtag->setTag($this->item->nbtSerialize(-1, "Item"));
|
||||
$this->namedtag->setShort("Health", (int) $this->getHealth());
|
||||
$this->namedtag->setShort("Age", $this->age);
|
||||
$this->namedtag->setShort("PickupDelay", $this->pickupDelay);
|
||||
if($this->owner !== null){
|
||||
$this->namedtag->Owner = new StringTag("Owner", $this->owner);
|
||||
$this->namedtag->setString("Owner", $this->owner);
|
||||
}
|
||||
if($this->thrower !== null){
|
||||
$this->namedtag->Thrower = new StringTag("Thrower", $this->thrower);
|
||||
$this->namedtag->setString("Thrower", $this->thrower);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,29 +65,33 @@ abstract class Living extends Entity implements Damageable{
|
||||
protected function initEntity(){
|
||||
parent::initEntity();
|
||||
|
||||
if(isset($this->namedtag->HealF)){
|
||||
$this->namedtag->Health = new FloatTag("Health", (float) $this->namedtag["HealF"]);
|
||||
unset($this->namedtag->HealF);
|
||||
}elseif(isset($this->namedtag->Health)){
|
||||
if(!($this->namedtag->Health instanceof FloatTag)){
|
||||
$this->namedtag->Health = new FloatTag("Health", (float) $this->namedtag->Health->getValue());
|
||||
$health = $this->getMaxHealth();
|
||||
|
||||
if($this->namedtag->hasTag("HealF", FloatTag::class)){
|
||||
$health = new FloatTag("Health", (float) $this->namedtag["HealF"]);
|
||||
$this->namedtag->removeTag("HealF");
|
||||
}elseif($this->namedtag->hasTag("Health")){
|
||||
$healthTag = $this->namedtag->getTag("Health");
|
||||
$health = (float) $healthTag->getValue(); //Older versions of PocketMine-MP incorrectly saved this as a short instead of a float
|
||||
if(!($healthTag instanceof FloatTag)){
|
||||
$this->namedtag->removeTag("Health");
|
||||
}
|
||||
}else{
|
||||
$this->namedtag->Health = new FloatTag("Health", (float) $this->getMaxHealth());
|
||||
}
|
||||
|
||||
$this->setHealth((float) $this->namedtag["Health"]);
|
||||
$this->setHealth($health);
|
||||
|
||||
if(isset($this->namedtag->ActiveEffects)){
|
||||
foreach($this->namedtag->ActiveEffects->getValue() as $e){
|
||||
$amplifier = Binary::unsignByte($e->Amplifier->getValue()); //0-255 only
|
||||
/** @var CompoundTag[]|ListTag $activeEffectsTag */
|
||||
$activeEffectsTag = $this->namedtag->getListTag("ActiveEffects");
|
||||
if($activeEffectsTag !== null){
|
||||
foreach($activeEffectsTag as $e){
|
||||
$amplifier = Binary::unsignByte($e->getByte("Amplifier")); //0-255 only
|
||||
|
||||
$effect = Effect::getEffect($e["Id"]);
|
||||
$effect = Effect::getEffect($e->getByte("Id"));
|
||||
if($effect === null){
|
||||
continue;
|
||||
}
|
||||
|
||||
$effect->setAmplifier($amplifier)->setDuration($e["Duration"])->setVisible($e["ShowParticles"] > 0);
|
||||
$effect->setAmplifier($amplifier)->setDuration($e->getInt("Duration"))->setVisible($e->getByte("ShowParticles", 1) > 0);
|
||||
|
||||
$this->addEffect($effect);
|
||||
}
|
||||
@ -130,7 +134,7 @@ abstract class Living extends Entity implements Damageable{
|
||||
|
||||
public function saveNBT(){
|
||||
parent::saveNBT();
|
||||
$this->namedtag->Health = new FloatTag("Health", $this->getHealth());
|
||||
$this->namedtag->setFloat("Health", $this->getHealth(), true);
|
||||
|
||||
if(count($this->effects) > 0){
|
||||
$effects = [];
|
||||
@ -144,9 +148,9 @@ abstract class Living extends Entity implements Damageable{
|
||||
]);
|
||||
}
|
||||
|
||||
$this->namedtag->ActiveEffects = new ListTag("ActiveEffects", $effects);
|
||||
$this->namedtag->setTag(new ListTag("ActiveEffects", $effects));
|
||||
}else{
|
||||
unset($this->namedtag->ActiveEffects);
|
||||
$this->namedtag->removeTag("ActiveEffects");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ namespace pocketmine\entity;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\ExplosionPrimeEvent;
|
||||
use pocketmine\level\Explosion;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||
|
||||
class PrimedTNT extends Entity implements Explosive{
|
||||
@ -54,8 +54,8 @@ class PrimedTNT extends Entity implements Explosive{
|
||||
protected function initEntity(){
|
||||
parent::initEntity();
|
||||
|
||||
if(isset($this->namedtag->Fuse)){
|
||||
$this->fuse = $this->namedtag["Fuse"];
|
||||
if($this->namedtag->hasTag("Fuse", ShortTag::class)){
|
||||
$this->fuse = $this->namedtag->getShort("Fuse");
|
||||
}else{
|
||||
$this->fuse = 80;
|
||||
}
|
||||
@ -73,7 +73,7 @@ class PrimedTNT extends Entity implements Explosive{
|
||||
|
||||
public function saveNBT(){
|
||||
parent::saveNBT();
|
||||
$this->namedtag->Fuse = new ByteTag("Fuse", $this->fuse);
|
||||
$this->namedtag->setShort("Fuse", $this->fuse, true); //older versions incorrectly saved this as a byte
|
||||
}
|
||||
|
||||
public function entityBaseTick(int $tickDiff = 1) : bool{
|
||||
|
@ -23,8 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\entity;
|
||||
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
|
||||
class Villager extends Creature implements NPC, Ageable{
|
||||
const PROFESSION_FARMER = 0;
|
||||
const PROFESSION_LIBRARIAN = 1;
|
||||
@ -45,7 +43,7 @@ class Villager extends Creature implements NPC, Ageable{
|
||||
parent::initEntity();
|
||||
|
||||
/** @var int $profession */
|
||||
$profession = $this->namedtag["Profession"] ?? self::PROFESSION_FARMER;
|
||||
$profession = $this->namedtag->getInt("Profession", self::PROFESSION_FARMER);
|
||||
|
||||
if($profession > 4 or $profession < 0){
|
||||
$profession = self::PROFESSION_FARMER;
|
||||
@ -56,7 +54,7 @@ class Villager extends Creature implements NPC, Ageable{
|
||||
|
||||
public function saveNBT(){
|
||||
parent::saveNBT();
|
||||
$this->namedtag->Profession = new IntTag("Profession", $this->getProfession());
|
||||
$this->namedtag->setInt("Profession", $this->getProfession());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,7 +34,6 @@ use pocketmine\level\Level;
|
||||
use pocketmine\level\MovingObjectPosition;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
|
||||
abstract class Projectile extends Entity{
|
||||
|
||||
@ -62,9 +61,7 @@ abstract class Projectile extends Entity{
|
||||
|
||||
$this->setMaxHealth(1);
|
||||
$this->setHealth(1);
|
||||
if(isset($this->namedtag->Age)){
|
||||
$this->age = $this->namedtag["Age"];
|
||||
}
|
||||
$this->age = $this->namedtag->getShort("Age", $this->age);
|
||||
}
|
||||
|
||||
public function canCollideWith(Entity $entity) : bool{
|
||||
@ -107,7 +104,7 @@ abstract class Projectile extends Entity{
|
||||
|
||||
public function saveNBT(){
|
||||
parent::saveNBT();
|
||||
$this->namedtag->Age = new ShortTag("Age", $this->age);
|
||||
$this->namedtag->setShort("Age", $this->age);
|
||||
}
|
||||
|
||||
protected function applyDragBeforeGravity() : bool{
|
||||
|
@ -481,9 +481,7 @@ class Item implements ItemIds, \JsonSerializable{
|
||||
public function getLore() : array{
|
||||
$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
|
||||
if($display instanceof CompoundTag and ($lore = $display->getListTag(self::TAG_DISPLAY_LORE)) !== null){
|
||||
return array_map(function(StringTag $tag) : string{
|
||||
return $tag->getValue();
|
||||
}, $lore->getValue());
|
||||
return $lore->getAllValues();
|
||||
}
|
||||
|
||||
return [];
|
||||
|
@ -23,12 +23,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
|
||||
class WritableBook extends Item{
|
||||
|
||||
const TAG_PAGES = "pages"; //TAG_List<TAG_Compound>
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
parent::__construct(self::WRITABLE_BOOK, $meta, "Book & Quill");
|
||||
}
|
||||
@ -41,7 +44,8 @@ class WritableBook extends Item{
|
||||
* @return bool
|
||||
*/
|
||||
public function pageExists(int $pageId) : bool{
|
||||
return isset($this->getNamedTag()->pages->{$pageId});
|
||||
$pages = $this->getNamedTag()->getListTag(self::TAG_PAGES);
|
||||
return $pages !== null and isset($pages[$pageId]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,10 +56,17 @@ class WritableBook extends Item{
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPageText(int $pageId) : ?string{
|
||||
if(!$this->pageExists($pageId)){
|
||||
$pages = $this->getNamedTag()->getListTag(self::TAG_PAGES);
|
||||
if($pages === null){
|
||||
return null;
|
||||
}
|
||||
return $this->getNamedTag()->pages->{$pageId}->text->getValue();
|
||||
|
||||
$page = $pages[$pageId] ?? null;
|
||||
if($page instanceof CompoundTag){
|
||||
return $page->getString("text", "");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,7 +85,11 @@ class WritableBook extends Item{
|
||||
}
|
||||
|
||||
$namedTag = $this->getNamedTag();
|
||||
$namedTag->pages->{$pageId}->text->setValue($pageText);
|
||||
/** @var CompoundTag[]|ListTag $pages */
|
||||
$pages = $namedTag->getListTag(self::TAG_PAGES);
|
||||
assert($pages instanceof ListTag);
|
||||
$pages[$pageId]->setString("text", $pageText);
|
||||
|
||||
$this->setNamedTag($namedTag);
|
||||
|
||||
return $created;
|
||||
@ -92,19 +107,19 @@ class WritableBook extends Item{
|
||||
}
|
||||
$namedTag = $this->getNamedTag();
|
||||
|
||||
if(!isset($namedTag->pages) or !($namedTag->pages instanceof ListTag)){
|
||||
$namedTag->pages = new ListTag("pages", []);
|
||||
}
|
||||
/** @var CompoundTag[]|ListTag $pages */
|
||||
$pages = $namedTag->getListTag(self::TAG_PAGES) ?? new ListTag(self::TAG_PAGES, [], NBT::TAG_Compound);
|
||||
|
||||
for($id = 0; $id <= $pageId; $id++){
|
||||
if(!$this->pageExists($id)){
|
||||
$namedTag->pages->{$id} = new CompoundTag("", [
|
||||
$pages[$id] = new CompoundTag("", [
|
||||
new StringTag("text", ""),
|
||||
new StringTag("photoname", "")
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$namedTag->setTag($pages);
|
||||
$this->setNamedTag($namedTag);
|
||||
}
|
||||
|
||||
@ -121,7 +136,7 @@ class WritableBook extends Item{
|
||||
}
|
||||
|
||||
$namedTag = $this->getNamedTag();
|
||||
unset($namedTag->pages->{$pageId});
|
||||
unset($namedTag->getListTag(self::TAG_PAGES)[$pageId]);
|
||||
$this->pushPages($pageId, $namedTag);
|
||||
$this->setNamedTag($namedTag);
|
||||
|
||||
@ -186,6 +201,9 @@ class WritableBook extends Item{
|
||||
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)){
|
||||
@ -193,9 +211,9 @@ class WritableBook extends Item{
|
||||
}
|
||||
|
||||
if($downwards){
|
||||
unset($namedTag->pages->{$key});
|
||||
unset($pagesTag[$key]);
|
||||
}
|
||||
$namedTag->pages->{$key + $type} = new CompoundTag("", [
|
||||
$pagesTag[$key + $type] = new CompoundTag("", [
|
||||
new StringTag("text", $page->text->getValue()),
|
||||
new StringTag("photoname", "")
|
||||
]);
|
||||
|
@ -23,9 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
|
||||
class WrittenBook extends WritableBook{
|
||||
|
||||
const GENERATION_ORIGINAL = 0;
|
||||
@ -33,6 +30,10 @@ class WrittenBook extends WritableBook{
|
||||
const GENERATION_COPY_OF_COPY = 2;
|
||||
const GENERATION_TATTERED = 3;
|
||||
|
||||
const TAG_GENERATION = "generation"; //TAG_Int
|
||||
const TAG_AUTHOR = "author"; //TAG_String
|
||||
const TAG_TITLE = "title"; //TAG_String
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
Item::__construct(self::WRITTEN_BOOK, $meta, "Written Book");
|
||||
}
|
||||
@ -48,10 +49,7 @@ class WrittenBook extends WritableBook{
|
||||
* @return int
|
||||
*/
|
||||
public function getGeneration() : int{
|
||||
if(!isset($this->getNamedTag()->generation)) {
|
||||
return -1;
|
||||
}
|
||||
return $this->getNamedTag()->generation->getValue();
|
||||
return $this->getNamedTag()->getInt(self::TAG_GENERATION, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,12 +62,7 @@ class WrittenBook extends WritableBook{
|
||||
throw new \InvalidArgumentException("Generation \"$generation\" is out of range");
|
||||
}
|
||||
$namedTag = $this->getNamedTag();
|
||||
|
||||
if(isset($namedTag->generation)){
|
||||
$namedTag->generation->setValue($generation);
|
||||
}else{
|
||||
$namedTag->generation = new IntTag("generation", $generation);
|
||||
}
|
||||
$namedTag->setInt(self::TAG_GENERATION, $generation);
|
||||
$this->setNamedTag($namedTag);
|
||||
}
|
||||
|
||||
@ -81,10 +74,7 @@ class WrittenBook extends WritableBook{
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthor() : string{
|
||||
if(!isset($this->getNamedTag()->author)){
|
||||
return "";
|
||||
}
|
||||
return $this->getNamedTag()->author->getValue();
|
||||
return $this->getNamedTag()->getString(self::TAG_AUTHOR, "");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,11 +84,7 @@ class WrittenBook extends WritableBook{
|
||||
*/
|
||||
public function setAuthor(string $authorName) : void{
|
||||
$namedTag = $this->getNamedTag();
|
||||
if(isset($namedTag->author)){
|
||||
$namedTag->author->setValue($authorName);
|
||||
}else{
|
||||
$namedTag->author = new StringTag("author", $authorName);
|
||||
}
|
||||
$namedTag->setString(self::TAG_AUTHOR, $authorName);
|
||||
$this->setNamedTag($namedTag);
|
||||
}
|
||||
|
||||
@ -108,10 +94,7 @@ class WrittenBook extends WritableBook{
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle() : string{
|
||||
if(!isset($this->getNamedTag()->title)){
|
||||
return "";
|
||||
}
|
||||
return $this->getNamedTag()->title->getValue();
|
||||
return $this->getNamedTag()->getString(self::TAG_TITLE, "");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -121,11 +104,7 @@ class WrittenBook extends WritableBook{
|
||||
*/
|
||||
public function setTitle(string $title) : void{
|
||||
$namedTag = $this->getNamedTag();
|
||||
if(isset($namedTag->title)){
|
||||
$namedTag->title->setValue($title);
|
||||
}else{
|
||||
$namedTag->title = new StringTag("title", $title);
|
||||
}
|
||||
$namedTag->setString(self::TAG_TITLE, $title);
|
||||
$this->setNamedTag($namedTag);
|
||||
}
|
||||
}
|
@ -31,8 +31,6 @@ use pocketmine\level\LevelException;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\LongTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
|
||||
@ -52,19 +50,19 @@ abstract class BaseLevelProvider implements LevelProvider{
|
||||
}
|
||||
$nbt = new NBT(NBT::BIG_ENDIAN);
|
||||
$nbt->readCompressed(file_get_contents($this->getPath() . "level.dat"));
|
||||
$levelData = $nbt->getData();
|
||||
if($levelData->Data instanceof CompoundTag){
|
||||
$this->levelData = $levelData->Data;
|
||||
$levelData = $nbt->getData()->getCompoundTag("Data");
|
||||
if($levelData !== null){
|
||||
$this->levelData = $levelData;
|
||||
}else{
|
||||
throw new LevelException("Invalid level.dat");
|
||||
}
|
||||
|
||||
if(!isset($this->levelData->generatorName)){
|
||||
$this->levelData->generatorName = new StringTag("generatorName", (string) Generator::getGenerator("DEFAULT"));
|
||||
if(!$this->levelData->hasTag("generatorName", StringTag::class)){
|
||||
$this->levelData->setString("generatorName", (string) Generator::getGenerator("DEFAULT"), true);
|
||||
}
|
||||
|
||||
if(!isset($this->levelData->generatorOptions)){
|
||||
$this->levelData->generatorOptions = new StringTag("generatorOptions", "");
|
||||
if(!$this->levelData->hasTag("generatorOptions", StringTag::class)){
|
||||
$this->levelData->setString("generatorOptions", "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,33 +79,33 @@ abstract class BaseLevelProvider implements LevelProvider{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return (string) $this->levelData["LevelName"];
|
||||
return $this->levelData->getString("LevelName");
|
||||
}
|
||||
|
||||
public function getTime() : int{
|
||||
return $this->levelData["Time"];
|
||||
return $this->levelData->getLong("Time", 0, true);
|
||||
}
|
||||
|
||||
public function setTime(int $value){
|
||||
$this->levelData->Time = new LongTag("Time", $value);
|
||||
$this->levelData->setLong("Time", $value, true); //some older PM worlds had this in the wrong format
|
||||
}
|
||||
|
||||
public function getSeed() : int{
|
||||
return $this->levelData["RandomSeed"];
|
||||
return $this->levelData->getLong("RandomSeed");
|
||||
}
|
||||
|
||||
public function setSeed(int $value){
|
||||
$this->levelData->RandomSeed = new LongTag("RandomSeed", $value);
|
||||
$this->levelData->setLong("RandomSeed", $value);
|
||||
}
|
||||
|
||||
public function getSpawn() : Vector3{
|
||||
return new Vector3((float) $this->levelData["SpawnX"], (float) $this->levelData["SpawnY"], (float) $this->levelData["SpawnZ"]);
|
||||
return new Vector3($this->levelData->getInt("SpawnX"), $this->levelData->getInt("SpawnY"), $this->levelData->getInt("SpawnZ"));
|
||||
}
|
||||
|
||||
public function setSpawn(Vector3 $pos){
|
||||
$this->levelData->SpawnX = new IntTag("SpawnX", (int) $pos->x);
|
||||
$this->levelData->SpawnY = new IntTag("SpawnY", (int) $pos->y);
|
||||
$this->levelData->SpawnZ = new IntTag("SpawnZ", (int) $pos->z);
|
||||
$this->levelData->setInt("SpawnX", (int) $pos->x);
|
||||
$this->levelData->setInt("SpawnY", (int) $pos->y);
|
||||
$this->levelData->setInt("SpawnZ", (int) $pos->z);
|
||||
}
|
||||
|
||||
public function doGarbageCollection(){
|
||||
|
@ -96,26 +96,26 @@ class LevelDB extends BaseLevelProvider{
|
||||
"compression" => LEVELDB_ZLIB_COMPRESSION
|
||||
]);
|
||||
|
||||
if(isset($this->levelData->StorageVersion) and $this->levelData->StorageVersion->getValue() > self::CURRENT_STORAGE_VERSION){
|
||||
throw new LevelException("Specified LevelDB world format version is newer than the version supported by the server");
|
||||
if($this->levelData->getInt("StorageVersion", INT32_MAX, true) > self::CURRENT_STORAGE_VERSION){
|
||||
throw new LevelException("Specified LevelDB world format version is not supported by " . \pocketmine\NAME);
|
||||
}
|
||||
|
||||
if(!isset($this->levelData->generatorName)){
|
||||
if(isset($this->levelData->Generator)){
|
||||
switch((int) $this->levelData->Generator->getValue()){ //Detect correct generator from MCPE data
|
||||
if(!$this->levelData->hasTag("generatorName", StringTag::class)){
|
||||
if($this->levelData->hasTag("Generator", IntTag::class)){
|
||||
switch($this->levelData->getInt("Generator")){ //Detect correct generator from MCPE data
|
||||
case self::GENERATOR_FLAT:
|
||||
$this->levelData->generatorName = new StringTag("generatorName", (string) Generator::getGenerator("FLAT"));
|
||||
$this->levelData->setString("generatorName", (string) Generator::getGenerator("FLAT"));
|
||||
if(($layers = $this->db->get(self::ENTRY_FLAT_WORLD_LAYERS)) !== false){ //Detect existing custom flat layers
|
||||
$layers = trim($layers, "[]");
|
||||
}else{
|
||||
$layers = "7,3,3,2";
|
||||
}
|
||||
$this->levelData->generatorOptions = new StringTag("generatorOptions", "2;" . $layers . ";1");
|
||||
$this->levelData->setString("generatorOptions", "2;" . $layers . ";1");
|
||||
break;
|
||||
case self::GENERATOR_INFINITE:
|
||||
//TODO: add a null generator which does not generate missing chunks (to allow importing back to MCPE and generating more normal terrain without PocketMine messing things up)
|
||||
$this->levelData->generatorName = new StringTag("generatorName", (string) Generator::getGenerator("DEFAULT"));
|
||||
$this->levelData->generatorOptions = new StringTag("generatorOptions", "");
|
||||
$this->levelData->setString("generatorName", (string) Generator::getGenerator("DEFAULT"));
|
||||
$this->levelData->setString("generatorOptions", "");
|
||||
break;
|
||||
case self::GENERATOR_LIMITED:
|
||||
throw new LevelException("Limited worlds are not currently supported");
|
||||
@ -123,12 +123,12 @@ class LevelDB extends BaseLevelProvider{
|
||||
throw new LevelException("Unknown LevelDB world format type, this level cannot be loaded");
|
||||
}
|
||||
}else{
|
||||
$this->levelData->generatorName = new StringTag("generatorName", (string) Generator::getGenerator("DEFAULT"));
|
||||
$this->levelData->setString("generatorName", (string) Generator::getGenerator("DEFAULT"));
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($this->levelData->generatorOptions)){
|
||||
$this->levelData->generatorOptions = new StringTag("generatorOptions", "");
|
||||
if(!$this->levelData->hasTag("generatorOptions", StringTag::class)){
|
||||
$this->levelData->setString("generatorOptions", "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,8 +226,8 @@ class LevelDB extends BaseLevelProvider{
|
||||
}
|
||||
|
||||
public function saveLevelData(){
|
||||
$this->levelData->NetworkVersion = new IntTag("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL);
|
||||
$this->levelData->StorageVersion = new IntTag("StorageVersion", self::CURRENT_STORAGE_VERSION);
|
||||
$this->levelData->setInt("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL);
|
||||
$this->levelData->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION);
|
||||
|
||||
$nbt = new NBT(NBT::LITTLE_ENDIAN);
|
||||
$nbt->setData($this->levelData);
|
||||
@ -251,11 +251,11 @@ class LevelDB extends BaseLevelProvider{
|
||||
}
|
||||
|
||||
public function getDifficulty() : int{
|
||||
return isset($this->levelData->Difficulty) ? $this->levelData->Difficulty->getValue() : Level::DIFFICULTY_NORMAL;
|
||||
return $this->levelData->getInt("Difficulty", Level::DIFFICULTY_NORMAL);
|
||||
}
|
||||
|
||||
public function setDifficulty(int $difficulty){
|
||||
$this->levelData->Difficulty = new IntTag("Difficulty", $difficulty);
|
||||
$this->levelData->setInt("Difficulty", $difficulty); //yes, this is intended! (in PE: int, PC: byte)
|
||||
}
|
||||
|
||||
public function getLoadedChunks() : array{
|
||||
|
@ -28,9 +28,10 @@ use pocketmine\level\format\ChunkException;
|
||||
use pocketmine\level\format\io\ChunkUtils;
|
||||
use pocketmine\level\format\SubChunk;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\{
|
||||
ByteArrayTag, ByteTag, CompoundTag, IntArrayTag, IntTag, ListTag, LongTag
|
||||
};
|
||||
use pocketmine\nbt\tag\ByteArrayTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntArrayTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\utils\MainLogger;
|
||||
|
||||
class Anvil extends McRegion{
|
||||
@ -39,28 +40,29 @@ class Anvil extends McRegion{
|
||||
|
||||
public function nbtSerialize(Chunk $chunk) : string{
|
||||
$nbt = new CompoundTag("Level", []);
|
||||
$nbt->xPos = new IntTag("xPos", $chunk->getX());
|
||||
$nbt->zPos = new IntTag("zPos", $chunk->getZ());
|
||||
$nbt->setInt("xPos", $chunk->getX());
|
||||
$nbt->setInt("zPos", $chunk->getZ());
|
||||
|
||||
$nbt->V = new ByteTag("V", 1);
|
||||
$nbt->LastUpdate = new LongTag("LastUpdate", 0); //TODO
|
||||
$nbt->InhabitedTime = new LongTag("InhabitedTime", 0); //TODO
|
||||
$nbt->TerrainPopulated = new ByteTag("TerrainPopulated", $chunk->isPopulated() ? 1 : 0);
|
||||
$nbt->LightPopulated = new ByteTag("LightPopulated", $chunk->isLightPopulated() ? 1 : 0);
|
||||
$nbt->setByte("V", 1);
|
||||
$nbt->setLong("LastUpdate", 0); //TODO
|
||||
$nbt->setLong("InhabitedTime", 0); //TODO
|
||||
$nbt->setByte("TerrainPopulated", $chunk->isPopulated() ? 1 : 0);
|
||||
$nbt->setByte("LightPopulated", $chunk->isLightPopulated() ? 1 : 0);
|
||||
|
||||
$nbt->Sections = new ListTag("Sections", [], NBT::TAG_Compound);
|
||||
$subChunks = -1;
|
||||
$subChunks = [];
|
||||
foreach($chunk->getSubChunks() as $y => $subChunk){
|
||||
if($subChunk->isEmpty()){
|
||||
continue;
|
||||
}
|
||||
|
||||
$tag = $this->serializeSubChunk($subChunk);
|
||||
$tag->setByte("Y", $y);
|
||||
$nbt->Sections[++$subChunks] = $tag;
|
||||
$subChunks[] = $tag;
|
||||
}
|
||||
$nbt->setTag(new ListTag("Sections", $subChunks, NBT::TAG_Compound));
|
||||
|
||||
$nbt->Biomes = new ByteArrayTag("Biomes", $chunk->getBiomeIdArray());
|
||||
$nbt->HeightMap = new IntArrayTag("HeightMap", $chunk->getHeightMapArray());
|
||||
$nbt->setByteArray("Biomes", $chunk->getBiomeIdArray());
|
||||
$nbt->setIntArray("HeightMap", $chunk->getHeightMapArray());
|
||||
|
||||
$entities = [];
|
||||
|
||||
@ -71,7 +73,7 @@ class Anvil extends McRegion{
|
||||
}
|
||||
}
|
||||
|
||||
$nbt->Entities = new ListTag("Entities", $entities, NBT::TAG_Compound);
|
||||
$nbt->setTag(new ListTag("Entities", $entities, NBT::TAG_Compound));
|
||||
|
||||
$tiles = [];
|
||||
foreach($chunk->getTiles() as $tile){
|
||||
@ -79,7 +81,7 @@ class Anvil extends McRegion{
|
||||
$tiles[] = $tile->namedtag;
|
||||
}
|
||||
|
||||
$nbt->TileEntities = new ListTag("TileEntities", $tiles, NBT::TAG_Compound);
|
||||
$nbt->setTag(new ListTag("TileEntities", $tiles, NBT::TAG_Compound));
|
||||
|
||||
//TODO: TileTicks
|
||||
|
||||
@ -104,43 +106,38 @@ class Anvil extends McRegion{
|
||||
try{
|
||||
$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");
|
||||
}
|
||||
|
||||
$chunk = $chunk->Level;
|
||||
|
||||
$subChunks = [];
|
||||
if($chunk->Sections instanceof ListTag){
|
||||
foreach($chunk->Sections as $subChunk){
|
||||
if($subChunk instanceof CompoundTag){
|
||||
$subChunks[$subChunk->Y->getValue()] = $this->deserializeSubChunk($subChunk);
|
||||
}
|
||||
$subChunksTag = $chunk->getListTag("Sections") ?? [];
|
||||
foreach($subChunksTag as $subChunk){
|
||||
if($subChunk instanceof CompoundTag){
|
||||
$subChunks[$subChunk->getByte("Y")] = $this->deserializeSubChunk($subChunk);
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($chunk->BiomeColors)){
|
||||
$biomeIds = ChunkUtils::convertBiomeColors($chunk->BiomeColors->getValue()); //Convert back to original format
|
||||
}elseif(isset($chunk->Biomes)){
|
||||
$biomeIds = $chunk->Biomes->getValue();
|
||||
if($chunk->hasTag("BiomeColors", IntArrayTag::class)){
|
||||
$biomeIds = ChunkUtils::convertBiomeColors($chunk->getIntArray("BiomeColors")); //Convert back to original format
|
||||
}else{
|
||||
$biomeIds = "";
|
||||
$biomeIds = $chunk->getByteArray("Biomes", "", true);
|
||||
}
|
||||
|
||||
$result = new Chunk(
|
||||
$chunk["xPos"],
|
||||
$chunk["zPos"],
|
||||
$chunk->getInt("xPos"),
|
||||
$chunk->getInt("zPos"),
|
||||
$subChunks,
|
||||
isset($chunk->Entities) ? $chunk->Entities->getValue() : [],
|
||||
isset($chunk->TileEntities) ? $chunk->TileEntities->getValue() : [],
|
||||
$chunk->hasTag("Entities", ListTag::class) ? $chunk->getListTag("Entities")->getValue() : [],
|
||||
$chunk->hasTag("TileEntities", ListTag::class) ? $chunk->getListTag("TileEntities")->getValue() : [],
|
||||
$biomeIds,
|
||||
isset($chunk->HeightMap) ? $chunk->HeightMap->getValue() : []
|
||||
$chunk->getIntArray("HeightMap", [])
|
||||
);
|
||||
$result->setLightPopulated(isset($chunk->LightPopulated) ? ((bool) $chunk->LightPopulated->getValue()) : false);
|
||||
$result->setPopulated(isset($chunk->TerrainPopulated) ? ((bool) $chunk->TerrainPopulated->getValue()) : false);
|
||||
$result->setGenerated(true);
|
||||
$result->setLightPopulated($chunk->getByte("LightPopulated", 0) !== 0);
|
||||
$result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0);
|
||||
$result->setGenerated();
|
||||
return $result;
|
||||
}catch(\Throwable $e){
|
||||
MainLogger::getLogger()->logException($e);
|
||||
@ -150,10 +147,10 @@ class Anvil extends McRegion{
|
||||
|
||||
protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
|
||||
return new SubChunk(
|
||||
ChunkUtils::reorderByteArray($subChunk->Blocks->getValue()),
|
||||
ChunkUtils::reorderNibbleArray($subChunk->Data->getValue()),
|
||||
ChunkUtils::reorderNibbleArray($subChunk->SkyLight->getValue(), "\xff"),
|
||||
ChunkUtils::reorderNibbleArray($subChunk->BlockLight->getValue())
|
||||
ChunkUtils::reorderByteArray($subChunk->getByteArray("Blocks")),
|
||||
ChunkUtils::reorderNibbleArray($subChunk->getByteArray("Data")),
|
||||
ChunkUtils::reorderNibbleArray($subChunk->getByteArray("SkyLight"), "\xff"),
|
||||
ChunkUtils::reorderNibbleArray($subChunk->getByteArray("BlockLight"))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -53,12 +53,12 @@ class McRegion extends BaseLevelProvider{
|
||||
*/
|
||||
public function nbtSerialize(Chunk $chunk) : string{
|
||||
$nbt = new CompoundTag("Level", []);
|
||||
$nbt->xPos = new IntTag("xPos", $chunk->getX());
|
||||
$nbt->zPos = new IntTag("zPos", $chunk->getZ());
|
||||
$nbt->setInt("xPos", $chunk->getX());
|
||||
$nbt->setInt("zPos", $chunk->getZ());
|
||||
|
||||
$nbt->LastUpdate = new LongTag("LastUpdate", 0); //TODO
|
||||
$nbt->TerrainPopulated = new ByteTag("TerrainPopulated", $chunk->isPopulated() ? 1 : 0);
|
||||
$nbt->LightPopulated = new ByteTag("LightPopulated", $chunk->isLightPopulated() ? 1 : 0);
|
||||
$nbt->setLong("LastUpdate", 0); //TODO
|
||||
$nbt->setByte("TerrainPopulated", $chunk->isPopulated() ? 1 : 0);
|
||||
$nbt->setByte("LightPopulated", $chunk->isLightPopulated() ? 1 : 0);
|
||||
|
||||
$ids = "";
|
||||
$data = "";
|
||||
@ -77,13 +77,13 @@ class McRegion extends BaseLevelProvider{
|
||||
}
|
||||
}
|
||||
|
||||
$nbt->Blocks = new ByteArrayTag("Blocks", $ids);
|
||||
$nbt->Data = new ByteArrayTag("Data", $data);
|
||||
$nbt->SkyLight = new ByteArrayTag("SkyLight", $skyLight);
|
||||
$nbt->BlockLight = new ByteArrayTag("BlockLight", $blockLight);
|
||||
$nbt->setByteArray("Blocks", $ids);
|
||||
$nbt->setByteArray("Data", $data);
|
||||
$nbt->setByteArray("SkyLight", $skyLight);
|
||||
$nbt->setByteArray("BlockLight", $blockLight);
|
||||
|
||||
$nbt->Biomes = new ByteArrayTag("Biomes", $chunk->getBiomeIdArray()); //doesn't exist in regular McRegion, this is here for PocketMine-MP only
|
||||
$nbt->HeightMap = new ByteArrayTag("HeightMap", pack("C*", ...$chunk->getHeightMapArray()));
|
||||
$nbt->setByteArray("Biomes", $chunk->getBiomeIdArray()); //doesn't exist in regular McRegion, this is here for PocketMine-MP only
|
||||
$nbt->setByteArray("HeightMap", pack("C*", ...$chunk->getHeightMapArray())); //this is ByteArray in McRegion, but IntArray in Anvil (due to raised build height)
|
||||
|
||||
$entities = [];
|
||||
|
||||
@ -94,7 +94,7 @@ class McRegion extends BaseLevelProvider{
|
||||
}
|
||||
}
|
||||
|
||||
$nbt->Entities = new ListTag("Entities", $entities, NBT::TAG_Compound);
|
||||
$nbt->setTag(new ListTag("Entities", $entities, NBT::TAG_Compound));
|
||||
|
||||
$tiles = [];
|
||||
foreach($chunk->getTiles() as $tile){
|
||||
@ -102,7 +102,7 @@ class McRegion extends BaseLevelProvider{
|
||||
$tiles[] = $tile->namedtag;
|
||||
}
|
||||
|
||||
$nbt->TileEntities = new ListTag("TileEntities", $tiles, NBT::TAG_Compound);
|
||||
$nbt->setTag(new ListTag("TileEntities", $tiles, NBT::TAG_Compound));
|
||||
|
||||
$writer = new NBT(NBT::BIG_ENDIAN);
|
||||
$nbt->setName("Level");
|
||||
@ -281,11 +281,11 @@ class McRegion extends BaseLevelProvider{
|
||||
}
|
||||
|
||||
public function getDifficulty() : int{
|
||||
return isset($this->levelData->Difficulty) ? $this->levelData->Difficulty->getValue() : Level::DIFFICULTY_NORMAL;
|
||||
return $this->levelData->getByte("Difficulty", Level::DIFFICULTY_NORMAL);
|
||||
}
|
||||
|
||||
public function setDifficulty(int $difficulty){
|
||||
$this->levelData->Difficulty = new ByteTag("Difficulty", $difficulty);
|
||||
$this->levelData->setByte("Difficulty", $difficulty);
|
||||
}
|
||||
|
||||
public function getChunk(int $chunkX, int $chunkZ, bool $create = false){
|
||||
|
@ -23,14 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\level\format\io\region;
|
||||
|
||||
use pocketmine\level\format\Chunk;
|
||||
use pocketmine\level\format\ChunkException;
|
||||
use pocketmine\level\format\SubChunk;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\{
|
||||
ByteArrayTag, ByteTag, CompoundTag, IntArrayTag, IntTag, ListTag, LongTag
|
||||
};
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\nbt\tag\ByteArrayTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
|
||||
/**
|
||||
* This format is exactly the same as the PC Anvil format, with the only difference being that the stored data order
|
||||
@ -51,10 +46,10 @@ class PMAnvil extends Anvil{
|
||||
|
||||
protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
|
||||
return new SubChunk(
|
||||
$subChunk->Blocks->getValue(),
|
||||
$subChunk->Data->getValue(),
|
||||
$subChunk->SkyLight->getValue(),
|
||||
$subChunk->BlockLight->getValue()
|
||||
$subChunk->getByteArray("Blocks"),
|
||||
$subChunk->getByteArray("Data"),
|
||||
$subChunk->getByteArray("SkyLight"),
|
||||
$subChunk->getByteArray("BlockLight")
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,23 @@ class ListTag extends NamedTag implements \ArrayAccess, \Countable{
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function getAllValues() : array{
|
||||
$result = [];
|
||||
foreach($this as $tag){
|
||||
if(!($tag instanceof NamedTag)){
|
||||
continue;
|
||||
}
|
||||
|
||||
if($tag instanceof \ArrayAccess){
|
||||
$result[] = $tag;
|
||||
}else{
|
||||
$result[] = $tag->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function offsetExists($offset){
|
||||
return isset($this->{$offset});
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
|
||||
public function __construct(Server $server){
|
||||
$this->server = $server;
|
||||
|
||||
$this->rakLib = new RakLibServer($this->server->getLogger(), $this->server->getLoader(), $this->server->getPort(), $this->server->getIp() === "" ? "0.0.0.0" : $this->server->getIp(), false);
|
||||
$this->rakLib = new RakLibServer($this->server->getLogger(), \pocketmine\COMPOSER_AUTOLOADER_PATH, $this->server->getPort(), $this->server->getIp() === "" ? "0.0.0.0" : $this->server->getIp(), false);
|
||||
$this->interface = new ServerHandler($this->rakLib, $this);
|
||||
}
|
||||
|
||||
|
@ -107,10 +107,10 @@ abstract class Spawnable extends Tile{
|
||||
*/
|
||||
final public function getSpawnCompound() : CompoundTag{
|
||||
$nbt = new CompoundTag("", [
|
||||
$this->namedtag->getTag("id"),
|
||||
$this->namedtag->getTag("x"),
|
||||
$this->namedtag->getTag("y"),
|
||||
$this->namedtag->getTag("z")
|
||||
$this->namedtag->getTag(self::TAG_ID),
|
||||
$this->namedtag->getTag(self::TAG_X),
|
||||
$this->namedtag->getTag(self::TAG_Y),
|
||||
$this->namedtag->getTag(self::TAG_Z)
|
||||
]);
|
||||
$this->addAdditionalSpawnData($nbt);
|
||||
return $nbt;
|
||||
|
@ -44,6 +44,11 @@ use pocketmine\Server;
|
||||
|
||||
abstract class Tile extends Position{
|
||||
|
||||
const TAG_ID = "id";
|
||||
const TAG_X = "x";
|
||||
const TAG_Y = "y";
|
||||
const TAG_Z = "z";
|
||||
|
||||
const BREWING_STAND = "BrewingStand";
|
||||
const CHEST = "Chest";
|
||||
const ENCHANT_TABLE = "EnchantTable";
|
||||
@ -136,14 +141,14 @@ abstract class Tile extends Position{
|
||||
$this->namedtag = $nbt;
|
||||
$this->server = $level->getServer();
|
||||
$this->setLevel($level);
|
||||
$this->chunk = $level->getChunk($this->namedtag->getInt("x") >> 4, $this->namedtag->getInt("z") >> 4, false);
|
||||
$this->chunk = $level->getChunk($this->namedtag->getInt(self::TAG_X) >> 4, $this->namedtag->getInt(self::TAG_Z) >> 4, false);
|
||||
assert($this->chunk !== null);
|
||||
|
||||
$this->name = "";
|
||||
$this->id = Tile::$tileCount++;
|
||||
$this->x = $this->namedtag->getInt("x");
|
||||
$this->y = $this->namedtag->getInt("y");
|
||||
$this->z = $this->namedtag->getInt("z");
|
||||
$this->x = $this->namedtag->getInt(self::TAG_X);
|
||||
$this->y = $this->namedtag->getInt(self::TAG_Y);
|
||||
$this->z = $this->namedtag->getInt(self::TAG_Z);
|
||||
|
||||
$this->chunk->addTile($this);
|
||||
$this->getLevel()->addTile($this);
|
||||
@ -154,10 +159,10 @@ abstract class Tile extends Position{
|
||||
}
|
||||
|
||||
public function saveNBT() : void{
|
||||
$this->namedtag->setString("id", static::getSaveId());
|
||||
$this->namedtag->setInt("x", $this->x);
|
||||
$this->namedtag->setInt("y", $this->y);
|
||||
$this->namedtag->setInt("z", $this->z);
|
||||
$this->namedtag->setString(self::TAG_ID, static::getSaveId());
|
||||
$this->namedtag->setInt(self::TAG_X, $this->x);
|
||||
$this->namedtag->setInt(self::TAG_Y, $this->y);
|
||||
$this->namedtag->setInt(self::TAG_Z, $this->z);
|
||||
}
|
||||
|
||||
public function getNBT() : CompoundTag{
|
||||
@ -167,7 +172,7 @@ abstract class Tile extends Position{
|
||||
public function getCleanedNBT() : ?CompoundTag{
|
||||
$this->saveNBT();
|
||||
$tag = clone $this->namedtag;
|
||||
$tag->removeTag("x", "y", "z", "id");
|
||||
$tag->removeTag(self::TAG_X, self::TAG_Y, self::TAG_Z, self::TAG_ID);
|
||||
if($tag->getCount() > 0){
|
||||
return $tag;
|
||||
}else{
|
||||
@ -187,10 +192,10 @@ abstract class Tile extends Position{
|
||||
*/
|
||||
public static function createNBT(Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : CompoundTag{
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", static::getSaveId()),
|
||||
new IntTag("x", (int) $pos->x),
|
||||
new IntTag("y", (int) $pos->y),
|
||||
new IntTag("z", (int) $pos->z)
|
||||
new StringTag(self::TAG_ID, static::getSaveId()),
|
||||
new IntTag(self::TAG_X, (int) $pos->x),
|
||||
new IntTag(self::TAG_Y, (int) $pos->y),
|
||||
new IntTag(self::TAG_Z, (int) $pos->z)
|
||||
]);
|
||||
|
||||
static::createAdditionalNBT($nbt, $pos, $face, $item, $player);
|
||||
|
@ -1 +0,0 @@
|
||||
Subproject commit 0e26115330808b91ac3ab0b39e54fc9f9f679189
|
1
src/spl
1
src/spl
@ -1 +0,0 @@
|
||||
Subproject commit cf7738721e7342c018a91ad300108b2dd95c7224
|
Loading…
x
Reference in New Issue
Block a user