diff --git a/src/block/Block.php b/src/block/Block.php index 89fe39265..aabb69665 100644 --- a/src/block/Block.php +++ b/src/block/Block.php @@ -36,6 +36,7 @@ use pocketmine\data\runtime\RuntimeDataSizeCalculator; use pocketmine\data\runtime\RuntimeDataWriter; use pocketmine\entity\Entity; use pocketmine\entity\projectile\Projectile; +use pocketmine\inventory\Inventory; use pocketmine\item\enchantment\AvailableEnchantmentRegistry; use pocketmine\item\enchantment\ItemEnchantmentTagRegistry; use pocketmine\item\enchantment\ItemEnchantmentTags; @@ -515,6 +516,15 @@ class Block{ } + /** + * Called by the World when a change is detected in a container's inventory at the block's position. + * Use this to do visual updates on the block if needed. + * Don't do any expensive logic in here. It will be called every time a slot of the inventory changes. + */ + public function onContainerUpdate(Inventory $inventory) : void{ + + } + /** * Do actions when interacted by Item. Returns if it has done anything * diff --git a/src/block/BrewingStand.php b/src/block/BrewingStand.php index 59e439b91..dc961aa55 100644 --- a/src/block/BrewingStand.php +++ b/src/block/BrewingStand.php @@ -28,6 +28,7 @@ use pocketmine\block\tile\BrewingStand as TileBrewingStand; use pocketmine\block\utils\BrewingStandSlot; use pocketmine\block\utils\SupportType; use pocketmine\data\runtime\RuntimeDataDescriber; +use pocketmine\inventory\Inventory; use pocketmine\item\Item; use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; @@ -114,19 +115,22 @@ class BrewingStand extends Transparent{ if($brewing->onUpdate()){ $world->scheduleDelayedBlockUpdate($this->position, 1); } + } + } - $changed = false; - foreach(BrewingStandSlot::cases() as $slot){ - $occupied = !$brewing->getInventory()->isSlotEmpty($slot->getSlotNumber()); - if($occupied !== $this->hasSlot($slot)){ - $this->setSlot($slot, $occupied); - $changed = true; - } + public function onContainerUpdate(Inventory $inventory) : void{ + $world = $this->position->getWorld(); + $changed = false; + foreach(BrewingStandSlot::cases() as $slot){ + $occupied = !$inventory->isSlotEmpty($slot->getSlotNumber()); + if($occupied !== $this->hasSlot($slot)){ + $this->setSlot($slot, $occupied); + $changed = true; } + } - if($changed){ - $world->setBlock($this->position, $this); - } + if($changed){ + $world->setBlock($this->position, $this); } } } diff --git a/src/block/Campfire.php b/src/block/Campfire.php index dcb0e3fa8..d5413d610 100644 --- a/src/block/Campfire.php +++ b/src/block/Campfire.php @@ -38,6 +38,7 @@ use pocketmine\entity\projectile\SplashPotion; use pocketmine\event\block\CampfireCookEvent; use pocketmine\event\entity\EntityDamageByBlockEvent; use pocketmine\event\entity\EntityDamageEvent; +use pocketmine\inventory\Inventory; use pocketmine\item\Durable; use pocketmine\item\enchantment\VanillaEnchantments; use pocketmine\item\Item; @@ -67,8 +68,6 @@ class Campfire extends Transparent{ LightableTrait::describeBlockOnlyState as encodeLitState; } - private const UPDATE_INTERVAL_TICKS = 10; - /** * @deprecated This was added by mistake. It can't be relied on as the inventory won't be initialized if this block * has never been set in the world. @@ -250,7 +249,7 @@ class Campfire extends Transparent{ $furnaceType = $this->getFurnaceType(); $maxCookDuration = $furnaceType->getCookDurationTicks(); foreach($items as $slot => $item){ - $this->setCookingTime($slot, min($maxCookDuration, $this->getCookingTime($slot) + self::UPDATE_INTERVAL_TICKS)); + $this->setCookingTime($slot, min($maxCookDuration, $this->getCookingTime($slot) + 1)); if($this->getCookingTime($slot) >= $maxCookDuration){ $result = ($recipe = $this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($furnaceType)->match($item)) instanceof FurnaceRecipe ? @@ -269,19 +268,25 @@ class Campfire extends Transparent{ $this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $ev->getResult()); } } + $tile = $this->position->getWorld()->getTile($this->position); + if($tile instanceof TileCampfire){ + //TODO: we probably need to rethink how these are tracked + $tile->setCookingTimes($this->cookingTimes); + } if(count($items) > 0){ $this->position->getWorld()->setBlock($this->position, $this); } if(mt_rand(1, 6) === 1){ $this->position->getWorld()->addSound($this->position, $furnaceType->getCookSound()); } - $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS); - }else{ - //make sure the visual state is updated when items are added - $this->position->getWorld()->setBlock($this->position, $this); + $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); } } + public function onContainerUpdate(Inventory $inventory) : void{ + $this->position->getWorld()->setBlock($this->position, $this); //update visual state + } + private function extinguish() : void{ $this->position->getWorld()->addSound($this->position, new FireExtinguishSound()); $this->position->getWorld()->setBlock($this->position, $this->setLit(false)); @@ -290,6 +295,6 @@ class Campfire extends Transparent{ private function ignite() : void{ $this->position->getWorld()->addSound($this->position, new FlintSteelSound()); $this->position->getWorld()->setBlock($this->position, $this->setLit(true)); - $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS); + $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); } } diff --git a/src/block/ChiseledBookshelf.php b/src/block/ChiseledBookshelf.php index 73c4861bf..4c91f1d94 100644 --- a/src/block/ChiseledBookshelf.php +++ b/src/block/ChiseledBookshelf.php @@ -28,6 +28,7 @@ use pocketmine\block\utils\ChiseledBookshelfSlot; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\data\runtime\RuntimeDataDescriber; +use pocketmine\inventory\Inventory; use pocketmine\item\Book; use pocketmine\item\EnchantedBook; use pocketmine\item\Item; @@ -164,6 +165,20 @@ class ChiseledBookshelf extends Opaque{ return true; } + public function onContainerUpdate(Inventory $inventory) : void{ + $changed = false; + foreach(ChiseledBookshelfSlot::cases() as $case){ + $hasItem = !$inventory->isSlotEmpty($case->value); + if($this->hasSlot($case) !== $hasItem){ + $this->setSlot($case, $hasItem); + $changed = true; + } + } + if($changed){ + $this->position->getWorld()->setBlock($this->position, $this); + } + } + public function getDropsForCompatibleTool(Item $item) : array{ return []; } diff --git a/src/world/World.php b/src/world/World.php index 03ceca29c..863cbd90f 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2834,6 +2834,7 @@ class World implements ChunkManager, InventoryListener{ private function notifyInventoryUpdate(Inventory $inventory) : void{ $blockPosition = $this->containerToBlockPositionMap[$inventory] ?? null; if($blockPosition !== null){ + $this->getBlock($blockPosition)->onContainerUpdate($inventory); $this->scheduleDelayedBlockUpdate($blockPosition, 1); } }