mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-10 19:48:13 +00:00
Compare commits
21 Commits
4.1.0-BETA
...
4.1.0-BETA
Author | SHA1 | Date | |
---|---|---|---|
1d2593208a | |||
a7bdef69e2 | |||
d9ea647925 | |||
822af4f7f5 | |||
3155c90396 | |||
1dbfedce4c | |||
3ab5b5a79d | |||
8a4bc72b34 | |||
6cbc14f2b2 | |||
75d0fc4749 | |||
ea161af4e5 | |||
0bf5f97fe9 | |||
b9f1bcf0e4 | |||
32b07e0940 | |||
99f087e5e1 | |||
22a4117109 | |||
aaf7a88de7 | |||
e0da99a973 | |||
b2630a0920 | |||
67a0ae0246 | |||
5ae20459dd |
@ -1620,3 +1620,10 @@ Released 21st January 2022.
|
||||
- Fixed ender pearls teleporting players when thrown by a player directly against a wall when cancelling `ProjectileLaunchEvent`.
|
||||
- Fixed collision box of brewing stand.
|
||||
- Fixed break times and tool types of bamboo, nether wart blocks, infested stone and leaves.
|
||||
|
||||
# 4.0.8
|
||||
Released 25th January 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe.
|
||||
- The correct amount of fall damage is now taken when falling from a height onto hay bales.
|
||||
|
@ -115,3 +115,52 @@ Released 22nd January 2022.
|
||||
|
||||
### Misc
|
||||
- Implemented player swimming.
|
||||
|
||||
# 4.1.0-BETA2
|
||||
Released 27th January 2022.
|
||||
|
||||
## API
|
||||
### Block
|
||||
- The following API methods have been added:
|
||||
- `utils\BrewingStandSlot->getSlotNumber() : int`
|
||||
- `utils\FurnaceType->getCookSound() : Sound`
|
||||
- The following API constants have been added:
|
||||
- `tile\BrewingStand::BREW_TIME_TICKS`
|
||||
|
||||
### Crafting
|
||||
- The following API methods have been added:
|
||||
- `CraftingManager->getPotionContainerChangeRecipes() : array<int, array<string, PotionContainerChangeRecipe>>`
|
||||
- `CraftingManager->getPotionTypeRecipes() : array<string, array<string, PotionTypeRecipe>>`
|
||||
- `CraftingManager->registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void`
|
||||
- `CraftingManager->registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void`
|
||||
- The following classes have been added:
|
||||
- `BrewingRecipe`
|
||||
- `PotionContainerChangeRecipe`
|
||||
- `PotionTypeRecipe`
|
||||
|
||||
### Event
|
||||
- The following classes have been added:
|
||||
- `BrewItemEvent` - called when a brewing stand finishes brewing potions; this is called up to 3 times (once for each brewing slot, as needed)
|
||||
- `BrewingFuelUseEvent` - called when a brewing stand consumes blaze powder
|
||||
- `PlayerViewDistanceChangeEvent` - called whenever a player alters their render distance or requests one for the first time when connecting
|
||||
|
||||
### World
|
||||
#### Sound
|
||||
- The following classes have been added:
|
||||
- `BlastFurnaceSound` - the sound made by a blast furnace during smelting
|
||||
- `FurnaceSound` - the sound made by a regular furnace during cooking or smelting
|
||||
- `PotionFinishBrewingSound` - the sound made by a brewing stand when a potion finishes being brewed
|
||||
- `SmokerSound` - the sound made by a smoker during cooking
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Brewing stands can now be used for brewing potions.
|
||||
- The visual appearance of a brewing stand now updates correctly when the contents of its inventory changes (adding/removing potions).
|
||||
- Added missing sounds for furnace, blast furnace and smoker.
|
||||
- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe.
|
||||
- Cobwebs now drop themselves when mined using shears.
|
||||
- The correct amount of fall damage is now taken when falling from a height onto hay bales.
|
||||
- Fixed block updating bug introduced by beta1 which caused crops and other plants to never grow.
|
||||
|
||||
### Misc
|
||||
- Added a workaround for client hitbox size bug after swimming which caused the player to be able to fit into one-block-tall gaps.
|
||||
|
@ -41,7 +41,7 @@
|
||||
"pocketmine/classloader": "^0.2.0",
|
||||
"pocketmine/color": "^0.2.0",
|
||||
"pocketmine/errorhandler": "^0.6.0",
|
||||
"pocketmine/locale-data": "~2.3.0",
|
||||
"pocketmine/locale-data": "~2.4.2",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/log-pthreads": "^0.4.0",
|
||||
"pocketmine/math": "^0.4.0",
|
||||
|
26
composer.lock
generated
26
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "292d4bf59374d46e1ae84272f0abd522",
|
||||
"content-hash": "9aa2f11ba68d00423732973554fafb20",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -536,16 +536,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/locale-data",
|
||||
"version": "2.3.33",
|
||||
"version": "2.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Language.git",
|
||||
"reference": "44998ca9c055f872a33e59cd4d2736d081ba84b5"
|
||||
"reference": "4d0b081f1a79407e087968ea76aaf330db6ea2b5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/44998ca9c055f872a33e59cd4d2736d081ba84b5",
|
||||
"reference": "44998ca9c055f872a33e59cd4d2736d081ba84b5",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/4d0b081f1a79407e087968ea76aaf330db6ea2b5",
|
||||
"reference": "4d0b081f1a79407e087968ea76aaf330db6ea2b5",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -553,9 +553,9 @@
|
||||
"description": "Language resources used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/Language/issues",
|
||||
"source": "https://github.com/pmmp/Language/tree/2.3.33"
|
||||
"source": "https://github.com/pmmp/Language/tree/2.4.3"
|
||||
},
|
||||
"time": "2022-01-16T22:08:04+00:00"
|
||||
"time": "2022-01-25T23:18:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/log",
|
||||
@ -2389,16 +2389,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.5.12",
|
||||
"version": "9.5.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256"
|
||||
"reference": "597cb647654ede35e43b137926dfdfef0fb11743"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/93d4bf4c37aec6384bb9e5d390d9049a463a7256",
|
||||
"reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/597cb647654ede35e43b137926dfdfef0fb11743",
|
||||
"reference": "597cb647654ede35e43b137926dfdfef0fb11743",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2476,7 +2476,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.12"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.13"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2488,7 +2488,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-21T05:54:47+00:00"
|
||||
"time": "2022-01-24T07:33:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "4.1.0-BETA1";
|
||||
public const BASE_VERSION = "4.1.0-BETA2";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "beta";
|
||||
|
||||
|
@ -398,35 +398,42 @@ class BlockFactory{
|
||||
|
||||
//TODO: in the future this won't be the same for all the types
|
||||
$stoneSlabBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_BRICK), "Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_COBBLESTONE), "Cobblestone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_FAKE_WOODEN), "Fake Wooden", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_NETHER_BRICK), "Nether Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_QUARTZ), "Quartz", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_SANDSTONE), "Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_SMOOTH_STONE), "Smooth Stone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_STONE_BRICK), "Stone Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_DARK_PRISMARINE), "Dark Prismarine", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_MOSSY_COBBLESTONE), "Mossy Cobblestone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_PRISMARINE), "Prismarine", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_PRISMARINE_BRICKS), "Prismarine Bricks", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_PURPUR), "Purpur", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_RED_NETHER_BRICK), "Red Nether Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_RED_SANDSTONE), "Red Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_SMOOTH_SANDSTONE), "Smooth Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_ANDESITE), "Andesite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_DIORITE), "Diorite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_END_STONE_BRICK), "End Stone Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_GRANITE), "Granite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_POLISHED_ANDESITE), "Polished Andesite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_POLISHED_DIORITE), "Polished Diorite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_POLISHED_GRANITE), "Polished Granite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_SMOOTH_RED_SANDSTONE), "Smooth Red Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_CUT_RED_SANDSTONE), "Cut Red Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_CUT_SANDSTONE), "Cut Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_MOSSY_STONE_BRICK), "Mossy Stone Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_SMOOTH_QUARTZ), "Smooth Quartz", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_STONE), "Stone", $stoneSlabBreakInfo));
|
||||
|
||||
$getStoneSlabId = static fn(int $stoneSlabId, int $meta) => BlockLegacyIdHelper::getStoneSlabIdentifier($stoneSlabId, $meta);
|
||||
foreach([
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_BRICK), "Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_COBBLESTONE), "Cobblestone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_FAKE_WOODEN), "Fake Wooden", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_NETHER_BRICK), "Nether Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_QUARTZ), "Quartz", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_SANDSTONE), "Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_SMOOTH_STONE), "Smooth Stone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_STONE_BRICK), "Stone Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_DARK_PRISMARINE), "Dark Prismarine", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_MOSSY_COBBLESTONE), "Mossy Cobblestone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_PRISMARINE), "Prismarine", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_PRISMARINE_BRICKS), "Prismarine Bricks", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_PURPUR), "Purpur", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_RED_NETHER_BRICK), "Red Nether Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_RED_SANDSTONE), "Red Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_SMOOTH_SANDSTONE), "Smooth Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_ANDESITE), "Andesite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_DIORITE), "Diorite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_END_STONE_BRICK), "End Stone Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_GRANITE), "Granite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_POLISHED_ANDESITE), "Polished Andesite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_POLISHED_DIORITE), "Polished Diorite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_POLISHED_GRANITE), "Polished Granite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_SMOOTH_RED_SANDSTONE), "Smooth Red Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_CUT_RED_SANDSTONE), "Cut Red Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_CUT_SANDSTONE), "Cut Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_MOSSY_STONE_BRICK), "Mossy Stone Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_SMOOTH_QUARTZ), "Smooth Quartz", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_STONE), "Stone", $stoneSlabBreakInfo),
|
||||
] as $slabType){
|
||||
$this->registerSlabWithDoubleHighBitsRemapping($slabType);
|
||||
}
|
||||
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::STONECUTTER, 0), "Stonecutter", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant()));
|
||||
|
@ -125,6 +125,24 @@ class BrewingStand extends Transparent{
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
//TODO
|
||||
$brewing = $this->position->getWorld()->getTile($this->position);
|
||||
if($brewing instanceof TileBrewingStand){
|
||||
if($brewing->onUpdate()){
|
||||
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1);
|
||||
}
|
||||
|
||||
$changed = false;
|
||||
foreach(BrewingStandSlot::getAll() as $slot){
|
||||
$occupied = !$brewing->getInventory()->isSlotEmpty($slot->getSlotNumber());
|
||||
if($occupied !== $this->hasSlot($slot)){
|
||||
$this->setSlot($slot, $occupied);
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($changed){
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,9 @@ class Cobweb extends Flowable{
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0){
|
||||
return [$this->asItem()];
|
||||
}
|
||||
return [
|
||||
VanillaItems::STRING()
|
||||
];
|
||||
|
@ -66,4 +66,8 @@ class EnderChest extends Transparent{
|
||||
VanillaBlocks::OBSIDIAN()->asItem()->setCount(8)
|
||||
];
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use function mt_rand;
|
||||
|
||||
class Furnace extends Opaque{
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
@ -84,6 +85,9 @@ class Furnace extends Opaque{
|
||||
public function onScheduledUpdate() : void{
|
||||
$furnace = $this->position->getWorld()->getTile($this->position);
|
||||
if($furnace instanceof TileFurnace && $furnace->onUpdate()){
|
||||
if(mt_rand(1, 60) === 1){ //in vanilla this is between 1 and 5 seconds; try to average about 3
|
||||
$this->position->getWorld()->addSound($this->position, $furnace->getFurnaceType()->getCookSound());
|
||||
}
|
||||
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); //TODO: check this
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\PillarRotationInMetadataTrait;
|
||||
use pocketmine\entity\Entity;
|
||||
|
||||
class HayBale extends Opaque{
|
||||
use PillarRotationInMetadataTrait;
|
||||
@ -35,4 +36,9 @@ class HayBale extends Opaque{
|
||||
public function getFlammability() : int{
|
||||
return 20;
|
||||
}
|
||||
|
||||
public function onEntityLand(Entity $entity) : ?float{
|
||||
$entity->fallDistance *= 0.2;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -24,16 +24,29 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\inventory\BrewingStandInventory;
|
||||
use pocketmine\crafting\BrewingRecipe;
|
||||
use pocketmine\event\block\BrewingFuelUseEvent;
|
||||
use pocketmine\event\block\BrewItemEvent;
|
||||
use pocketmine\inventory\CallbackInventoryListener;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\PotionFinishBrewingSound;
|
||||
use pocketmine\world\World;
|
||||
use function array_map;
|
||||
use function count;
|
||||
|
||||
class BrewingStand extends Spawnable implements Container, Nameable{
|
||||
|
||||
use NameableTrait {
|
||||
addAdditionalSpawnData as addNameSpawnData;
|
||||
}
|
||||
use ContainerTrait;
|
||||
use NameableTrait;
|
||||
|
||||
public const BREW_TIME_TICKS = 400; // Brew time in ticks
|
||||
|
||||
private const TAG_BREW_TIME = "BrewTime"; //TAG_Short
|
||||
private const TAG_BREW_TIME_PE = "CookTime"; //TAG_Short
|
||||
@ -41,15 +54,11 @@ class BrewingStand extends Spawnable implements Container, Nameable{
|
||||
private const TAG_REMAINING_FUEL_TIME = "Fuel"; //TAG_Byte
|
||||
private const TAG_REMAINING_FUEL_TIME_PE = "FuelAmount"; //TAG_Short
|
||||
|
||||
/** @var BrewingStandInventory */
|
||||
private $inventory;
|
||||
private BrewingStandInventory $inventory;
|
||||
|
||||
/** @var int */
|
||||
private $brewTime = 0;
|
||||
/** @var int */
|
||||
private $maxFuelTime = 0;
|
||||
/** @var int */
|
||||
private $remainingFuelTime = 0;
|
||||
private int $brewTime = 0;
|
||||
private int $maxFuelTime = 0;
|
||||
private int $remainingFuelTime = 0;
|
||||
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
@ -83,6 +92,14 @@ class BrewingStand extends Spawnable implements Container, Nameable{
|
||||
$nbt->setShort(self::TAG_REMAINING_FUEL_TIME_PE, $this->remainingFuelTime);
|
||||
}
|
||||
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
$this->addNameSpawnData($nbt);
|
||||
|
||||
$nbt->setShort(self::TAG_BREW_TIME_PE, $this->brewTime);
|
||||
$nbt->setShort(self::TAG_MAX_FUEL_TIME, $this->maxFuelTime);
|
||||
$nbt->setShort(self::TAG_REMAINING_FUEL_TIME_PE, $this->remainingFuelTime);
|
||||
}
|
||||
|
||||
public function getDefaultName() : string{
|
||||
return "Brewing Stand";
|
||||
}
|
||||
@ -108,4 +125,135 @@ class BrewingStand extends Spawnable implements Container, Nameable{
|
||||
public function getRealInventory(){
|
||||
return $this->inventory;
|
||||
}
|
||||
|
||||
private function checkFuel(Item $item) : void{
|
||||
$ev = new BrewingFuelUseEvent($this);
|
||||
if(!$item->equals(VanillaItems::BLAZE_POWDER(), true, false)){
|
||||
$ev->cancel();
|
||||
}
|
||||
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
}
|
||||
|
||||
$item->pop();
|
||||
$this->inventory->setItem(BrewingStandInventory::SLOT_FUEL, $item);
|
||||
|
||||
$this->maxFuelTime = $this->remainingFuelTime = $ev->getFuelTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BrewingRecipe[]
|
||||
* @phpstan-return array<int, BrewingRecipe>
|
||||
*/
|
||||
private function getBrewableRecipes() : array{
|
||||
if($this->inventory->getItem(BrewingStandInventory::SLOT_INGREDIENT)->isNull()){
|
||||
return [];
|
||||
}
|
||||
|
||||
$recipes = [];
|
||||
foreach([BrewingStandInventory::SLOT_BOTTLE_LEFT, BrewingStandInventory::SLOT_BOTTLE_MIDDLE, BrewingStandInventory::SLOT_BOTTLE_RIGHT] as $slot){
|
||||
$input = $this->inventory->getItem($slot);
|
||||
if($input->isNull()){
|
||||
continue;
|
||||
}
|
||||
|
||||
if(($recipe = $this->position->getWorld()->getServer()->getCraftingManager()->matchBrewingRecipe($input, $this->inventory->getItem(BrewingStandInventory::SLOT_INGREDIENT))) !== null){
|
||||
$recipes[$slot] = $recipe;
|
||||
}
|
||||
}
|
||||
|
||||
return $recipes;
|
||||
}
|
||||
|
||||
public function onUpdate() : bool{
|
||||
if($this->closed){
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->timings->startTiming();
|
||||
|
||||
$prevBrewTime = $this->brewTime;
|
||||
$prevRemainingFuelTime = $this->remainingFuelTime;
|
||||
$prevMaxFuelTime = $this->maxFuelTime;
|
||||
|
||||
$ret = false;
|
||||
|
||||
$fuel = $this->inventory->getItem(BrewingStandInventory::SLOT_FUEL);
|
||||
$ingredient = $this->inventory->getItem(BrewingStandInventory::SLOT_INGREDIENT);
|
||||
|
||||
$recipes = $this->getBrewableRecipes();
|
||||
$canBrew = count($recipes) !== 0;
|
||||
|
||||
if($this->remainingFuelTime <= 0 && $canBrew){
|
||||
$this->checkFuel($fuel);
|
||||
}
|
||||
|
||||
if($this->remainingFuelTime > 0){
|
||||
if($canBrew){
|
||||
if($this->brewTime === 0){
|
||||
$this->brewTime = self::BREW_TIME_TICKS;
|
||||
--$this->remainingFuelTime;
|
||||
}
|
||||
|
||||
--$this->brewTime;
|
||||
|
||||
if($this->brewTime <= 0){
|
||||
$anythingBrewed = false;
|
||||
foreach($recipes as $slot => $recipe){
|
||||
$input = $this->inventory->getItem($slot);
|
||||
$output = $recipe->getResultFor($input);
|
||||
if($output === null){
|
||||
continue;
|
||||
}
|
||||
|
||||
$ev = new BrewItemEvent($this, $slot, $input, $output, $recipe);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->inventory->setItem($slot, $ev->getResult());
|
||||
$anythingBrewed = true;
|
||||
}
|
||||
|
||||
if($anythingBrewed){
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new PotionFinishBrewingSound());
|
||||
}
|
||||
|
||||
$ingredient->pop();
|
||||
$this->inventory->setItem(BrewingStandInventory::SLOT_INGREDIENT, $ingredient);
|
||||
|
||||
$this->brewTime = 0;
|
||||
}else{
|
||||
$ret = true;
|
||||
}
|
||||
}else{
|
||||
$this->brewTime = 0;
|
||||
}
|
||||
}else{
|
||||
$this->brewTime = $this->remainingFuelTime = $this->maxFuelTime = 0;
|
||||
}
|
||||
|
||||
$viewers = array_map(fn(Player $p) => $p->getNetworkSession()->getInvManager(), $this->inventory->getViewers());
|
||||
foreach($viewers as $v){
|
||||
if($v === null){
|
||||
continue;
|
||||
}
|
||||
if($prevBrewTime !== $this->brewTime){
|
||||
$v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_BREWING_STAND_BREW_TIME, $this->brewTime);
|
||||
}
|
||||
if($prevRemainingFuelTime !== $this->remainingFuelTime){
|
||||
$v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_BREWING_STAND_FUEL_AMOUNT, $this->remainingFuelTime);
|
||||
}
|
||||
if($prevMaxFuelTime !== $this->maxFuelTime){
|
||||
$v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_BREWING_STAND_FUEL_TOTAL, $this->maxFuelTime);
|
||||
}
|
||||
}
|
||||
|
||||
$this->timings->stopTiming();
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\block\inventory\BrewingStandInventory;
|
||||
use pocketmine\utils\EnumTrait;
|
||||
|
||||
/**
|
||||
@ -36,13 +37,24 @@ use pocketmine\utils\EnumTrait;
|
||||
* @method static BrewingStandSlot SOUTHWEST()
|
||||
*/
|
||||
final class BrewingStandSlot{
|
||||
use EnumTrait;
|
||||
use EnumTrait {
|
||||
__construct as Enum___construct;
|
||||
}
|
||||
|
||||
protected static function setup() : void{
|
||||
self::registerAll(
|
||||
new self("east"),
|
||||
new self("northwest"),
|
||||
new self("southwest")
|
||||
new self("east", BrewingStandInventory::SLOT_BOTTLE_LEFT),
|
||||
new self("northwest", BrewingStandInventory::SLOT_BOTTLE_MIDDLE),
|
||||
new self("southwest", BrewingStandInventory::SLOT_BOTTLE_RIGHT)
|
||||
);
|
||||
}
|
||||
|
||||
private function __construct(string $enumName, private int $slotNumber){
|
||||
$this->Enum___construct($enumName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the brewing stand inventory slot number associated with this visual slot.
|
||||
*/
|
||||
public function getSlotNumber() : int{ return $this->slotNumber; }
|
||||
}
|
||||
|
30
src/crafting/BrewingRecipe.php
Normal file
30
src/crafting/BrewingRecipe.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
interface BrewingRecipe{
|
||||
public function getResultFor(Item $input) : ?Item;
|
||||
}
|
@ -45,6 +45,18 @@ class CraftingManager{
|
||||
*/
|
||||
protected $furnaceRecipeManagers;
|
||||
|
||||
/**
|
||||
* @var PotionTypeRecipe[][]
|
||||
* @phpstan-var array<string, array<string, PotionTypeRecipe>>
|
||||
*/
|
||||
protected $potionTypeRecipes = [];
|
||||
|
||||
/**
|
||||
* @var PotionContainerChangeRecipe[][]
|
||||
* @phpstan-var array<int, array<string, PotionContainerChangeRecipe>>
|
||||
*/
|
||||
protected $potionContainerChangeRecipes = [];
|
||||
|
||||
/**
|
||||
* @var ObjectSet
|
||||
* @phpstan-var ObjectSet<\Closure() : void>
|
||||
@ -140,6 +152,22 @@ class CraftingManager{
|
||||
return $this->furnaceRecipeManagers[$furnaceType->id()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PotionTypeRecipe[][]
|
||||
* @phpstan-return array<string, array<string, PotionTypeRecipe>>
|
||||
*/
|
||||
public function getPotionTypeRecipes() : array{
|
||||
return $this->potionTypeRecipes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PotionContainerChangeRecipe[][]
|
||||
* @phpstan-return array<int, array<string, PotionContainerChangeRecipe>>
|
||||
*/
|
||||
public function getPotionContainerChangeRecipes() : array{
|
||||
return $this->potionContainerChangeRecipes;
|
||||
}
|
||||
|
||||
public function registerShapedRecipe(ShapedRecipe $recipe) : void{
|
||||
$this->shapedRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;
|
||||
|
||||
@ -156,6 +184,25 @@ class CraftingManager{
|
||||
}
|
||||
}
|
||||
|
||||
public function registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void{
|
||||
$input = $recipe->getInput();
|
||||
$ingredient = $recipe->getIngredient();
|
||||
$this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":" . ($ingredient->hasAnyDamageValue() ? "?" : $ingredient->getMeta())] = $recipe;
|
||||
|
||||
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||
$callback();
|
||||
}
|
||||
}
|
||||
|
||||
public function registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void{
|
||||
$ingredient = $recipe->getIngredient();
|
||||
$this->potionContainerChangeRecipes[$recipe->getInputItemId()][$ingredient->getId() . ":" . ($ingredient->hasAnyDamageValue() ? "?" : $ingredient->getMeta())] = $recipe;
|
||||
|
||||
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||
$callback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item[] $outputs
|
||||
*/
|
||||
@ -206,4 +253,11 @@ class CraftingManager{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function matchBrewingRecipe(Item $input, Item $ingredient) : ?BrewingRecipe{
|
||||
return $this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":" . $ingredient->getMeta()] ??
|
||||
$this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":?"] ??
|
||||
$this->potionContainerChangeRecipes[$input->getId()][$ingredient->getId() . ":" . $ingredient->getMeta()] ??
|
||||
$this->potionContainerChangeRecipes[$input->getId()][$ingredient->getId() . ":?"] ?? null;
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,20 @@ final class CraftingManagerFromDataHelper{
|
||||
Item::jsonDeserialize($recipe["input"]))
|
||||
);
|
||||
}
|
||||
foreach($recipes["potion_type"] as $recipe){
|
||||
$result->registerPotionTypeRecipe(new PotionTypeRecipe(
|
||||
Item::jsonDeserialize($recipe["input"]),
|
||||
Item::jsonDeserialize($recipe["ingredient"]),
|
||||
Item::jsonDeserialize($recipe["output"])
|
||||
));
|
||||
}
|
||||
foreach($recipes["potion_container_change"] as $recipe){
|
||||
$result->registerPotionContainerChangeRecipe(new PotionContainerChangeRecipe(
|
||||
$recipe["input_item_id"],
|
||||
Item::jsonDeserialize($recipe["ingredient"]),
|
||||
$recipe["output_item_id"]
|
||||
));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
@ -24,6 +24,10 @@ declare(strict_types=1);
|
||||
namespace pocketmine\crafting;
|
||||
|
||||
use pocketmine\utils\EnumTrait;
|
||||
use pocketmine\world\sound\BlastFurnaceSound;
|
||||
use pocketmine\world\sound\FurnaceSound;
|
||||
use pocketmine\world\sound\SmokerSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
|
||||
/**
|
||||
* This doc-block is generated automatically, do not modify it manually.
|
||||
@ -42,15 +46,17 @@ final class FurnaceType{
|
||||
|
||||
protected static function setup() : void{
|
||||
self::registerAll(
|
||||
new self("furnace", 200),
|
||||
new self("blast_furnace", 100),
|
||||
new self("smoker", 100),
|
||||
new self("furnace", 200, new FurnaceSound()),
|
||||
new self("blast_furnace", 100, new BlastFurnaceSound()),
|
||||
new self("smoker", 100, new SmokerSound()),
|
||||
);
|
||||
}
|
||||
|
||||
private function __construct(string $enumName, private int $cookDurationTicks){
|
||||
private function __construct(string $enumName, private int $cookDurationTicks, private Sound $cookSound){
|
||||
$this->Enum___construct($enumName);
|
||||
}
|
||||
|
||||
public function getCookDurationTicks() : int{ return $this->cookDurationTicks; }
|
||||
|
||||
public function getCookSound() : Sound{ return $this->cookSound; }
|
||||
}
|
||||
|
54
src/crafting/PotionContainerChangeRecipe.php
Normal file
54
src/crafting/PotionContainerChangeRecipe.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
|
||||
class PotionContainerChangeRecipe implements BrewingRecipe{
|
||||
|
||||
public function __construct(
|
||||
private int $inputItemId,
|
||||
private Item $ingredient,
|
||||
private int $outputItemId
|
||||
){
|
||||
$this->ingredient = clone $ingredient;
|
||||
}
|
||||
|
||||
public function getInputItemId() : int{
|
||||
return $this->inputItemId;
|
||||
}
|
||||
|
||||
public function getIngredient() : Item{
|
||||
return clone $this->ingredient;
|
||||
}
|
||||
|
||||
public function getOutputItemId() : int{
|
||||
return $this->outputItemId;
|
||||
}
|
||||
|
||||
public function getResultFor(Item $input) : ?Item{
|
||||
return $input->getId() === $this->getInputItemId() ? ItemFactory::getInstance()->get($this->getOutputItemId(), $input->getMeta()) : null;
|
||||
}
|
||||
}
|
55
src/crafting/PotionTypeRecipe.php
Normal file
55
src/crafting/PotionTypeRecipe.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class PotionTypeRecipe implements BrewingRecipe{
|
||||
|
||||
public function __construct(
|
||||
private Item $input,
|
||||
private Item $ingredient,
|
||||
private Item $output
|
||||
){
|
||||
$this->input = clone $input;
|
||||
$this->ingredient = clone $ingredient;
|
||||
$this->output = clone $output;
|
||||
}
|
||||
|
||||
public function getInput() : Item{
|
||||
return clone $this->input;
|
||||
}
|
||||
|
||||
public function getIngredient() : Item{
|
||||
return clone $this->ingredient;
|
||||
}
|
||||
|
||||
public function getOutput() : Item{
|
||||
return clone $this->output;
|
||||
}
|
||||
|
||||
public function getResultFor(Item $input) : ?Item{
|
||||
return $input->equals($this->input, true, false) ? $this->getOutput() : null;
|
||||
}
|
||||
}
|
71
src/event/block/BrewItemEvent.php
Normal file
71
src/event/block/BrewItemEvent.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event\block;
|
||||
|
||||
use pocketmine\block\tile\BrewingStand;
|
||||
use pocketmine\crafting\BrewingRecipe;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class BrewItemEvent extends BlockEvent implements Cancellable{
|
||||
use CancellableTrait;
|
||||
|
||||
public function __construct(
|
||||
private BrewingStand $brewingStand,
|
||||
private int $slot,
|
||||
private Item $input,
|
||||
private Item $result,
|
||||
private BrewingRecipe $recipe
|
||||
){
|
||||
parent::__construct($brewingStand->getBlock());
|
||||
}
|
||||
|
||||
public function getBrewingStand() : BrewingStand{
|
||||
return $this->brewingStand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which slot of the brewing stand's inventory the potion is in.
|
||||
*/
|
||||
public function getSlot() : int{
|
||||
return $this->slot;
|
||||
}
|
||||
|
||||
public function getInput() : Item{
|
||||
return clone $this->input;
|
||||
}
|
||||
|
||||
public function getResult() : Item{
|
||||
return clone $this->result;
|
||||
}
|
||||
|
||||
public function setResult(Item $result) : void{
|
||||
$this->result = clone $result;
|
||||
}
|
||||
|
||||
public function getRecipe() : BrewingRecipe{
|
||||
return $this->recipe;
|
||||
}
|
||||
}
|
64
src/event/block/BrewingFuelUseEvent.php
Normal file
64
src/event/block/BrewingFuelUseEvent.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event\block;
|
||||
|
||||
use pocketmine\block\tile\BrewingStand;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
|
||||
/**
|
||||
* Called when a brewing stand consumes a new fuel item.
|
||||
*/
|
||||
class BrewingFuelUseEvent extends BlockEvent implements Cancellable{
|
||||
use CancellableTrait;
|
||||
|
||||
private int $fuelTime = 20;
|
||||
|
||||
public function __construct(
|
||||
private BrewingStand $brewingStand
|
||||
){
|
||||
parent::__construct($brewingStand->getBlock());
|
||||
}
|
||||
|
||||
public function getBrewingStand() : BrewingStand{
|
||||
return $this->brewingStand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how many times the fuel can be used for potion brewing before it runs out.
|
||||
*/
|
||||
public function getFuelTime() : int{
|
||||
return $this->fuelTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many times the fuel can be used for potion brewing before it runs out.
|
||||
*/
|
||||
public function setFuelTime(int $fuelTime) : void{
|
||||
if($fuelTime <= 0){
|
||||
throw new \InvalidArgumentException("Fuel time must be positive");
|
||||
}
|
||||
$this->fuelTime = $fuelTime;
|
||||
}
|
||||
}
|
55
src/event/player/PlayerViewDistanceChangeEvent.php
Normal file
55
src/event/player/PlayerViewDistanceChangeEvent.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event\player;
|
||||
|
||||
use pocketmine\player\Player;
|
||||
|
||||
/**
|
||||
* Called when a player requests a different viewing distance than the current one.
|
||||
*/
|
||||
class PlayerViewDistanceChangeEvent extends PlayerEvent{
|
||||
protected int $newDistance;
|
||||
protected int $oldDistance;
|
||||
|
||||
public function __construct(Player $player, int $oldDistance, int $newDistance){
|
||||
$this->player = $player;
|
||||
$this->oldDistance = $oldDistance;
|
||||
$this->newDistance = $newDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new view radius, measured in chunks.
|
||||
*/
|
||||
public function getNewDistance() : int{
|
||||
return $this->newDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the old view radius, measured in chunks.
|
||||
* A value of -1 means that the player has just connected and did not have a view distance before this event.
|
||||
*/
|
||||
public function getOldDistance() : int{
|
||||
return $this->oldDistance;
|
||||
}
|
||||
}
|
37
src/network/mcpe/cache/CraftingDataCache.php
vendored
37
src/network/mcpe/cache/CraftingDataCache.php
vendored
@ -26,12 +26,15 @@ namespace pocketmine\network\mcpe\cache;
|
||||
use pocketmine\crafting\CraftingManager;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\convert\ItemTranslator;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\CraftingRecipeBlockName;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe as ProtocolFurnaceRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipeBlockName;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\PotionContainerChangeRecipe as ProtocolPotionContainerChangeRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\PotionTypeRecipe as ProtocolPotionTypeRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\ShapedRecipe as ProtocolShapedRecipe;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\ShapelessRecipe as ProtocolShapelessRecipe;
|
||||
@ -137,7 +140,39 @@ final class CraftingDataCache{
|
||||
}
|
||||
}
|
||||
|
||||
$potionTypeRecipes = [];
|
||||
foreach($manager->getPotionTypeRecipes() as $recipes){
|
||||
foreach($recipes as $recipe){
|
||||
$input = $converter->coreItemStackToNet($recipe->getInput());
|
||||
$ingredient = $converter->coreItemStackToNet($recipe->getIngredient());
|
||||
$output = $converter->coreItemStackToNet($recipe->getOutput());
|
||||
$potionTypeRecipes[] = new ProtocolPotionTypeRecipe(
|
||||
$input->getId(),
|
||||
$input->getMeta(),
|
||||
$ingredient->getId(),
|
||||
$ingredient->getMeta(),
|
||||
$output->getId(),
|
||||
$output->getMeta()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$potionContainerChangeRecipes = [];
|
||||
$itemTranslator = ItemTranslator::getInstance();
|
||||
foreach($manager->getPotionContainerChangeRecipes() as $recipes){
|
||||
foreach($recipes as $recipe){
|
||||
$input = $itemTranslator->toNetworkId($recipe->getInputItemId(), 0);
|
||||
$ingredient = $itemTranslator->toNetworkId($recipe->getIngredient()->getId(), 0);
|
||||
$output = $itemTranslator->toNetworkId($recipe->getOutputItemId(), 0);
|
||||
$potionContainerChangeRecipes[] = new ProtocolPotionContainerChangeRecipe(
|
||||
$input[0],
|
||||
$ingredient[0],
|
||||
$output[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Timings::$craftingDataCacheRebuild->stopTiming();
|
||||
return CraftingDataPacket::create($recipesWithTypeIds, [], [], [], true);
|
||||
return CraftingDataPacket::create($recipesWithTypeIds, $potionTypeRecipes, $potionContainerChangeRecipes, [], true);
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,8 @@ use pocketmine\network\mcpe\protocol\SubClientLoginPacket;
|
||||
use pocketmine\network\mcpe\protocol\TextPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\ActorEvent;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\NetworkInventoryAction;
|
||||
@ -222,6 +224,11 @@ class InGamePacketHandler extends PacketHandler{
|
||||
($gliding !== null && !$this->player->toggleGlide($gliding));
|
||||
if((bool) $mismatch){
|
||||
$this->player->sendData([$this->player]);
|
||||
}elseif($packet->hasFlag(PlayerAuthInputFlags::STOP_SWIMMING) || $packet->hasFlag(PlayerAuthInputFlags::STOP_GLIDING)){
|
||||
//TODO: HACK! workaround for a client bug where the AABB doesn't change back properly when stopping swimming or gliding
|
||||
$this->player->sendData([$this->player], [
|
||||
EntityMetadataProperties::BOUNDING_BOX_HEIGHT => new FloatMetadataProperty($this->player->getSize()->getHeight())
|
||||
]);
|
||||
}
|
||||
|
||||
if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){
|
||||
|
@ -73,6 +73,7 @@ use pocketmine\event\player\PlayerToggleSneakEvent;
|
||||
use pocketmine\event\player\PlayerToggleSprintEvent;
|
||||
use pocketmine\event\player\PlayerToggleSwimEvent;
|
||||
use pocketmine\event\player\PlayerTransferEvent;
|
||||
use pocketmine\event\player\PlayerViewDistanceChangeEvent;
|
||||
use pocketmine\form\Form;
|
||||
use pocketmine\form\FormValidationException;
|
||||
use pocketmine\inventory\CallbackInventoryListener;
|
||||
@ -507,7 +508,14 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
}
|
||||
|
||||
public function setViewDistance(int $distance) : void{
|
||||
$this->viewDistance = $this->server->getAllowedViewDistance($distance);
|
||||
$newViewDistance = $this->server->getAllowedViewDistance($distance);
|
||||
|
||||
if($newViewDistance !== $this->viewDistance){
|
||||
$ev = new PlayerViewDistanceChangeEvent($this, $this->viewDistance, $newViewDistance);
|
||||
$ev->call();
|
||||
}
|
||||
|
||||
$this->viewDistance = $newViewDistance;
|
||||
|
||||
$this->spawnThreshold = (int) (min($this->viewDistance, $this->server->getConfigGroup()->getPropertyInt("chunk-sending.spawn-radius", 4)) ** 2 * M_PI);
|
||||
|
||||
|
@ -493,7 +493,7 @@ class World implements ChunkManager{
|
||||
|
||||
foreach(BlockFactory::getInstance()->getAllKnownStates() as $state){
|
||||
$dontTickName = $dontTickBlocks[$state->getTypeId()] ?? null;
|
||||
if($dontTickName === null && !$state->ticksRandomly()){
|
||||
if($dontTickName === null && $state->ticksRandomly()){
|
||||
$this->randomTickBlocks[$state->getFullId()] = true;
|
||||
}
|
||||
}
|
||||
@ -971,6 +971,8 @@ class World implements ChunkManager{
|
||||
public function createBlockUpdatePackets(array $blocks) : array{
|
||||
$packets = [];
|
||||
|
||||
$blockMapping = RuntimeBlockMapping::getInstance();
|
||||
|
||||
foreach($blocks as $b){
|
||||
if(!($b instanceof Vector3)){
|
||||
throw new \TypeError("Expected Vector3 in blocks array, got " . (is_object($b) ? get_class($b) : gettype($b)));
|
||||
@ -980,7 +982,7 @@ class World implements ChunkManager{
|
||||
$blockPosition = BlockPosition::fromVector3($b);
|
||||
$packets[] = UpdateBlockPacket::create(
|
||||
$blockPosition,
|
||||
RuntimeBlockMapping::getInstance()->toRuntimeId($fullBlock->getFullId()),
|
||||
$blockMapping->toRuntimeId($fullBlock->getFullId()),
|
||||
UpdateBlockPacket::FLAG_NETWORK,
|
||||
UpdateBlockPacket::DATA_LAYER_NORMAL
|
||||
);
|
||||
@ -1129,6 +1131,7 @@ class World implements ChunkManager{
|
||||
$entity->onRandomUpdate();
|
||||
}
|
||||
|
||||
$blockFactory = BlockFactory::getInstance();
|
||||
foreach($chunk->getSubChunks() as $Y => $subChunk){
|
||||
if(!$subChunk->isEmptyFast()){
|
||||
$k = 0;
|
||||
@ -1145,8 +1148,7 @@ class World implements ChunkManager{
|
||||
$state = $subChunk->getFullBlock($x, $y, $z);
|
||||
|
||||
if(isset($this->randomTickBlocks[$state])){
|
||||
/** @var Block $block */
|
||||
$block = BlockFactory::getInstance()->fromFullBlock($state);
|
||||
$block = $blockFactory->fromFullBlock($state);
|
||||
$block->position($this, $chunkX * Chunk::EDGE_LENGTH + $x, ($Y << SubChunk::COORD_BIT_SIZE) + $y, $chunkZ * Chunk::EDGE_LENGTH + $z);
|
||||
$block->onRandomTick();
|
||||
}
|
||||
|
35
src/world/sound/BlastFurnaceSound.php
Normal file
35
src/world/sound/BlastFurnaceSound.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\sound;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
|
||||
|
||||
final class BlastFurnaceSound implements Sound{
|
||||
|
||||
public function encode(Vector3 $pos) : array{
|
||||
return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BLOCK_BLASTFURNACE_FIRE_CRACKLE, $pos, false)];
|
||||
}
|
||||
}
|
35
src/world/sound/FurnaceSound.php
Normal file
35
src/world/sound/FurnaceSound.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\sound;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
|
||||
|
||||
final class FurnaceSound implements Sound{
|
||||
|
||||
public function encode(Vector3 $pos) : array{
|
||||
return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BLOCK_FURNACE_LIT, $pos, false)];
|
||||
}
|
||||
}
|
35
src/world/sound/PotionFinishBrewingSound.php
Normal file
35
src/world/sound/PotionFinishBrewingSound.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\sound;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
|
||||
|
||||
final class PotionFinishBrewingSound implements Sound{
|
||||
|
||||
public function encode(Vector3 $pos) : array{
|
||||
return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::POTION_BREWED, $pos, false)];
|
||||
}
|
||||
}
|
35
src/world/sound/SmokerSound.php
Normal file
35
src/world/sound/SmokerSound.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\sound;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
|
||||
|
||||
final class SmokerSound implements Sound{
|
||||
|
||||
public function encode(Vector3 $pos) : array{
|
||||
return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BLOCK_SMOKER_SMOKE, $pos, false)];
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user