Merge branch 'next-minor' into next-major

This commit is contained in:
Dylan K. Taylor 2022-12-18 21:05:26 +00:00
commit ffa88aff67
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
6 changed files with 118 additions and 45 deletions

View File

@ -37,7 +37,7 @@
"pocketmine/bedrock-block-upgrade-schema": "dev-master@dev",
"pocketmine/bedrock-data": "dev-modern-world-support@dev",
"pocketmine/bedrock-item-upgrade-schema": "dev-master",
"pocketmine/bedrock-protocol": "~17.0.0+bedrock-1.19.50",
"pocketmine/bedrock-protocol": "~17.1.0+bedrock-1.19.50",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.2.0",

16
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "6c40129ef11a3cfc79081b8f53edda8e",
"content-hash": "614023b483badb5ec8720775dd2d3d12",
"packages": [
{
"name": "adhocore/json-comment",
@ -329,16 +329,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
"version": "17.0.0+bedrock-1.19.50",
"version": "17.1.0+bedrock-1.19.50",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "272e10197bb1603c0a81075bf5b9dae0d081a6e2"
"reference": "c572706cf5e3202718dd35a35dd30fe08cd671de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/272e10197bb1603c0a81075bf5b9dae0d081a6e2",
"reference": "272e10197bb1603c0a81075bf5b9dae0d081a6e2",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/c572706cf5e3202718dd35a35dd30fe08cd671de",
"reference": "c572706cf5e3202718dd35a35dd30fe08cd671de",
"shasum": ""
},
"require": {
@ -352,7 +352,7 @@
"ramsey/uuid": "^4.1"
},
"require-dev": {
"phpstan/phpstan": "1.9.0",
"phpstan/phpstan": "1.9.3",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5"
@ -370,9 +370,9 @@
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
"support": {
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
"source": "https://github.com/pmmp/BedrockProtocol/tree/17.0.0+bedrock-1.19.50"
"source": "https://github.com/pmmp/BedrockProtocol/tree/17.1.0+bedrock-1.19.50"
},
"time": "2022-11-30T16:16:27+00:00"
"time": "2022-12-15T20:34:49+00:00"
},
{
"name": "pocketmine/binaryutils",

View File

@ -378,7 +378,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
array_values($this->inventory->getContents()),
array_values($this->armorInventory->getContents()),
array_values($this->offHandInventory->getContents()),
), function(Item $item) : bool{ return !$item->hasEnchantment(VanillaEnchantments::VANISHING()); });
), function(Item $item) : bool{ return !$item->hasEnchantment(VanillaEnchantments::VANISHING()) && !$item->keepOnDeath(); });
}
public function saveNBT() : CompoundTag{

View File

@ -66,6 +66,8 @@ class Item implements \JsonSerializable{
public const TAG_DISPLAY_NAME = "Name";
public const TAG_DISPLAY_LORE = "Lore";
public const TAG_KEEP_ON_DEATH = "minecraft:keep_on_death";
private CompoundTag $nbt;
protected int $count = 1;
@ -89,6 +91,8 @@ class Item implements \JsonSerializable{
*/
protected array $canDestroy = [];
protected bool $keepOnDeath = false;
/**
* Constructs a new Item type. This constructor should ONLY be used when constructing a new item TYPE to register
* into the index.
@ -213,6 +217,17 @@ class Item implements \JsonSerializable{
}
}
/**
* Returns whether players will retain this item on death. If a non-player dies it will be excluded from the drops.
*/
public function keepOnDeath() : bool{
return $this->keepOnDeath;
}
public function setKeepOnDeath(bool $keepOnDeath) : void{
$this->keepOnDeath = $keepOnDeath;
}
/**
* Returns whether this Item has a non-empty NBT.
*/
@ -311,6 +326,8 @@ class Item implements \JsonSerializable{
$this->canDestroy[$entry->getValue()] = $entry->getValue();
}
}
$this->keepOnDeath = $tag->getByte(self::TAG_KEEP_ON_DEATH, 0) !== 0;
}
protected function serializeCompoundTag(CompoundTag $tag) : void{
@ -368,6 +385,12 @@ class Item implements \JsonSerializable{
}else{
$tag->removeTag("CanDestroy");
}
if($this->keepOnDeath){
$tag->setByte(self::TAG_KEEP_ON_DEATH, 1);
}else{
$tag->removeTag(self::TAG_KEEP_ON_DEATH);
}
}
public function getCount() : int{

View File

@ -131,6 +131,7 @@ use pocketmine\world\sound\Sound;
use pocketmine\world\World;
use Ramsey\Uuid\UuidInterface;
use function abs;
use function array_filter;
use function array_map;
use function array_shift;
use function assert;
@ -2280,10 +2281,11 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->getWorld()->dropItem($this->location, $item);
}
$clearInventory = fn(Inventory $inventory) => $inventory->setContents(array_filter($inventory->getContents(), fn(Item $item) => $item->keepOnDeath()));
$this->inventory->setHeldItemIndex(0);
$this->inventory->clearAll();
$this->armorInventory->clearAll();
$this->offHandInventory->clearAll();
$clearInventory($this->inventory);
$clearInventory($this->armorInventory);
$clearInventory($this->offHandInventory);
}
if(!$ev->getKeepXp()){

View File

@ -38,6 +38,8 @@ use function is_float;
use function is_int;
use function is_string;
use function mkdir;
use function rtrim;
use function strlen;
use function strtolower;
use const DIRECTORY_SEPARATOR;
@ -93,41 +95,26 @@ class ResourcePackManager{
}
$pack = (string) $pack;
try{
$packPath = Path::join($this->path, $pack);
if(!file_exists($packPath)){
throw new ResourcePackException("File or directory not found");
}
if(is_dir($packPath)){
throw new ResourcePackException("Directory resource packs are unsupported");
}
$newPack = $this->loadPackFromPath(Path::join($this->path, $pack));
$newPack = null;
//Detect the type of resource pack.
$info = new \SplFileInfo($packPath);
switch($info->getExtension()){
case "zip":
case "mcpack":
$newPack = new ZippedResourcePack($packPath);
break;
}
$this->resourcePacks[] = $newPack;
$index = strtolower($newPack->getPackId());
$this->uuidList[$index] = $newPack;
if($newPack instanceof ResourcePack){
$this->resourcePacks[] = $newPack;
$index = strtolower($newPack->getPackId());
$this->uuidList[$index] = $newPack;
$keyPath = Path::join($this->path, $pack . ".key");
if(file_exists($keyPath)){
try{
$this->encryptionKeys[$index] = ErrorToExceptionHandler::trapAndRemoveFalse(
fn() => file_get_contents($keyPath)
);
}catch(\ErrorException $e){
throw new ResourcePackException("Could not read encryption key file: " . $e->getMessage(), 0, $e);
}
$keyPath = Path::join($this->path, $pack . ".key");
if(file_exists($keyPath)){
try{
$key = ErrorToExceptionHandler::trapAndRemoveFalse(
fn() => file_get_contents($keyPath)
);
}catch(\ErrorException $e){
throw new ResourcePackException("Could not read encryption key file: " . $e->getMessage(), 0, $e);
}
}else{
throw new ResourcePackException("Format not recognized");
$key = rtrim($key, "\r\n");
if(strlen($key) !== 32){
throw new ResourcePackException("Invalid encryption key length, must be exactly 32 bytes");
}
$this->encryptionKeys[$index] = $key;
}
}catch(ResourcePackException $e){
$logger->critical("Could not load resource pack \"$pack\": " . $e->getMessage());
@ -137,6 +124,25 @@ class ResourcePackManager{
$logger->debug("Successfully loaded " . count($this->resourcePacks) . " resource packs");
}
private function loadPackFromPath(string $packPath) : ResourcePack{
if(!file_exists($packPath)){
throw new ResourcePackException("File or directory not found");
}
if(is_dir($packPath)){
throw new ResourcePackException("Directory resource packs are unsupported");
}
//Detect the type of resource pack.
$info = new \SplFileInfo($packPath);
switch($info->getExtension()){
case "zip":
case "mcpack":
return new ZippedResourcePack($packPath);
}
throw new ResourcePackException("Format not recognized");
}
/**
* Returns the directory which resource packs are loaded from.
*/
@ -159,6 +165,29 @@ class ResourcePackManager{
return $this->resourcePacks;
}
/**
* Sets the resource packs to use. Packs earliest in the list will appear at the top of the stack (maximum
* priority), and later ones will appear below (lower priority), in the same manner as the Bedrock resource packs
* screen in-game.
*
* @param ResourcePack[] $resourceStack
* @phpstan-param list<ResourcePack> $resourceStack
*/
public function setResourceStack(array $resourceStack) : void{
$uuidList = [];
$resourcePacks = [];
foreach($resourceStack as $pack){
$uuid = strtolower($pack->getPackId());
if(isset($uuidList[$uuid])){
throw new \InvalidArgumentException("Cannot load two resource pack with the same UUID ($uuid)");
}
$uuidList[$uuid] = $pack;
$resourcePacks[] = $pack;
}
$this->resourcePacks = $resourcePacks;
$this->uuidList = $uuidList;
}
/**
* Returns the resource pack matching the specified UUID string, or null if the ID was not recognized.
*/
@ -180,4 +209,23 @@ class ResourcePackManager{
public function getPackEncryptionKey(string $id) : ?string{
return $this->encryptionKeys[strtolower($id)] ?? null;
}
/**
* Sets the encryption key to use for decrypting the specified resource pack. The pack will **NOT** be decrypted by
* PocketMine-MP; the key is simply passed to the client to allow it to decrypt the pack after downloading it.
*/
public function setPackEncryptionKey(string $id, ?string $key) : void{
$id = strtolower($id);
if($key === null){
//allow deprovisioning keys for resource packs that have been removed
unset($this->encryptionKeys[$id]);
}elseif(isset($this->uuidList[$id])){
if(strlen($key) !== 32){
throw new \InvalidArgumentException("Encryption key must be exactly 32 bytes long");
}
$this->encryptionKeys[$id] = $key;
}else{
throw new \InvalidArgumentException("Unknown pack ID $id");
}
}
}