Compare commits

..

21 Commits

Author SHA1 Message Date
1d2593208a Release 4.1.0-BETA2 2022-01-27 00:55:02 +00:00
a7bdef69e2 Merge remote-tracking branch 'origin/stable' into next-minor 2022-01-27 00:40:34 +00:00
d9ea647925 InGamePacketHandler: add a hack for swimming AABB client bug 2022-01-27 00:28:54 +00:00
822af4f7f5 Bump pocketmine/locale-data from 2.4.2 to 2.4.3 (#4773)
Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.4.2 to 2.4.3.
- [Release notes](https://github.com/pmmp/Language/releases)
- [Commits](https://github.com/pmmp/Language/compare/2.4.2...2.4.3)

---
updated-dependencies:
- dependency-name: pocketmine/locale-data
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-26 00:45:05 +00:00
3155c90396 Fixed incorrect drops for Cobweb (#4759) 2022-01-26 00:25:00 +00:00
1dbfedce4c Bump pocketmine/locale-data from 2.3.33 to 2.4.2 (#4769)
Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.3.33 to 2.4.2.
- [Release notes](https://github.com/pmmp/Language/releases)
- [Commits](https://github.com/pmmp/Language/compare/2.3.33...2.4.2)

---
updated-dependencies:
- dependency-name: pocketmine/locale-data
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-26 00:19:02 +00:00
3ab5b5a79d 4.0.9 is next 2022-01-25 23:33:24 +00:00
8a4bc72b34 Release 4.0.8 2022-01-25 23:33:20 +00:00
6cbc14f2b2 World: fixed block update bug introduced by 3faeb5a556 2022-01-25 21:53:15 +00:00
75d0fc4749 BlockFactory: Make stone slab registration a little less unpleasant to read 2022-01-25 19:23:04 +00:00
ea161af4e5 Added FurnaceType->getCookSound() 2022-01-25 19:01:49 +00:00
0bf5f97fe9 Implement furnace sound (#4755)
closes #4363 

The following classes have been added:
- BlastFurnaceSound
- SmokerSound
- FurnaceSound
2022-01-25 18:52:31 +00:00
b9f1bcf0e4 Implement PlayerViewDistanceChangeEvent (#4749)
closes #4550
2022-01-25 18:00:26 +00:00
32b07e0940 World: avoid repeated getInstance() calls in hot paths 2022-01-24 21:08:12 +00:00
99f087e5e1 Bump phpunit/phpunit from 9.5.12 to 9.5.13 (#4767)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.12 to 9.5.13.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.12...9.5.13)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-24 14:21:49 +00:00
22a4117109 Merge remote-tracking branch 'origin/stable' into next-minor 2022-01-23 15:47:13 +00:00
aaf7a88de7 HayBale: fixed fall damage 2022-01-22 21:26:44 +00:00
e0da99a973 feat: Implement Brewing (#4413)
The following API constants have been added:
- tile\BrewingStand::BREW_TIME_TICKS
The following public API methods have been added:
- utils\BrewingStandSlot->getSlotNumber() : int
- CraftingManager->getPotionTypeRecipes() : array<string, array<string, PotionTypeRecipe>>
- CraftingManager->getPotionContainerChangeRecipes() : array<int, array<string, PotionContainerChangeRecipe>>
- CraftingManager->registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void
- CraftingManager->registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void
The following classes have been added:
- BrewingRecipe
- PotionTypeRecipe
- PotionContainerChangeRecipe
- BrewItemEvent
- BrewingFuelUseEvent
- PotionFinishBrewingSound
2022-01-22 16:54:58 +00:00
b2630a0920 Merge remote-tracking branch 'origin/stable' into next-minor 2022-01-22 14:46:55 +00:00
67a0ae0246 Fixed incorrect drops for ender chest (#4751) 2022-01-22 14:01:56 +00:00
5ae20459dd 4.1.0-BETA2 is next 2022-01-22 02:23:09 +00:00
30 changed files with 922 additions and 69 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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
View File

@ -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",

View File

@ -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";

View File

@ -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()));

View File

@ -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);
}
}
}
}

View File

@ -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()
];

View File

@ -66,4 +66,8 @@ class EnderChest extends Transparent{
VanillaBlocks::OBSIDIAN()->asItem()->setCount(8)
];
}
public function isAffectedBySilkTouch() : bool{
return true;
}
}

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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; }
}

View 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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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; }
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View File

@ -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);
}
}

View File

@ -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)){

View File

@ -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);

View File

@ -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();
}

View 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)];
}
}

View 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)];
}
}

View 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)];
}
}

View 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)];
}
}