mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-09 15:29:47 +00:00
Allow blocks to respond to the contents of their containers being updated
turns out relying on scheduled updates for this was a bad idea, since it causes a lot of unnecessary code to run every tick, as well as being problematic for campfire, which doesn't have any blockstates to compare against.
This commit is contained in:
parent
40574be333
commit
4850bd5538
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 [];
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user