Merge branch 'minor-next' into stable

This commit is contained in:
Dylan K. Taylor
2023-09-06 12:06:15 +01:00
119 changed files with 3729 additions and 832 deletions

View File

@ -35,9 +35,12 @@ use pocketmine\block\inventory\LoomInventory;
use pocketmine\block\inventory\SmithingTableInventory;
use pocketmine\block\inventory\StonecutterInventory;
use pocketmine\crafting\FurnaceType;
use pocketmine\data\bedrock\EnchantmentIdMap;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\transaction\action\SlotChangeAction;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\item\enchantment\EnchantingOption;
use pocketmine\item\enchantment\EnchantmentInstance;
use pocketmine\network\mcpe\cache\CreativeInventoryCache;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
@ -46,7 +49,10 @@ use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\PlayerEnchantOptionsPacket;
use pocketmine\network\mcpe\protocol\types\BlockPosition;
use pocketmine\network\mcpe\protocol\types\Enchant;
use pocketmine\network\mcpe\protocol\types\EnchantOption as ProtocolEnchantOption;
use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
@ -59,6 +65,7 @@ use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\ObjectSet;
use function array_fill_keys;
use function array_keys;
use function array_map;
use function array_search;
use function count;
use function get_class;
@ -104,6 +111,12 @@ class InventoryManager{
private bool $fullSyncRequested = false;
/** @var int[] network recipe ID => enchanting table option index */
private array $enchantingTableOptions = [];
//TODO: this should be based on the total number of crafting recipes - if there are ever 100k recipes, this will
//conflict with regular recipes
private int $nextEnchantingTableOptionId = 100000;
public function __construct(
private Player $player,
private NetworkSession $session
@ -383,6 +396,7 @@ class InventoryManager{
throw new AssumptionFailedError("We should not have opened a new window while a window was waiting to be closed");
}
$this->pendingCloseWindowId = $this->lastInventoryNetworkId;
$this->enchantingTableOptions = [];
}
}
@ -630,6 +644,39 @@ class InventoryManager{
$this->session->sendDataPacket(CreativeInventoryCache::getInstance()->getCache($this->player->getCreativeInventory()));
}
/**
* @param EnchantingOption[] $options
*/
public function syncEnchantingTableOptions(array $options) : void{
$protocolOptions = [];
foreach($options as $index => $option){
$optionId = $this->nextEnchantingTableOptionId++;
$this->enchantingTableOptions[$optionId] = $index;
$protocolEnchantments = array_map(
fn(EnchantmentInstance $e) => new Enchant(EnchantmentIdMap::getInstance()->toId($e->getType()), $e->getLevel()),
$option->getEnchantments()
);
// We don't pay attention to the $slotFlags, $heldActivatedEnchantments and $selfActivatedEnchantments
// as everything works fine without them (perhaps these values are used somehow in the BDS).
$protocolOptions[] = new ProtocolEnchantOption(
$option->getRequiredXpLevel(),
0, $protocolEnchantments,
[],
[],
$option->getDisplayName(),
$optionId
);
}
$this->session->sendDataPacket(PlayerEnchantOptionsPacket::create($protocolOptions));
}
public function getEnchantingTableOptionIndex(int $recipeId) : ?int{
return $this->enchantingTableOptions[$recipeId] ?? null;
}
private function newItemStackId() : int{
return $this->nextItemStackId++;
}

View File

