mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-20 16:00:20 +00:00
implement waterlogged flow
This commit is contained in:
parent
3ec3be6b20
commit
7164dd9f49
@ -623,6 +623,9 @@ class Block{
|
||||
final public function position(World $world, int $x, int $y, int $z) : void{
|
||||
$this->position = new Position($x, $y, $z, $world);
|
||||
$this->collisionBoxes = null;
|
||||
if($this instanceof Waterloggable){
|
||||
$this->getWaterState()?->position($world, $x, $y, $z);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\MinimumCostFlowCalculator;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\block\utils\Waterloggable;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
@ -144,6 +145,9 @@ abstract class Liquid extends Transparent{
|
||||
}
|
||||
|
||||
protected function getEffectiveFlowDecay(Block $block) : int{
|
||||
if($block instanceof Waterloggable){
|
||||
$block = $block->getWaterState() ?? $block;
|
||||
}
|
||||
if(!($block instanceof Liquid) || !$block->hasSameTypeId($this)){
|
||||
return -1;
|
||||
}
|
||||
@ -181,6 +185,9 @@ abstract class Liquid extends Transparent{
|
||||
$sideZ = $z + $dz;
|
||||
|
||||
$sideBlock = $world->getBlockAt($sideX, $sideY, $sideZ);
|
||||
if($sideBlock instanceof Waterloggable){
|
||||
$sideBlock = $sideBlock->getWaterState() ?? $sideBlock;
|
||||
}
|
||||
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
|
||||
|
||||
if($blockDecay < 0){
|
||||
@ -292,14 +299,25 @@ abstract class Liquid extends Transparent{
|
||||
}
|
||||
|
||||
if($falling !== $this->falling || (!$falling && $newDecay !== $this->decay)){
|
||||
$actualBlock = $world->getBlockAt($x, $y, $z);
|
||||
if(!$falling && $newDecay < 0){
|
||||
$world->setBlockAt($x, $y, $z, VanillaBlocks::AIR());
|
||||
if($actualBlock instanceof Waterloggable && $this instanceof Water){
|
||||
$actualBlock->setWaterState(null);
|
||||
$world->setBlockAt($x, $y, $z, $actualBlock);
|
||||
}else{
|
||||
$world->setBlockAt($x, $y, $z, VanillaBlocks::AIR());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->falling = $falling;
|
||||
$this->decay = $falling ? 0 : $newDecay;
|
||||
$world->setBlockAt($x, $y, $z, $this); //local block update will cause an update to be scheduled
|
||||
if($actualBlock instanceof Waterloggable && $this instanceof Water){
|
||||
$actualBlock->setWaterState($this);
|
||||
$world->setBlockAt($x, $y, $z, $actualBlock);
|
||||
}else{
|
||||
$world->setBlockAt($x, $y, $z, $this); //local block update will cause an update to be scheduled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -347,6 +365,9 @@ abstract class Liquid extends Transparent{
|
||||
|
||||
/** @phpstan-impure */
|
||||
private function getSmallestFlowDecay(Block $block, int $decay) : int{
|
||||
if($block instanceof Waterloggable){
|
||||
$block = $block->getWaterState() ?? $block;
|
||||
}
|
||||
if(!($block instanceof Liquid) || !$block->hasSameTypeId($this)){
|
||||
return $decay;
|
||||
}
|
||||
@ -374,6 +395,9 @@ abstract class Liquid extends Transparent{
|
||||
}
|
||||
|
||||
protected function canFlowInto(Block $block) : bool{
|
||||
if($block instanceof Waterloggable){
|
||||
$block = $block->getWaterState() ?? $block;
|
||||
}
|
||||
return
|
||||
$this->position->getWorld()->isInWorld($block->position->x, $block->position->y, $block->position->z) &&
|
||||
$block->canBeFlowedInto() &&
|
||||
|
@ -30,7 +30,6 @@ use pocketmine\block\utils\Waterloggable;
|
||||
use pocketmine\block\utils\WaterloggableTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\LiquidBucket;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
@ -40,7 +39,9 @@ use pocketmine\world\BlockTransaction;
|
||||
|
||||
class Stair extends Transparent implements Waterloggable{
|
||||
use HorizontalFacingTrait;
|
||||
use WaterloggableTrait;
|
||||
use WaterloggableTrait {
|
||||
WaterloggableTrait::readStateFromWorld as private readWaterStateFromWorld;
|
||||
}
|
||||
|
||||
protected bool $upsideDown = false;
|
||||
protected StairShape $shape = StairShape::STRAIGHT;
|
||||
@ -52,6 +53,7 @@ class Stair extends Transparent implements Waterloggable{
|
||||
|
||||
public function readStateFromWorld() : Block{
|
||||
parent::readStateFromWorld();
|
||||
$this->readWaterStateFromWorld();
|
||||
|
||||
$this->collisionBoxes = null;
|
||||
|
||||
@ -135,15 +137,19 @@ class Stair extends Transparent implements Waterloggable{
|
||||
$this->facing = $player->getHorizontalFacing();
|
||||
}
|
||||
$this->upsideDown = (($clickVector->y > 0.5 && $face !== Facing::UP) || $face === Facing::DOWN);
|
||||
if($blockReplace instanceof Water && $blockReplace->isSource()){
|
||||
$this->waterState = $blockReplace;
|
||||
}
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof LiquidBucket && $item->getLiquid() instanceof Water){
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setWaterState($item->getLiquid()));
|
||||
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
$ret = parent::onBreak($item, $player, $returnedItems);
|
||||
if($this->waterState !== null){
|
||||
$this->position->getWorld()->setBlock($this->position, $this->waterState);
|
||||
}
|
||||
|
||||
return parent::onInteract($item, $face, $clickVector, $player, $returnedItems);
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
@ -37,4 +37,16 @@ trait WaterloggableTrait{
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function readStateFromWorld() : void{
|
||||
$this->waterState?->readStateFromWorld();
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$this->waterState?->onNearbyBlockChange();
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
$this->waterState?->onScheduledUpdate();
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\event\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\utils\Waterloggable;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
use pocketmine\event\Event;
|
||||
|
@ -26,10 +26,12 @@ namespace pocketmine\item;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockTypeIds;
|
||||
use pocketmine\block\Liquid;
|
||||
use pocketmine\block\utils\Waterloggable;
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
use pocketmine\event\player\PlayerBucketFillEvent;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use function var_dump;
|
||||
|
||||
class Bucket extends Item{
|
||||
|
||||
@ -39,11 +41,15 @@ class Bucket extends Item{
|
||||
|
||||
public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, array &$returnedItems) : ItemUseResult{
|
||||
//TODO: move this to generic placement logic
|
||||
if($blockClicked instanceof Liquid && $blockClicked->isSource()){
|
||||
if($blockClicked instanceof Liquid && $blockClicked->isSource() || $blockClicked instanceof Waterloggable && $blockClicked->getWaterState() !== null){
|
||||
$stack = clone $this;
|
||||
$stack->pop();
|
||||
|
||||
$resultItem = match($blockClicked->getTypeId()){
|
||||
$id = $blockClicked->getTypeId();
|
||||
if($blockClicked instanceof Waterloggable){
|
||||
$id = $blockClicked->getWaterState()->getTypeId();
|
||||
}
|
||||
$resultItem = match($id){
|
||||
BlockTypeIds::LAVA => VanillaItems::LAVA_BUCKET(),
|
||||
BlockTypeIds::WATER => VanillaItems::WATER_BUCKET(),
|
||||
default => null
|
||||
@ -55,8 +61,16 @@ class Bucket extends Item{
|
||||
$ev = new PlayerBucketFillEvent($player, $blockReplace, $face, $this, $resultItem);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$player->getWorld()->setBlock($blockClicked->getPosition(), VanillaBlocks::AIR());
|
||||
$player->getWorld()->addSound($blockClicked->getPosition()->add(0.5, 0.5, 0.5), $blockClicked->getBucketFillSound());
|
||||
if($blockClicked instanceof Waterloggable){
|
||||
var_dump("Setting water state", $blockClicked->__toString());
|
||||
$sound = $blockClicked->getWaterState()->getBucketFillSound();
|
||||
$blockClicked->setWaterState(null);
|
||||
$player->getWorld()->setBlock($blockClicked->getPosition(), $blockClicked);
|
||||
}else{
|
||||
$sound = $blockClicked->getBucketFillSound();
|
||||
$player->getWorld()->setBlock($blockClicked->getPosition(), VanillaBlocks::AIR());
|
||||
}
|
||||
$player->getWorld()->addSound($blockClicked->getPosition()->add(0.5, 0.5, 0.5), $sound);
|
||||
|
||||
$this->pop();
|
||||
$returnedItems[] = $ev->getItem();
|
||||
|
@ -26,9 +26,12 @@ namespace pocketmine\item;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\Lava;
|
||||
use pocketmine\block\Liquid;
|
||||
use pocketmine\block\utils\Waterloggable;
|
||||
use pocketmine\block\Water;
|
||||
use pocketmine\event\player\PlayerBucketEmptyEvent;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use function var_dump;
|
||||
|
||||
class LiquidBucket extends Item{
|
||||
private Liquid $liquid;
|
||||
@ -55,7 +58,7 @@ class LiquidBucket extends Item{
|
||||
}
|
||||
|
||||
public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, array &$returnedItems) : ItemUseResult{
|
||||
if(!$blockReplace->canBeReplaced()){
|
||||
if(!$blockReplace->canBeReplaced() && !($blockReplace instanceof Waterloggable)){
|
||||
return ItemUseResult::NONE;
|
||||
}
|
||||
|
||||
@ -65,7 +68,14 @@ class LiquidBucket extends Item{
|
||||
$ev = new PlayerBucketEmptyEvent($player, $blockReplace, $face, $this, VanillaItems::BUCKET());
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$player->getWorld()->setBlock($blockReplace->getPosition(), $resultBlock->getFlowingForm());
|
||||
if($blockClicked instanceof Waterloggable && $resultBlock instanceof Water){
|
||||
var_dump("Setting water state", $resultBlock->__toString());
|
||||
$blockClicked->setWaterState($resultBlock);
|
||||
$player->getWorld()->setBlock($blockClicked->getPosition(), $blockClicked);
|
||||
$blockClicked->onNearbyBlockChange();
|
||||
}else{
|
||||
$player->getWorld()->setBlock($blockReplace->getPosition(), $resultBlock->getFlowingForm());
|
||||
}
|
||||
$player->getWorld()->addSound($blockReplace->getPosition()->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
|
||||
|
||||
$this->pop();
|
||||
|
Loading…
x
Reference in New Issue
Block a user