mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-06 09:56:06 +00:00
Merge branch 'minor-next' into stable
This commit is contained in:
@ -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++;
|
||||
}
|
||||
|
@ -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){
|
||||
|
@ -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 = [];
|
||||
|
||||
|
@ -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){
|
||||
|
@ -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
|
||||
);
|
||||
|
Reference in New Issue
Block a user