@ -108,6 +108,7 @@ use pocketmine\utils\BinaryStream;
use pocketmine\utils\ObjectSet;
use pocketmine\utils\TextFormat;
use pocketmine\world\Position;
use pocketmine\YmlServerProperties;
use function array_map;
use function array_values;
use function base64_encode;
@ -406,10 +407,12 @@ class NetworkSession{
$timings->startTiming();
try{
$ev = new DataPacketDecodeEvent($this, $packet->pid(), $buffer);
$ev->call();
if($ev->isCancelled()){
return;
if(DataPacketDecodeEvent::hasHandlers()){
$ev = new DataPacketDecodeEvent($this, $packet->pid(), $buffer);
$ev->call();
if($ev->isCancelled()){
return;
}
}
$decodeTimings = Timings::getDecodeDataPacketTimings($packet);
@ -429,19 +432,22 @@ class NetworkSession{
$decodeTimings->stopTiming();
}
$ev = new DataPacketReceiveEvent($this, $packet);
$ev->call();
if(!$ev->isCancelled()){
$handlerTimings = Timings::getHandleDataPacketTimings($packet);
$handlerTimings->startTiming();
try{
if($this->handler === null || !$packet->handle($this->handler)){
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
}
}finally{
$handlerTimings->stopTiming();
if(DataPacketReceiveEvent::hasHandlers()){
$ev = new DataPacketReceiveEvent($this, $packet);
$ev->call();
if($ev->isCancelled()){
return;
}
}
$handlerTimings = Timings::getHandleDataPacketTimings($packet);
$handlerTimings->startTiming();
try{
if($this->handler === null || !$packet->handle($this->handler)){
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
}
}finally{
$handlerTimings->stopTiming();
}
}finally{
$timings->stopTiming();
}
@ -459,12 +465,16 @@ class NetworkSession{
$timings = Timings::getSendDataPacketTimings($packet);
$timings->startTiming();
try{
$ev = new DataPacketSendEvent([$this], [$packet]);
$ev->call();
if($ev->isCancelled()){
return false;
if(DataPacketSendEvent::hasHandlers()){
$ev = new DataPacketSendEvent([$this], [$packet]);
$ev->call();
if($ev->isCancelled()){
return false;
}
$packets = $ev->getPackets();
}else{
$packets = [$packet];
}
$packets = $ev->getPackets();
foreach($packets as $evPacket){
$this->addToSendBuffer(self::encodePacketTimed(PacketSerializer::encoder($this->packetSerializerContext), $evPacket));
@ -731,7 +741,7 @@ class NetworkSession{
}
$this->logger->debug("Xbox Live authenticated: " . ($this->authenticated ? "YES" : "NO"));
$checkXUID = $this->server->getConfigGroup()->getPropertyBool("player.verify-xuid", true);
$checkXUID = $this->server->getConfigGroup()->getPropertyBool(YmlServerProperties::PLAYER_VERIFY_XUID, true);
$myXUID = $this->info instanceof XboxLivePlayerInfo ? $this->info->getXuid() : "";
$kickForXUIDMismatch = function(string $xuid) use ($checkXUID, $myXUID) : bool{
if($checkXUID && $myXUID !== $xuid){

View File

@ -44,12 +44,14 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
public function broadcastPackets(array $recipients, array $packets) : void{
//TODO: this shouldn't really be called here, since the broadcaster might be replaced by an alternative
//implementation that doesn't fire events
$ev = new DataPacketSendEvent($recipients, $packets);
$ev->call();
if($ev->isCancelled()){
return;
if(DataPacketSendEvent::hasHandlers()){
$ev = new DataPacketSendEvent($recipients, $packets);
$ev->call();
if($ev->isCancelled()){
return;
}
$packets = $ev->getPackets();
}
$packets = $ev->getPackets();
$compressors = [];

View File

@ -23,11 +23,13 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\handler;
use pocketmine\block\inventory\EnchantInventory;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\transaction\action\CreateItemAction;
use pocketmine\inventory\transaction\action\DestroyItemAction;
use pocketmine\inventory\transaction\action\DropItemAction;
use pocketmine\inventory\transaction\CraftingTransaction;
use pocketmine\inventory\transaction\EnchantingTransaction;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\inventory\transaction\TransactionBuilder;
use pocketmine\inventory\transaction\TransactionBuilderInventory;
@ -287,7 +289,7 @@ class ItemStackRequestExecutor{
* @throws ItemStackRequestProcessException
*/
private function assertDoingCrafting() : void{
if(!$this->specialTransaction instanceof CraftingTransaction){
if(!$this->specialTransaction instanceof CraftingTransaction && !$this->specialTransaction instanceof EnchantingTransaction){
if($this->specialTransaction === null){
throw new ItemStackRequestProcessException("Expected CraftRecipe or CraftRecipeAuto action to precede this action");
}else{
@ -333,7 +335,16 @@ class ItemStackRequestExecutor{
$this->setNextCreatedItem($item, true);
}elseif($action instanceof CraftRecipeStackRequestAction){
$this->beginCrafting($action->getRecipeId(), 1);
$window = $this->player->getCurrentWindow();
if($window instanceof EnchantInventory){
$optionId = $this->inventoryManager->getEnchantingTableOptionIndex($action->getRecipeId());
if($optionId !== null && ($option = $window->getOption($optionId)) !== null){
$this->specialTransaction = new EnchantingTransaction($this->player, $option, $optionId + 1);
$this->setNextCreatedItem($window->getOutput($optionId));
}
}else{
$this->beginCrafting($action->getRecipeId(), 1);
}
}elseif($action instanceof CraftRecipeAutoStackRequestAction){
$this->beginCrafting($action->getRecipeId(), $action->getRepetitions());
}elseif($action instanceof CraftingConsumeInputStackRequestAction){

View File

@ -42,6 +42,7 @@ use pocketmine\Server;
use pocketmine\thread\ThreadCrashException;
use pocketmine\timings\Timings;
use pocketmine\utils\Utils;
use pocketmine\YmlServerProperties;
use raklib\generic\DisconnectReason;
use raklib\generic\SocketException;
use raklib\protocol\EncapsulatedPacket;
@ -125,7 +126,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
$threadToMainBuffer,
new InternetAddress($ip, $port, $ipV6 ? 6 : 4),
$this->rakServerId,
$this->server->getConfigGroup()->getPropertyInt("network.max-mtu-size", 1492),
$this->server->getConfigGroup()->getPropertyInt(YmlServerProperties::NETWORK_MAX_MTU_SIZE, 1492),
self::MCPE_RAKNET_PROTOCOL_VERSION,
$sleeperEntry
);

View File

@ -29,6 +29,7 @@ use pocketmine\plugin\Plugin;
use pocketmine\Server;
use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
use pocketmine\YmlServerProperties;
use function array_map;
use function chr;
use function count;
@ -66,7 +67,7 @@ final class QueryInfo{
public function __construct(Server $server){
$this->serverName = $server->getMotd();
$this->listPlugins = $server->getConfigGroup()->getPropertyBool("settings.query-plugins", true);
$this->listPlugins = $server->getConfigGroup()->getPropertyBool(YmlServerProperties::SETTINGS_QUERY_PLUGINS, true);
$this->plugins = $server->getPluginManager()->getPlugins();
$this->players = array_map(fn(Player $p) => $p->getName(), $server->getOnlinePlayers());