mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-10 05:34:54 +00:00
Merge branch 'minor-next' into feat/async-events
This commit is contained in:
commit
4451770ca3
10
.github/ISSUE_TEMPLATE/api-change-request.md
vendored
10
.github/ISSUE_TEMPLATE/api-change-request.md
vendored
@ -7,13 +7,13 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--- tell us what you want -->
|
||||
## Description
|
||||
<!--- Describe the problem you want to solve -->
|
||||
## Problem description
|
||||
|
||||
|
||||
<!--- explain why you want this and why it's a good idea -->
|
||||
## Justification
|
||||
<!--- Describe what changes you want to make to solve this problem -->
|
||||
## Proposed solution
|
||||
|
||||
|
||||
<!--- (optional) describe alternative methods you've explored to achieve your goal -->
|
||||
## Alternative methods
|
||||
## Alternative solutions that don't require API changes
|
||||
|
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -24,11 +24,9 @@
|
||||
<!-- Suggest any actions to be done before/after merging this pull request -->
|
||||
<!-- For example, future changes that this PR lays the groundwork for -->
|
||||
|
||||
## In-Game Testing
|
||||
## Tests
|
||||
<!--
|
||||
GAMEPLAY FEATURE PRS MUST BE TESTED IN-GAME.
|
||||
Include any screenshots or videos of in-game testing here.
|
||||
If this PR affects gameplay or user experience in some way, it must be manually tested.
|
||||
Include any screenshots or videos of manual testing here.
|
||||
Any test plugin code should also be pasted here if it can't be adapted to a PHPUnit test.
|
||||
|
||||
If this isn't a gameplay PR, you can delete this section.
|
||||
-->
|
||||
|
36
.github/workflows/team-pr-auto-approve.yml
vendored
36
.github/workflows/team-pr-auto-approve.yml
vendored
@ -13,30 +13,26 @@ on:
|
||||
- reopened
|
||||
- ready_for_review
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
approve:
|
||||
name: Auto approve
|
||||
dispatch:
|
||||
name: Request approval
|
||||
runs-on: ubuntu-latest
|
||||
if: '! github.event.pull_request.draft'
|
||||
|
||||
steps:
|
||||
- name: Check if PR author has write access
|
||||
id: check-permission
|
||||
uses: actions-cool/check-user-permission@v2
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
require: write
|
||||
username: ${{ github.event.pull_request.user.login }}
|
||||
#technically this would be fine for dependabot but generally bots don't count as team members
|
||||
check-bot: true
|
||||
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
|
||||
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repositories: RestrictedActions
|
||||
|
||||
#TODO: Some way to avoid unnecessary repeated reviews would be nice here
|
||||
|
||||
- name: Approve PR if authorized
|
||||
if: steps.check-permission.outputs.require-result == 'true' && steps.check-permission.outputs.check-result == 'false'
|
||||
uses: juliangruber/approve-pull-request-action@v2
|
||||
- name: Dispatch restricted action
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
number: ${{ github.event.pull_request.number }}
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
repository: ${{ github.repository_owner }}/RestrictedActions
|
||||
event-type: auto_approve_collaborator_pr
|
||||
client-payload: '{"repo": "${{ github.repository }}", "pull_request_id": "${{ github.event.pull_request.number }}" }'
|
||||
|
@ -41,7 +41,7 @@
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
"pocketmine/errorhandler": "^0.7.0",
|
||||
"pocketmine/locale-data": "~2.19.0",
|
||||
"pocketmine/locale-data": "~2.21.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/math": "~1.0.0",
|
||||
"pocketmine/nbt": "~1.0.0",
|
||||
|
14
composer.lock
generated
14
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": "b2fbf6e7a9d650341dc71fa4dd124681",
|
||||
"content-hash": "476374fb3d22e26a97c1dea8c6736faf",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -420,16 +420,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/locale-data",
|
||||
"version": "2.19.6",
|
||||
"version": "2.21.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Language.git",
|
||||
"reference": "93e473e20e7f4515ecf45c5ef0f9155b9247a86e"
|
||||
"reference": "fdba0f764d6281f64e5968dca94fdab96bf4e167"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/93e473e20e7f4515ecf45c5ef0f9155b9247a86e",
|
||||
"reference": "93e473e20e7f4515ecf45c5ef0f9155b9247a86e",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/fdba0f764d6281f64e5968dca94fdab96bf4e167",
|
||||
"reference": "fdba0f764d6281f64e5968dca94fdab96bf4e167",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -437,9 +437,9 @@
|
||||
"description": "Language resources used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/Language/issues",
|
||||
"source": "https://github.com/pmmp/Language/tree/2.19.6"
|
||||
"source": "https://github.com/pmmp/Language/tree/2.21.1"
|
||||
},
|
||||
"time": "2023-08-08T16:53:23+00:00"
|
||||
"time": "2024-11-14T23:11:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/log",
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
/**
|
||||
* "Flowable" blocks are destroyed if water flows into the same space as the block. These blocks usually don't have any
|
||||
@ -40,6 +41,11 @@ abstract class Flowable extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return (!$this->canBeFlowedInto() || !$blockReplace instanceof Liquid) &&
|
||||
parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
|
@ -24,60 +24,20 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\MultiAnySupportTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\World;
|
||||
use function array_key_first;
|
||||
use function count;
|
||||
use function shuffle;
|
||||
|
||||
class GlowLichen extends Transparent{
|
||||
|
||||
/** @var int[] */
|
||||
protected array $faces = [];
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->facingFlags($this->faces);
|
||||
}
|
||||
|
||||
/** @return int[] */
|
||||
public function getFaces() : array{ return $this->faces; }
|
||||
|
||||
public function hasFace(int $face) : bool{
|
||||
return isset($this->faces[$face]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
* @return $this
|
||||
*/
|
||||
public function setFaces(array $faces) : self{
|
||||
$uniqueFaces = [];
|
||||
foreach($faces as $face){
|
||||
Facing::validate($face);
|
||||
$uniqueFaces[$face] = $face;
|
||||
}
|
||||
$this->faces = $uniqueFaces;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function setFace(int $face, bool $value) : self{
|
||||
Facing::validate($face);
|
||||
if($value){
|
||||
$this->faces[$face] = $face;
|
||||
}else{
|
||||
unset($this->faces[$face]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
use MultiAnySupportTrait;
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return 7;
|
||||
@ -102,39 +62,11 @@ class GlowLichen extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->faces = $blockReplace instanceof GlowLichen ? $blockReplace->faces : [];
|
||||
$availableFaces = $this->getAvailableFaces();
|
||||
|
||||
if(count($availableFaces) === 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
$opposite = Facing::opposite($face);
|
||||
$placedFace = isset($availableFaces[$opposite]) ? $opposite : array_key_first($availableFaces);
|
||||
$this->faces[$placedFace] = $placedFace;
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$changed = false;
|
||||
|
||||
foreach($this->faces as $face){
|
||||
if($this->getAdjacentSupportType($face) !== SupportType::FULL){
|
||||
unset($this->faces[$face]);
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($changed){
|
||||
$world = $this->position->getWorld();
|
||||
if(count($this->faces) === 0){
|
||||
$world->useBreakOn($this->position);
|
||||
}else{
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
protected function getInitialPlaceFaces(Block $blockReplace) : array{
|
||||
return $blockReplace instanceof GlowLichen ? $blockReplace->faces : [];
|
||||
}
|
||||
|
||||
private function getSpreadBlock(Block $replace, int $spreadFace) : ?Block{
|
||||
@ -261,17 +193,4 @@ class GlowLichen extends Transparent{
|
||||
public function getFlammability() : int{
|
||||
return 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, int> $faces
|
||||
*/
|
||||
private function getAvailableFaces() : array{
|
||||
$faces = [];
|
||||
foreach(Facing::ALL as $face){
|
||||
if(!$this->hasFace($face) && $this->getAdjacentSupportType($face) === SupportType::FULL){
|
||||
$faces[$face] = $face;
|
||||
}
|
||||
}
|
||||
return $faces;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,9 @@ use pocketmine\world\Position;
|
||||
|
||||
class Sugarcane extends Flowable{
|
||||
use AgeableTrait;
|
||||
use StaticSupportTrait;
|
||||
use StaticSupportTrait {
|
||||
onNearbyBlockChange as onSupportBlockChange;
|
||||
}
|
||||
|
||||
public const MAX_AGE = 15;
|
||||
|
||||
@ -97,7 +99,13 @@ class Sugarcane extends Flowable{
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if(!$this->getSide(Facing::DOWN)->hasSameTypeId($this)){
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
if(!$down->hasSameTypeId($this)){
|
||||
if(!$this->hasNearbyWater($down)){
|
||||
$this->position->getWorld()->useBreakOn($this->position, createParticles: true);
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->age === self::MAX_AGE){
|
||||
$this->grow($this->position);
|
||||
}else{
|
||||
@ -123,4 +131,23 @@ class Sugarcane extends Flowable{
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function hasNearbyWater(Block $down) : bool{
|
||||
foreach($down->getHorizontalSides() as $sideBlock){
|
||||
$blockId = $sideBlock->getTypeId();
|
||||
if($blockId === BlockTypeIds::WATER || $blockId === BlockTypeIds::FROSTED_ICE){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
if(!$down->hasSameTypeId($this) && !$this->hasNearbyWater($down)){
|
||||
$this->position->getWorld()->useBreakOn($this->position, createParticles: true);
|
||||
}else{
|
||||
$this->onSupportBlockChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,263 +0,0 @@
|
||||
<?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\block;
|
||||
|
||||
use pocketmine\block\BlockIdentifier as BID;
|
||||
use pocketmine\block\BlockTypeIds as Ids;
|
||||
use pocketmine\block\tile\Sign as TileSign;
|
||||
use pocketmine\block\utils\LeavesType;
|
||||
use pocketmine\block\utils\SaplingType;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\item\VanillaItems;
|
||||
|
||||
/**
|
||||
* All wood-like blocks have different IDs for different wood types.
|
||||
*
|
||||
* We can't make these dynamic, because some types of wood have different type properties (e.g. crimson and warped planks
|
||||
* are not flammable, but all other planks are).
|
||||
*
|
||||
* In the future, it's entirely within the realm of reason that the other types of wood may differ in other ways, such
|
||||
* as flammability, hardness, required tool tier, etc.
|
||||
* Therefore, to stay on the safe side of Mojang, wood-like blocks have static types. This does unfortunately generate
|
||||
* a lot of ugly code.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class WoodLikeBlockIdHelper{
|
||||
|
||||
public static function getPlanksIdentifier(WoodType $type) : BID{
|
||||
return new BID(match($type){
|
||||
WoodType::OAK => Ids::OAK_PLANKS,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_PLANKS,
|
||||
WoodType::BIRCH => Ids::BIRCH_PLANKS,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_PLANKS,
|
||||
WoodType::ACACIA => Ids::ACACIA_PLANKS,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_PLANKS,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_PLANKS,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_PLANKS,
|
||||
WoodType::WARPED => Ids::WARPED_PLANKS,
|
||||
WoodType::CHERRY => Ids::CHERRY_PLANKS,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getFenceIdentifier(WoodType $type) : BID{
|
||||
return new BID(match($type){
|
||||
WoodType::OAK => Ids::OAK_FENCE,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_FENCE,
|
||||
WoodType::BIRCH => Ids::BIRCH_FENCE,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_FENCE,
|
||||
WoodType::ACACIA => Ids::ACACIA_FENCE,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_FENCE,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_FENCE,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_FENCE,
|
||||
WoodType::WARPED => Ids::WARPED_FENCE,
|
||||
WoodType::CHERRY => Ids::CHERRY_FENCE,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getSlabIdentifier(WoodType $type) : BID{
|
||||
return new BID(match($type){
|
||||
WoodType::OAK => Ids::OAK_SLAB,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_SLAB,
|
||||
WoodType::BIRCH => Ids::BIRCH_SLAB,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_SLAB,
|
||||
WoodType::ACACIA => Ids::ACACIA_SLAB,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_SLAB,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_SLAB,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_SLAB,
|
||||
WoodType::WARPED => Ids::WARPED_SLAB,
|
||||
WoodType::CHERRY => Ids::CHERRY_SLAB,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getLogIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_LOG,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_LOG,
|
||||
WoodType::BIRCH => Ids::BIRCH_LOG,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_LOG,
|
||||
WoodType::ACACIA => Ids::ACACIA_LOG,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_LOG,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_LOG,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_STEM,
|
||||
WoodType::WARPED => Ids::WARPED_STEM,
|
||||
WoodType::CHERRY => Ids::CHERRY_LOG,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getAllSidedLogIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_WOOD,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_WOOD,
|
||||
WoodType::BIRCH => Ids::BIRCH_WOOD,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_WOOD,
|
||||
WoodType::ACACIA => Ids::ACACIA_WOOD,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_WOOD,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_WOOD,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_HYPHAE,
|
||||
WoodType::WARPED => Ids::WARPED_HYPHAE,
|
||||
WoodType::CHERRY => Ids::CHERRY_WOOD,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getLeavesIdentifier(LeavesType $leavesType) : BID{
|
||||
return new BID(match($leavesType){
|
||||
LeavesType::OAK => Ids::OAK_LEAVES,
|
||||
LeavesType::SPRUCE => Ids::SPRUCE_LEAVES,
|
||||
LeavesType::BIRCH => Ids::BIRCH_LEAVES,
|
||||
LeavesType::JUNGLE => Ids::JUNGLE_LEAVES,
|
||||
LeavesType::ACACIA => Ids::ACACIA_LEAVES,
|
||||
LeavesType::DARK_OAK => Ids::DARK_OAK_LEAVES,
|
||||
LeavesType::MANGROVE => Ids::MANGROVE_LEAVES,
|
||||
LeavesType::AZALEA => Ids::AZALEA_LEAVES,
|
||||
LeavesType::FLOWERING_AZALEA => Ids::FLOWERING_AZALEA_LEAVES,
|
||||
LeavesType::CHERRY => Ids::CHERRY_LEAVES,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getSaplingIdentifier(SaplingType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
SaplingType::OAK => Ids::OAK_SAPLING,
|
||||
SaplingType::SPRUCE => Ids::SPRUCE_SAPLING,
|
||||
SaplingType::BIRCH => Ids::BIRCH_SAPLING,
|
||||
SaplingType::JUNGLE => Ids::JUNGLE_SAPLING,
|
||||
SaplingType::ACACIA => Ids::ACACIA_SAPLING,
|
||||
SaplingType::DARK_OAK => Ids::DARK_OAK_SAPLING,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BID[]|\Closure[]
|
||||
* @phpstan-return array{BID, BID, \Closure() : \pocketmine\item\Item}
|
||||
*/
|
||||
public static function getSignInfo(WoodType $treeType) : array{
|
||||
$make = fn(int $floorId, int $wallId, \Closure $getItem) => [
|
||||
new BID($floorId, TileSign::class),
|
||||
new BID($wallId, TileSign::class),
|
||||
$getItem
|
||||
];
|
||||
return match($treeType){
|
||||
WoodType::OAK => $make(Ids::OAK_SIGN, Ids::OAK_WALL_SIGN, fn() => VanillaItems::OAK_SIGN()),
|
||||
WoodType::SPRUCE => $make(Ids::SPRUCE_SIGN, Ids::SPRUCE_WALL_SIGN, fn() => VanillaItems::SPRUCE_SIGN()),
|
||||
WoodType::BIRCH => $make(Ids::BIRCH_SIGN, Ids::BIRCH_WALL_SIGN, fn() => VanillaItems::BIRCH_SIGN()),
|
||||
WoodType::JUNGLE => $make(Ids::JUNGLE_SIGN, Ids::JUNGLE_WALL_SIGN, fn() => VanillaItems::JUNGLE_SIGN()),
|
||||
WoodType::ACACIA => $make(Ids::ACACIA_SIGN, Ids::ACACIA_WALL_SIGN, fn() => VanillaItems::ACACIA_SIGN()),
|
||||
WoodType::DARK_OAK => $make(Ids::DARK_OAK_SIGN, Ids::DARK_OAK_WALL_SIGN, fn() => VanillaItems::DARK_OAK_SIGN()),
|
||||
WoodType::MANGROVE => $make(Ids::MANGROVE_SIGN, Ids::MANGROVE_WALL_SIGN, fn() => VanillaItems::MANGROVE_SIGN()),
|
||||
WoodType::CRIMSON => $make(Ids::CRIMSON_SIGN, Ids::CRIMSON_WALL_SIGN, fn() => VanillaItems::CRIMSON_SIGN()),
|
||||
WoodType::WARPED => $make(Ids::WARPED_SIGN, Ids::WARPED_WALL_SIGN, fn() => VanillaItems::WARPED_SIGN()),
|
||||
WoodType::CHERRY => $make(Ids::CHERRY_SIGN, Ids::CHERRY_WALL_SIGN, fn() => VanillaItems::CHERRY_SIGN()),
|
||||
};
|
||||
}
|
||||
|
||||
public static function getTrapdoorIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_TRAPDOOR,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_TRAPDOOR,
|
||||
WoodType::BIRCH => Ids::BIRCH_TRAPDOOR,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_TRAPDOOR,
|
||||
WoodType::ACACIA => Ids::ACACIA_TRAPDOOR,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_TRAPDOOR,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_TRAPDOOR,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_TRAPDOOR,
|
||||
WoodType::WARPED => Ids::WARPED_TRAPDOOR,
|
||||
WoodType::CHERRY => Ids::CHERRY_TRAPDOOR,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getButtonIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_BUTTON,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_BUTTON,
|
||||
WoodType::BIRCH => Ids::BIRCH_BUTTON,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_BUTTON,
|
||||
WoodType::ACACIA => Ids::ACACIA_BUTTON,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_BUTTON,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_BUTTON,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_BUTTON,
|
||||
WoodType::WARPED => Ids::WARPED_BUTTON,
|
||||
WoodType::CHERRY => Ids::CHERRY_BUTTON,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getPressurePlateIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_PRESSURE_PLATE,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_PRESSURE_PLATE,
|
||||
WoodType::BIRCH => Ids::BIRCH_PRESSURE_PLATE,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_PRESSURE_PLATE,
|
||||
WoodType::ACACIA => Ids::ACACIA_PRESSURE_PLATE,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_PRESSURE_PLATE,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_PRESSURE_PLATE,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_PRESSURE_PLATE,
|
||||
WoodType::WARPED => Ids::WARPED_PRESSURE_PLATE,
|
||||
WoodType::CHERRY => Ids::CHERRY_PRESSURE_PLATE,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getDoorIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_DOOR,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_DOOR,
|
||||
WoodType::BIRCH => Ids::BIRCH_DOOR,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_DOOR,
|
||||
WoodType::ACACIA => Ids::ACACIA_DOOR,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_DOOR,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_DOOR,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_DOOR,
|
||||
WoodType::WARPED => Ids::WARPED_DOOR,
|
||||
WoodType::CHERRY => Ids::CHERRY_DOOR,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getFenceGateIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_FENCE_GATE,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_FENCE_GATE,
|
||||
WoodType::BIRCH => Ids::BIRCH_FENCE_GATE,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_FENCE_GATE,
|
||||
WoodType::ACACIA => Ids::ACACIA_FENCE_GATE,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_FENCE_GATE,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_FENCE_GATE,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_FENCE_GATE,
|
||||
WoodType::WARPED => Ids::WARPED_FENCE_GATE,
|
||||
WoodType::CHERRY => Ids::CHERRY_FENCE_GATE,
|
||||
});
|
||||
}
|
||||
|
||||
public static function getStairsIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_STAIRS,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_STAIRS,
|
||||
WoodType::BIRCH => Ids::BIRCH_STAIRS,
|
||||
WoodType::JUNGLE => Ids::JUNGLE_STAIRS,
|
||||
WoodType::ACACIA => Ids::ACACIA_STAIRS,
|
||||
WoodType::DARK_OAK => Ids::DARK_OAK_STAIRS,
|
||||
WoodType::MANGROVE => Ids::MANGROVE_STAIRS,
|
||||
WoodType::CRIMSON => Ids::CRIMSON_STAIRS,
|
||||
WoodType::WARPED => Ids::WARPED_STAIRS,
|
||||
WoodType::CHERRY => Ids::CHERRY_STAIRS,
|
||||
});
|
||||
}
|
||||
}
|
72
src/block/utils/MultiAnyFacingTrait.php
Normal file
72
src/block/utils/MultiAnyFacingTrait.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?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\block\utils;
|
||||
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\math\Facing;
|
||||
|
||||
/**
|
||||
* Used by blocks that can have multiple target faces in the area of one solid block, such as covering three sides of a corner.
|
||||
*/
|
||||
trait MultiAnyFacingTrait{
|
||||
|
||||
/** @var int[] */
|
||||
protected array $faces = [];
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->facingFlags($this->faces);
|
||||
}
|
||||
|
||||
/** @return int[] */
|
||||
public function getFaces() : array{ return $this->faces; }
|
||||
|
||||
public function hasFace(int $face) : bool{
|
||||
return isset($this->faces[$face]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
* @return $this
|
||||
*/
|
||||
public function setFaces(array $faces) : self{
|
||||
$uniqueFaces = [];
|
||||
foreach($faces as $face){
|
||||
Facing::validate($face);
|
||||
$uniqueFaces[$face] = $face;
|
||||
}
|
||||
$this->faces = $uniqueFaces;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function setFace(int $face, bool $value) : self{
|
||||
Facing::validate($face);
|
||||
if($value){
|
||||
$this->faces[$face] = $face;
|
||||
}else{
|
||||
unset($this->faces[$face]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
96
src/block/utils/MultiAnySupportTrait.php
Normal file
96
src/block/utils/MultiAnySupportTrait.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?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\block\utils;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function array_key_first;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Used by blocks that have multiple support requirements in the area of one solid block, such as covering three sides of a corner.
|
||||
* Prevents placement if support isn't available and automatically destroys a block side if it's support is removed.
|
||||
*/
|
||||
trait MultiAnySupportTrait{
|
||||
use MultiAnyFacingTrait;
|
||||
|
||||
/**
|
||||
* Returns a list of faces that block should already have when placed.
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
abstract protected function getInitialPlaceFaces(Block $blockReplace) : array;
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->faces = $this->getInitialPlaceFaces($blockReplace);
|
||||
$availableFaces = $this->getAvailableFaces();
|
||||
|
||||
if(count($availableFaces) === 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
$opposite = Facing::opposite($face);
|
||||
$placedFace = isset($availableFaces[$opposite]) ? $opposite : array_key_first($availableFaces);
|
||||
$this->faces[$placedFace] = $placedFace;
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$changed = false;
|
||||
|
||||
foreach($this->faces as $face){
|
||||
if($this->getAdjacentSupportType($face) !== SupportType::FULL){
|
||||
unset($this->faces[$face]);
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($changed){
|
||||
$world = $this->position->getWorld();
|
||||
if(count($this->faces) === 0){
|
||||
$world->useBreakOn($this->position);
|
||||
}else{
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, int> $faces
|
||||
*/
|
||||
private function getAvailableFaces() : array{
|
||||
$faces = [];
|
||||
foreach(Facing::ALL as $face){
|
||||
if(!$this->hasFace($face) && $this->getAdjacentSupportType($face) === SupportType::FULL){
|
||||
$faces[$face] = $face;
|
||||
}
|
||||
}
|
||||
return $faces;
|
||||
}
|
||||
}
|
@ -64,6 +64,7 @@ use pocketmine\command\defaults\TransferServerCommand;
|
||||
use pocketmine\command\defaults\VanillaCommand;
|
||||
use pocketmine\command\defaults\VersionCommand;
|
||||
use pocketmine\command\defaults\WhitelistCommand;
|
||||
use pocketmine\command\defaults\XpCommand;
|
||||
use pocketmine\command\utils\CommandStringHelper;
|
||||
use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
@ -128,7 +129,8 @@ class SimpleCommandMap implements CommandMap{
|
||||
new TitleCommand(),
|
||||
new TransferServerCommand(),
|
||||
new VersionCommand(),
|
||||
new WhitelistCommand()
|
||||
new WhitelistCommand(),
|
||||
new XpCommand(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
89
src/command/defaults/XpCommand.php
Normal file
89
src/command/defaults/XpCommand.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?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\command\defaults;
|
||||
|
||||
use pocketmine\command\CommandSender;
|
||||
use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\entity\Attribute;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Limits;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function abs;
|
||||
use function count;
|
||||
use function str_ends_with;
|
||||
use function substr;
|
||||
|
||||
class XpCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"xp",
|
||||
KnownTranslationFactory::pocketmine_command_xp_description(),
|
||||
KnownTranslationFactory::pocketmine_command_xp_usage()
|
||||
);
|
||||
$this->setPermissions([
|
||||
DefaultPermissionNames::COMMAND_XP_SELF,
|
||||
DefaultPermissionNames::COMMAND_XP_OTHER
|
||||
]);
|
||||
}
|
||||
|
||||
public function execute(CommandSender $sender, string $commandLabel, array $args){
|
||||
if(count($args) < 1){
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $this->fetchPermittedPlayerTarget($sender, $args[1] ?? null, DefaultPermissionNames::COMMAND_XP_SELF, DefaultPermissionNames::COMMAND_XP_OTHER);
|
||||
if($player === null){
|
||||
return true;
|
||||
}
|
||||
|
||||
$xpManager = $player->getXpManager();
|
||||
if(str_ends_with($args[0], "L")){
|
||||
$xpLevelAttr = $player->getAttributeMap()->get(Attribute::EXPERIENCE_LEVEL) ?? throw new AssumptionFailedError();
|
||||
$maxXpLevel = (int) $xpLevelAttr->getMaxValue();
|
||||
$currentXpLevel = $xpManager->getXpLevel();
|
||||
$xpLevels = $this->getInteger($sender, substr($args[0], 0, -1), -$currentXpLevel, $maxXpLevel - $currentXpLevel);
|
||||
if($xpLevels >= 0){
|
||||
$xpManager->addXpLevels($xpLevels, false);
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_xp_success_levels((string) $xpLevels, $player->getName()));
|
||||
}else{
|
||||
$xpLevels = abs($xpLevels);
|
||||
$xpManager->subtractXpLevels($xpLevels);
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_xp_success_negative_levels((string) $xpLevels, $player->getName()));
|
||||
}
|
||||
}else{
|
||||
$xp = $this->getInteger($sender, $args[0], max: Limits::INT32_MAX);
|
||||
if($xp < 0){
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_xp_failure_widthdrawXp()->prefix(TextFormat::RED));
|
||||
}else{
|
||||
$xpManager->addXp($xp, false);
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_xp_success((string) $xp, $player->getName()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -29,23 +29,21 @@ use pocketmine\utils\Process;
|
||||
use function cli_set_process_title;
|
||||
use function count;
|
||||
use function dirname;
|
||||
use function feof;
|
||||
use function fwrite;
|
||||
use function stream_socket_client;
|
||||
use function is_numeric;
|
||||
use const PHP_EOL;
|
||||
use const STDOUT;
|
||||
|
||||
if(count($argv) !== 2 || !is_numeric($argv[1])){
|
||||
echo "Usage: " . $argv[0] . " <command token seed>" . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$commandTokenSeed = (int) $argv[1];
|
||||
|
||||
require dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
|
||||
if(count($argv) !== 2){
|
||||
die("Please provide a server to connect to");
|
||||
}
|
||||
|
||||
@cli_set_process_title('PocketMine-MP Console Reader');
|
||||
$errCode = null;
|
||||
$errMessage = null;
|
||||
$socket = stream_socket_client($argv[1], $errCode, $errMessage, 15.0);
|
||||
if($socket === false){
|
||||
throw new \RuntimeException("Failed to connect to server process ($errCode): $errMessage");
|
||||
}
|
||||
|
||||
/** @phpstan-var ThreadSafeArray<int, string> $channel */
|
||||
$channel = new ThreadSafeArray();
|
||||
@ -75,15 +73,15 @@ $thread = new class($channel) extends NativeThread{
|
||||
};
|
||||
|
||||
$thread->start(NativeThread::INHERIT_NONE);
|
||||
while(!feof($socket)){
|
||||
while(true){
|
||||
$line = $channel->synchronized(function() use ($channel) : ?string{
|
||||
if(count($channel) === 0){
|
||||
$channel->wait(1_000_000);
|
||||
}
|
||||
$line = $channel->shift();
|
||||
return $line;
|
||||
return $channel->shift();
|
||||
});
|
||||
if(@fwrite($socket, ($line ?? "") . "\n") === false){
|
||||
$message = $line !== null ? ConsoleReaderChildProcessUtils::createMessage($line, $commandTokenSeed) : "";
|
||||
if(@fwrite(STDOUT, $message . "\n") === false){
|
||||
//Always send even if there's no line, to check if the parent is alive
|
||||
//If the parent process was terminated forcibly, it won't close the connection properly, so feof() will return
|
||||
//false even though the connection is actually broken. However, fwrite() will fail.
|
||||
|
@ -29,19 +29,16 @@ use Symfony\Component\Filesystem\Path;
|
||||
use function base64_encode;
|
||||
use function fgets;
|
||||
use function fopen;
|
||||
use function mt_rand;
|
||||
use function preg_replace;
|
||||
use function proc_close;
|
||||
use function proc_open;
|
||||
use function proc_terminate;
|
||||
use function rtrim;
|
||||
use function sprintf;
|
||||
use function stream_select;
|
||||
use function stream_socket_accept;
|
||||
use function stream_socket_get_name;
|
||||
use function stream_socket_server;
|
||||
use function stream_socket_shutdown;
|
||||
use function trim;
|
||||
use const PHP_BINARY;
|
||||
use const STREAM_SHUT_RDWR;
|
||||
|
||||
/**
|
||||
* This pile of shit exists because PHP on Windows is broken, and can't handle stream_select() on stdin or pipes
|
||||
@ -58,44 +55,44 @@ use const STREAM_SHUT_RDWR;
|
||||
* communication.
|
||||
*/
|
||||
final class ConsoleReaderChildProcessDaemon{
|
||||
public const TOKEN_DELIMITER = ":";
|
||||
public const TOKEN_HASH_ALGO = "xxh3";
|
||||
|
||||
private \PrefixedLogger $logger;
|
||||
/** @var resource */
|
||||
private $subprocess;
|
||||
/** @var resource */
|
||||
private $socket;
|
||||
private int $commandTokenSeed;
|
||||
|
||||
public function __construct(
|
||||
\Logger $logger
|
||||
){
|
||||
$this->logger = new \PrefixedLogger($logger, "Console Reader Daemon");
|
||||
$this->commandTokenSeed = mt_rand();
|
||||
$this->prepareSubprocess();
|
||||
}
|
||||
|
||||
private function prepareSubprocess() : void{
|
||||
$server = stream_socket_server("tcp://127.0.0.1:0");
|
||||
if($server === false){
|
||||
throw new \RuntimeException("Failed to open console reader socket server");
|
||||
}
|
||||
$address = Utils::assumeNotFalse(stream_socket_get_name($server, false), "stream_socket_get_name() shouldn't return false here");
|
||||
|
||||
//Windows sucks, and likes to corrupt UTF-8 file paths when they travel to the subprocess, so we base64 encode
|
||||
//the path to avoid the problem. This is an abysmally shitty hack, but here we are :(
|
||||
$sub = Utils::assumeNotFalse(proc_open(
|
||||
[PHP_BINARY, '-dopcache.enable_cli=0', '-r', sprintf('require base64_decode("%s", true);', base64_encode(Path::join(__DIR__, 'ConsoleReaderChildProcess.php'))), $address],
|
||||
[
|
||||
PHP_BINARY,
|
||||
'-dopcache.enable_cli=0',
|
||||
'-r',
|
||||
sprintf('require base64_decode("%s", true);', base64_encode(Path::join(__DIR__, 'ConsoleReaderChildProcess.php'))),
|
||||
(string) $this->commandTokenSeed
|
||||
],
|
||||
[
|
||||
1 => ['socket'],
|
||||
2 => fopen("php://stderr", "w"),
|
||||
],
|
||||
$pipes
|
||||
), "Something has gone horribly wrong");
|
||||
|
||||
$client = stream_socket_accept($server, 15);
|
||||
if($client === false){
|
||||
throw new AssumptionFailedError("stream_socket_accept() returned false");
|
||||
}
|
||||
stream_socket_shutdown($server, STREAM_SHUT_RDWR);
|
||||
|
||||
$this->subprocess = $sub;
|
||||
$this->socket = $client;
|
||||
$this->socket = $pipes[1];
|
||||
}
|
||||
|
||||
private function shutdownSubprocess() : void{
|
||||
@ -104,7 +101,6 @@ final class ConsoleReaderChildProcessDaemon{
|
||||
//the first place).
|
||||
proc_terminate($this->subprocess);
|
||||
proc_close($this->subprocess);
|
||||
stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);
|
||||
}
|
||||
|
||||
public function readLine() : ?string{
|
||||
@ -112,13 +108,27 @@ final class ConsoleReaderChildProcessDaemon{
|
||||
$w = null;
|
||||
$e = null;
|
||||
if(stream_select($r, $w, $e, 0, 0) === 1){
|
||||
$command = fgets($this->socket);
|
||||
if($command === false){
|
||||
$line = fgets($this->socket);
|
||||
if($line === false){
|
||||
$this->logger->debug("Lost connection to subprocess, restarting (maybe the child process was killed from outside?)");
|
||||
$this->shutdownSubprocess();
|
||||
$this->prepareSubprocess();
|
||||
return null;
|
||||
}
|
||||
$line = rtrim($line, "\n");
|
||||
|
||||
if($line === ""){
|
||||
//keepalive
|
||||
return null;
|
||||
}
|
||||
|
||||
$command = ConsoleReaderChildProcessUtils::parseMessage($line, $this->commandTokenSeed);
|
||||
if($command === null){
|
||||
//this is not a command - it may be some kind of error output from the subprocess
|
||||
//write it directly to the console
|
||||
$this->logger->warning("Unexpected output from child process: $line");
|
||||
return null;
|
||||
}
|
||||
|
||||
$command = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", trim($command)) ?? throw new AssumptionFailedError("This regex is assumed to be valid");
|
||||
$command = preg_replace('/[[:cntrl:]]/', '', $command) ?? throw new AssumptionFailedError("This regex is assumed to be valid");
|
||||
|
71
src/console/ConsoleReaderChildProcessUtils.php
Normal file
71
src/console/ConsoleReaderChildProcessUtils.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\console;
|
||||
|
||||
use function hash;
|
||||
use function strlen;
|
||||
use function strrpos;
|
||||
use function substr;
|
||||
|
||||
final class ConsoleReaderChildProcessUtils{
|
||||
public const TOKEN_DELIMITER = ":";
|
||||
public const TOKEN_HASH_ALGO = "xxh3";
|
||||
|
||||
private function __construct(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IPC message to transmit a user's input command to the parent process.
|
||||
*
|
||||
* Unfortunately we can't currently provide IPC pipes other than stdout/stderr to subprocesses on Windows, so this
|
||||
* adds a hash of the user input (with a counter as salt) to prevent unintended process output (like error messages)
|
||||
* from being treated as user input.
|
||||
*/
|
||||
public static function createMessage(string $line, int &$counter) : string{
|
||||
$token = hash(self::TOKEN_HASH_ALGO, $line, options: ['seed' => $counter]);
|
||||
$counter++;
|
||||
return $line . self::TOKEN_DELIMITER . $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a command from an IPC message from the console reader subprocess.
|
||||
* Returns the user's input command, or null if this isn't a user input.
|
||||
*/
|
||||
public static function parseMessage(string $message, int &$counter) : ?string{
|
||||
$delimiterPos = strrpos($message, self::TOKEN_DELIMITER);
|
||||
if($delimiterPos !== false){
|
||||
$left = substr($message, 0, $delimiterPos);
|
||||
$right = substr($message, $delimiterPos + strlen(self::TOKEN_DELIMITER));
|
||||
$expectedToken = hash(self::TOKEN_HASH_ALGO, $left, options: ['seed' => $counter]);
|
||||
|
||||
if($expectedToken === $right){
|
||||
$counter++;
|
||||
return $left;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
48
src/data/bedrock/GoatHornTypeIdMap.php
Normal file
48
src/data/bedrock/GoatHornTypeIdMap.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?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\data\bedrock;
|
||||
|
||||
use pocketmine\item\GoatHornType;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
|
||||
final class GoatHornTypeIdMap{
|
||||
use SingletonTrait;
|
||||
/** @phpstan-use IntSaveIdMapTrait<GoatHornType> */
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
foreach(GoatHornType::cases() as $case){
|
||||
$this->register(match($case){
|
||||
GoatHornType::PONDER => GoatHornTypeIds::PONDER,
|
||||
GoatHornType::SING => GoatHornTypeIds::SING,
|
||||
GoatHornType::SEEK => GoatHornTypeIds::SEEK,
|
||||
GoatHornType::FEEL => GoatHornTypeIds::FEEL,
|
||||
GoatHornType::ADMIRE => GoatHornTypeIds::ADMIRE,
|
||||
GoatHornType::CALL => GoatHornTypeIds::CALL,
|
||||
GoatHornType::YEARN => GoatHornTypeIds::YEARN,
|
||||
GoatHornType::DREAM => GoatHornTypeIds::DREAM
|
||||
}, $case);
|
||||
}
|
||||
}
|
||||
}
|
35
src/data/bedrock/GoatHornTypeIds.php
Normal file
35
src/data/bedrock/GoatHornTypeIds.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\data\bedrock;
|
||||
|
||||
final class GoatHornTypeIds{
|
||||
public const PONDER = 0;
|
||||
public const SING = 1;
|
||||
public const SEEK = 2;
|
||||
public const FEEL = 3;
|
||||
public const ADMIRE = 4;
|
||||
public const CALL = 5;
|
||||
public const YEARN = 6;
|
||||
public const DREAM = 7;
|
||||
}
|
@ -31,6 +31,7 @@ use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\VanillaBlocks as Blocks;
|
||||
use pocketmine\data\bedrock\CompoundTypeIds;
|
||||
use pocketmine\data\bedrock\DyeColorIdMap;
|
||||
use pocketmine\data\bedrock\GoatHornTypeIdMap;
|
||||
use pocketmine\data\bedrock\item\ItemTypeNames as Ids;
|
||||
use pocketmine\data\bedrock\item\SavedItemData as Data;
|
||||
use pocketmine\data\bedrock\MedicineTypeIdMap;
|
||||
@ -38,6 +39,7 @@ use pocketmine\data\bedrock\PotionTypeIdMap;
|
||||
use pocketmine\data\bedrock\SuspiciousStewTypeIdMap;
|
||||
use pocketmine\item\Banner;
|
||||
use pocketmine\item\Dye;
|
||||
use pocketmine\item\GoatHorn;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Medicine;
|
||||
use pocketmine\item\Potion;
|
||||
@ -230,6 +232,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::EMERALD, Items::EMERALD());
|
||||
$this->map1to1Item(Ids::ENCHANTED_BOOK, Items::ENCHANTED_BOOK());
|
||||
$this->map1to1Item(Ids::ENCHANTED_GOLDEN_APPLE, Items::ENCHANTED_GOLDEN_APPLE());
|
||||
$this->map1to1Item(Ids::END_CRYSTAL, Items::END_CRYSTAL());
|
||||
$this->map1to1Item(Ids::ENDER_PEARL, Items::ENDER_PEARL());
|
||||
$this->map1to1Item(Ids::EXPERIENCE_BOTTLE, Items::EXPERIENCE_BOTTLE());
|
||||
$this->map1to1Item(Ids::EYE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::EYE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
@ -483,6 +486,14 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
},
|
||||
fn(Banner $item) => DyeColorIdMap::getInstance()->toInvertedId($item->getColor())
|
||||
);
|
||||
$this->map1to1ItemWithMeta(
|
||||
Ids::GOAT_HORN,
|
||||
Items::GOAT_HORN(),
|
||||
function(GoatHorn $item, int $meta) : void{
|
||||
$item->setHornType(GoatHornTypeIdMap::getInstance()->fromId($meta) ?? throw new ItemTypeDeserializeException("Unknown goat horn type ID $meta"));
|
||||
},
|
||||
fn(GoatHorn $item) => GoatHornTypeIdMap::getInstance()->toId($item->getHornType())
|
||||
);
|
||||
$this->map1to1ItemWithMeta(
|
||||
Ids::MEDICINE,
|
||||
Items::MEDICINE(),
|
||||
|
@ -35,6 +35,7 @@ use pocketmine\event\entity\EntityMotionEvent;
|
||||
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||
use pocketmine\event\entity\EntitySpawnEvent;
|
||||
use pocketmine\event\entity\EntityTeleportEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector2;
|
||||
@ -1560,6 +1561,13 @@ abstract class Entity{
|
||||
$this->hasSpawned = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item that players will equip when middle-clicking on this entity.
|
||||
*/
|
||||
public function getPickedItem() : ?Item{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags the entity to be removed from the world on the next tick.
|
||||
*/
|
||||
|
@ -32,6 +32,7 @@ use pocketmine\data\bedrock\PotionTypeIdMap;
|
||||
use pocketmine\data\bedrock\PotionTypeIds;
|
||||
use pocketmine\data\SavedDataLoadingException;
|
||||
use pocketmine\entity\EntityDataHelper as Helper;
|
||||
use pocketmine\entity\object\EndCrystal;
|
||||
use pocketmine\entity\object\ExperienceOrb;
|
||||
use pocketmine\entity\object\FallingBlock;
|
||||
use pocketmine\entity\object\ItemEntity;
|
||||
@ -92,6 +93,10 @@ final class EntityFactory{
|
||||
return new Egg(Helper::parseLocation($nbt, $world), null, $nbt);
|
||||
}, ['Egg', 'minecraft:egg']);
|
||||
|
||||
$this->register(EndCrystal::class, function(World $world, CompoundTag $nbt) : EndCrystal{
|
||||
return new EndCrystal(Helper::parseLocation($nbt, $world), $nbt);
|
||||
}, ['EnderCrystal', 'minecraft:ender_crystal']);
|
||||
|
||||
$this->register(EnderPearl::class, function(World $world, CompoundTag $nbt) : EnderPearl{
|
||||
return new EnderPearl(Helper::parseLocation($nbt, $world), null, $nbt);
|
||||
}, ['ThrownEnderpearl', 'minecraft:ender_pearl']);
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\entity;
|
||||
use pocketmine\entity\animation\SquidInkCloudAnimation;
|
||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
@ -124,4 +125,8 @@ class Squid extends WaterAnimal{
|
||||
VanillaItems::INK_SAC()->setCount(mt_rand(1, 3))
|
||||
];
|
||||
}
|
||||
|
||||
public function getPickedItem() : ?Item{
|
||||
return VanillaItems::SQUID_SPAWN_EGG();
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\entity;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
||||
@ -87,6 +89,10 @@ class Villager extends Living implements Ageable{
|
||||
return $this->baby;
|
||||
}
|
||||
|
||||
public function getPickedItem() : ?Item{
|
||||
return VanillaItems::VILLAGER_SPAWN_EGG();
|
||||
}
|
||||
|
||||
protected function syncNetworkData(EntityMetadataCollection $properties) : void{
|
||||
parent::syncNetworkData($properties);
|
||||
$properties->setGenericFlag(EntityMetadataFlags::BABY, $this->baby);
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\entity;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||
use function mt_rand;
|
||||
@ -65,4 +66,8 @@ class Zombie extends Living{
|
||||
//TODO: check for equipment and whether it's a baby
|
||||
return 5;
|
||||
}
|
||||
|
||||
public function getPickedItem() : ?Item{
|
||||
return VanillaItems::ZOMBIE_SPAWN_EGG();
|
||||
}
|
||||
}
|
||||
|
146
src/entity/object/EndCrystal.php
Normal file
146
src/entity/object/EndCrystal.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?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\entity\object;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\EntitySizeInfo;
|
||||
use pocketmine\entity\Explosive;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\EntityPreExplodeEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||
use pocketmine\world\Explosion;
|
||||
|
||||
class EndCrystal extends Entity implements Explosive{
|
||||
private const TAG_SHOWBASE = "ShowBottom"; //TAG_Byte
|
||||
|
||||
private const TAG_BLOCKTARGET_X = "BlockTargetX"; //TAG_Int
|
||||
private const TAG_BLOCKTARGET_Y = "BlockTargetY"; //TAG_Int
|
||||
private const TAG_BLOCKTARGET_Z = "BlockTargetZ"; //TAG_Int
|
||||
|
||||
public static function getNetworkTypeId() : string{ return EntityIds::ENDER_CRYSTAL; }
|
||||
|
||||
protected bool $showBase = false;
|
||||
protected ?Vector3 $beamTarget = null;
|
||||
|
||||
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(2.0, 2.0); }
|
||||
|
||||
protected function getInitialDragMultiplier() : float{ return 1.0; }
|
||||
|
||||
protected function getInitialGravity() : float{ return 0.0; }
|
||||
|
||||
public function isFireProof() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getPickedItem() : ?Item{
|
||||
return VanillaItems::END_CRYSTAL();
|
||||
}
|
||||
|
||||
public function showBase() : bool{
|
||||
return $this->showBase;
|
||||
}
|
||||
|
||||
public function setShowBase(bool $showBase) : void{
|
||||
$this->showBase = $showBase;
|
||||
$this->networkPropertiesDirty = true;
|
||||
}
|
||||
|
||||
public function getBeamTarget() : ?Vector3{
|
||||
return $this->beamTarget;
|
||||
}
|
||||
|
||||
public function setBeamTarget(?Vector3 $beamTarget) : void{
|
||||
$this->beamTarget = $beamTarget;
|
||||
$this->networkPropertiesDirty = true;
|
||||
}
|
||||
|
||||
public function attack(EntityDamageEvent $source) : void{
|
||||
parent::attack($source);
|
||||
if(
|
||||
$source->getCause() !== EntityDamageEvent::CAUSE_VOID &&
|
||||
!$this->isFlaggedForDespawn() &&
|
||||
!$source->isCancelled()
|
||||
){
|
||||
$this->flagForDespawn();
|
||||
$this->explode();
|
||||
}
|
||||
}
|
||||
|
||||
protected function initEntity(CompoundTag $nbt) : void{
|
||||
parent::initEntity($nbt);
|
||||
|
||||
$this->setMaxHealth(1);
|
||||
$this->setHealth(1);
|
||||
|
||||
$this->setShowBase($nbt->getByte(self::TAG_SHOWBASE, 0) === 1);
|
||||
|
||||
if(
|
||||
($beamXTag = $nbt->getTag(self::TAG_BLOCKTARGET_X)) instanceof IntTag &&
|
||||
($beamYTag = $nbt->getTag(self::TAG_BLOCKTARGET_Y)) instanceof IntTag &&
|
||||
($beamZTag = $nbt->getTag(self::TAG_BLOCKTARGET_Z)) instanceof IntTag
|
||||
){
|
||||
$this->setBeamTarget(new Vector3($beamXTag->getValue(), $beamYTag->getValue(), $beamZTag->getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public function saveNBT() : CompoundTag{
|
||||
$nbt = parent::saveNBT();
|
||||
|
||||
$nbt->setByte(self::TAG_SHOWBASE, $this->showBase ? 1 : 0);
|
||||
if($this->beamTarget !== null){
|
||||
$nbt->setInt(self::TAG_BLOCKTARGET_X, $this->beamTarget->getFloorX());
|
||||
$nbt->setInt(self::TAG_BLOCKTARGET_Y, $this->beamTarget->getFloorY());
|
||||
$nbt->setInt(self::TAG_BLOCKTARGET_Z, $this->beamTarget->getFloorZ());
|
||||
}
|
||||
return $nbt;
|
||||
}
|
||||
|
||||
public function explode() : void{
|
||||
$ev = new EntityPreExplodeEvent($this, 6);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$explosion = new Explosion($this->getPosition(), $ev->getRadius(), $this);
|
||||
if($ev->isBlockBreaking()){
|
||||
$explosion->explodeA();
|
||||
}
|
||||
$explosion->explodeB();
|
||||
}
|
||||
}
|
||||
|
||||
protected function syncNetworkData(EntityMetadataCollection $properties) : void{
|
||||
parent::syncNetworkData($properties);
|
||||
|
||||
$properties->setGenericFlag(EntityMetadataFlags::SHOWBASE, $this->showBase);
|
||||
$properties->setBlockPos(EntityMetadataProperties::BLOCK_TARGET, BlockPosition::fromVector3($this->beamTarget ?? Vector3::zero()));
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ use pocketmine\entity\Location;
|
||||
use pocketmine\event\entity\EntityBlockChangeEvent;
|
||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
@ -194,6 +195,10 @@ class FallingBlock extends Entity{
|
||||
return $nbt;
|
||||
}
|
||||
|
||||
public function getPickedItem() : ?Item{
|
||||
return $this->block->asItem();
|
||||
}
|
||||
|
||||
protected function syncNetworkData(EntityMetadataCollection $properties) : void{
|
||||
parent::syncNetworkData($properties);
|
||||
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\EntitySizeInfo;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
@ -165,6 +166,10 @@ class Painting extends Entity{
|
||||
));
|
||||
}
|
||||
|
||||
public function getPickedItem() : ?Item{
|
||||
return VanillaItems::PAINTING();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the painting motive (which image is displayed on the painting)
|
||||
*/
|
||||
|
@ -23,11 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\entity\object;
|
||||
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\EntitySizeInfo;
|
||||
use pocketmine\entity\Explosive;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\EntityPreExplodeEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||
@ -127,6 +129,10 @@ class PrimedTNT extends Entity implements Explosive{
|
||||
}
|
||||
}
|
||||
|
||||
public function getPickedItem() : ?Item{
|
||||
return VanillaBlocks::TNT()->setWorksUnderwater($this->worksUnderwater)->asItem();
|
||||
}
|
||||
|
||||
protected function syncNetworkData(EntityMetadataCollection $properties) : void{
|
||||
parent::syncNetworkData($properties);
|
||||
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\data\SavedDataLoadingException;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\object\EndCrystal;
|
||||
use pocketmine\event\entity\EntityCombustByEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageByChildEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||
@ -96,7 +97,7 @@ abstract class Projectile extends Entity{
|
||||
}
|
||||
|
||||
public function canCollideWith(Entity $entity) : bool{
|
||||
return $entity instanceof Living && !$this->onGround;
|
||||
return ($entity instanceof Living || $entity instanceof EndCrystal) && !$this->onGround;
|
||||
}
|
||||
|
||||
public function canBeCollidedWith() : bool{
|
||||
|
53
src/event/player/PlayerEntityPickEvent.php
Normal file
53
src/event/player/PlayerEntityPickEvent.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?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\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
/**
|
||||
* Called when a player middle-clicks on an entity to get an item in creative mode.
|
||||
*/
|
||||
class PlayerEntityPickEvent extends PlayerEvent implements Cancellable{
|
||||
use CancellableTrait;
|
||||
|
||||
public function __construct(
|
||||
Player $player,
|
||||
private Entity $entityClicked,
|
||||
private Item $resultItem
|
||||
){
|
||||
$this->player = $player;
|
||||
}
|
||||
|
||||
public function getEntity() : Entity{
|
||||
return $this->entityClicked;
|
||||
}
|
||||
|
||||
public function getResultItem() : Item{
|
||||
return $this->resultItem;
|
||||
}
|
||||
}
|
@ -42,6 +42,9 @@ class PlayerInteractEvent extends PlayerEvent implements Cancellable{
|
||||
|
||||
protected Vector3 $touchVector;
|
||||
|
||||
protected bool $useItem = true;
|
||||
protected bool $useBlock = true;
|
||||
|
||||
public function __construct(
|
||||
Player $player,
|
||||
protected Item $item,
|
||||
@ -73,4 +76,28 @@ class PlayerInteractEvent extends PlayerEvent implements Cancellable{
|
||||
public function getFace() : int{
|
||||
return $this->blockFace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the item may react to the interaction. If disabled, items such as spawn eggs will not activate.
|
||||
* This does NOT prevent blocks from being placed - it makes the item behave as if the player is sneaking.
|
||||
*/
|
||||
public function useItem() : bool{ return $this->useItem; }
|
||||
|
||||
/**
|
||||
* Sets whether the used item may react to the interaction. If false, items such as spawn eggs will not activate.
|
||||
* This does NOT prevent blocks from being placed - it makes the item behave as if the player is sneaking.
|
||||
*/
|
||||
public function setUseItem(bool $useItem) : void{ $this->useItem = $useItem; }
|
||||
|
||||
/**
|
||||
* Returns whether the block may react to the interaction. If false, doors, fence gates and trapdoors will not
|
||||
* respond, containers will not open, etc.
|
||||
*/
|
||||
public function useBlock() : bool{ return $this->useBlock; }
|
||||
|
||||
/**
|
||||
* Sets whether the block may react to the interaction. If false, doors, fence gates and trapdoors will not
|
||||
* respond, containers will not open, etc.
|
||||
*/
|
||||
public function setUseBlock(bool $useBlock) : void{ $this->useBlock = $useBlock; }
|
||||
}
|
||||
|
59
src/item/EndCrystal.php
Normal file
59
src/item/EndCrystal.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?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\item;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockTypeIds;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\object\EndCrystal as EntityEndCrystal;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use function count;
|
||||
|
||||
class EndCrystal extends Item{
|
||||
|
||||
public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, array &$returnedItems) : ItemUseResult{
|
||||
if($blockClicked->getTypeId() === BlockTypeIds::OBSIDIAN || $blockClicked->getTypeId() === BlockTypeIds::BEDROCK){
|
||||
$pos = $blockClicked->getPosition();
|
||||
$world = $pos->getWorld();
|
||||
$bb = AxisAlignedBB::one()
|
||||
->offset($pos->getX(), $pos->getY(), $pos->getZ())
|
||||
->extend(Facing::UP, 1);
|
||||
if(
|
||||
count($world->getNearbyEntities($bb)) === 0 &&
|
||||
$blockClicked->getSide(Facing::UP)->getTypeId() === BlockTypeIds::AIR &&
|
||||
$blockClicked->getSide(Facing::UP, 2)->getTypeId() === BlockTypeIds::AIR
|
||||
){
|
||||
$crystal = new EntityEndCrystal(Location::fromObject($pos->add(0.5, 1, 0.5), $world));
|
||||
$crystal->spawnToAll();
|
||||
|
||||
$this->pop();
|
||||
return ItemUseResult::SUCCESS;
|
||||
}
|
||||
}
|
||||
return ItemUseResult::NONE;
|
||||
}
|
||||
}
|
71
src/item/GoatHorn.php
Normal file
71
src/item/GoatHorn.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\item;
|
||||
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\GoatHornSound;
|
||||
|
||||
class GoatHorn extends Item implements Releasable{
|
||||
|
||||
private GoatHornType $goatHornType = GoatHornType::PONDER;
|
||||
|
||||
protected function describeState(RuntimeDataDescriber $w) : void{
|
||||
$w->enum($this->goatHornType);
|
||||
}
|
||||
|
||||
public function getHornType() : GoatHornType{ return $this->goatHornType; }
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setHornType(GoatHornType $type) : self{
|
||||
$this->goatHornType = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMaxStackSize() : int{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getCooldownTicks() : int{
|
||||
return 140;
|
||||
}
|
||||
|
||||
public function getCooldownTag() : ?string{
|
||||
return ItemCooldownTags::GOAT_HORN;
|
||||
}
|
||||
|
||||
public function canStartUsingItem(Player $player) : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onClickAir(Player $player, Vector3 $directionVector, array &$returnedItems) : ItemUseResult{
|
||||
$position = $player->getPosition();
|
||||
$position->getWorld()->addSound($position, new GoatHornSound($this->goatHornType));
|
||||
|
||||
return ItemUseResult::SUCCESS;
|
||||
}
|
||||
}
|
36
src/item/GoatHornType.php
Normal file
36
src/item/GoatHornType.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?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\item;
|
||||
|
||||
enum GoatHornType{
|
||||
|
||||
case PONDER;
|
||||
case SING;
|
||||
case SEEK;
|
||||
case FEEL;
|
||||
case ADMIRE;
|
||||
case CALL;
|
||||
case YEARN;
|
||||
case DREAM;
|
||||
}
|
@ -324,8 +324,10 @@ final class ItemTypeIds{
|
||||
public const SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = 20285;
|
||||
public const PITCHER_POD = 20286;
|
||||
public const NAME_TAG = 20287;
|
||||
public const GOAT_HORN = 20288;
|
||||
public const END_CRYSTAL = 20289;
|
||||
|
||||
public const FIRST_UNUSED_ITEM_ID = 20288;
|
||||
public const FIRST_UNUSED_ITEM_ID = 20290;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;
|
||||
|
||||
|
@ -1184,6 +1184,13 @@ final class StringToItemParser extends StringToTParser{
|
||||
|
||||
$result->register($prefix("dye"), fn() => Items::DYE()->setColor($color));
|
||||
}
|
||||
|
||||
foreach(GoatHornType::cases() as $goatHornType){
|
||||
$prefix = fn(string $name) => strtolower($goatHornType->name) . "_" . $name;
|
||||
|
||||
$result->register($prefix("goat_horn"), fn() => Items::GOAT_HORN()->setHornType($goatHornType));
|
||||
}
|
||||
|
||||
foreach(SuspiciousStewType::cases() as $suspiciousStewType){
|
||||
$prefix = fn(string $name) => strtolower($suspiciousStewType->name) . "_" . $name;
|
||||
|
||||
@ -1323,6 +1330,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("enchanted_book", fn() => Items::ENCHANTED_BOOK());
|
||||
$result->register("enchanted_golden_apple", fn() => Items::ENCHANTED_GOLDEN_APPLE());
|
||||
$result->register("enchanting_bottle", fn() => Items::EXPERIENCE_BOTTLE());
|
||||
$result->register("end_crystal", fn() => Items::END_CRYSTAL());
|
||||
$result->register("ender_pearl", fn() => Items::ENDER_PEARL());
|
||||
$result->register("experience_bottle", fn() => Items::EXPERIENCE_BOTTLE());
|
||||
$result->register("eye_armor_trim_smithing_template", fn() => Items::EYE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
@ -1341,6 +1349,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("glow_berries", fn() => Items::GLOW_BERRIES());
|
||||
$result->register("glow_ink_sac", fn() => Items::GLOW_INK_SAC());
|
||||
$result->register("glowstone_dust", fn() => Items::GLOWSTONE_DUST());
|
||||
$result->register("goat_horn", fn() => Items::GOAT_HORN());
|
||||
$result->register("gold_axe", fn() => Items::GOLDEN_AXE());
|
||||
$result->register("gold_boots", fn() => Items::GOLDEN_BOOTS());
|
||||
$result->register("gold_chestplate", fn() => Items::GOLDEN_CHESTPLATE());
|
||||
|
@ -33,11 +33,12 @@ use pocketmine\entity\Zombie;
|
||||
use pocketmine\inventory\ArmorInventory;
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTags as EnchantmentTags;
|
||||
use pocketmine\item\ItemIdentifier as IID;
|
||||
use pocketmine\item\ItemTypeIds as Ids;
|
||||
use pocketmine\item\VanillaArmorMaterials as ArmorMaterials;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\utils\CloningRegistryTrait;
|
||||
use pocketmine\world\World;
|
||||
use function is_int;
|
||||
use function mb_strtoupper;
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
@ -157,6 +158,7 @@ use function strtolower;
|
||||
* @method static EnchantedBook ENCHANTED_BOOK()
|
||||
* @method static GoldenAppleEnchanted ENCHANTED_GOLDEN_APPLE()
|
||||
* @method static EnderPearl ENDER_PEARL()
|
||||
* @method static EndCrystal END_CRYSTAL()
|
||||
* @method static ExperienceBottle EXPERIENCE_BOTTLE()
|
||||
* @method static Item EYE_ARMOR_TRIM_SMITHING_TEMPLATE()
|
||||
* @method static Item FEATHER()
|
||||
@ -171,6 +173,7 @@ use function strtolower;
|
||||
* @method static Item GLOWSTONE_DUST()
|
||||
* @method static GlowBerries GLOW_BERRIES()
|
||||
* @method static Item GLOW_INK_SAC()
|
||||
* @method static GoatHorn GOAT_HORN()
|
||||
* @method static GoldenApple GOLDEN_APPLE()
|
||||
* @method static Axe GOLDEN_AXE()
|
||||
* @method static Armor GOLDEN_BOOTS()
|
||||
@ -339,8 +342,29 @@ final class VanillaItems{
|
||||
//NOOP
|
||||
}
|
||||
|
||||
protected static function register(string $name, Item $item) : void{
|
||||
/**
|
||||
* @phpstan-template TItem of Item
|
||||
* @phpstan-param \Closure(IID) : TItem $createItem
|
||||
* @phpstan-return TItem
|
||||
*/
|
||||
protected static function register(string $name, \Closure $createItem) : Item{
|
||||
//this sketchy hack allows us to avoid manually writing the constants inline
|
||||
//since type IDs are generated from this class anyway, I'm OK with this hack
|
||||
//nonetheless, we should try to get rid of it in a future major version (e.g by using string type IDs)
|
||||
$reflect = new \ReflectionClass(ItemTypeIds::class);
|
||||
$typeId = $reflect->getConstant(mb_strtoupper($name));
|
||||
if(!is_int($typeId)){
|
||||
//this allows registering new stuff without adding new type ID constants
|
||||
//this reduces the number of mandatory steps to test new features in local development
|
||||
\GlobalLogger::get()->error(self::class . ": No constant type ID found for $name, generating a new one");
|
||||
$typeId = ItemTypeIds::newId();
|
||||
}
|
||||
|
||||
$item = $createItem(new IID($typeId));
|
||||
|
||||
self::_registryRegister($name, $item);
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,242 +384,238 @@ final class VanillaItems{
|
||||
self::registerTierToolItems();
|
||||
self::registerSmithingTemplates();
|
||||
|
||||
self::register("air", Blocks::AIR()->asItem()->setCount(0));
|
||||
//this doesn't use the regular register() because it doesn't have an item typeID
|
||||
//in the future we'll probably want to dissociate this from the air block and make a proper null item
|
||||
self::_registryRegister("air", Blocks::AIR()->asItem()->setCount(0));
|
||||
|
||||
self::register("acacia_sign", new ItemBlockWallOrFloor(new IID(Ids::ACACIA_SIGN), Blocks::ACACIA_SIGN(), Blocks::ACACIA_WALL_SIGN()));
|
||||
self::register("amethyst_shard", new Item(new IID(Ids::AMETHYST_SHARD), "Amethyst Shard"));
|
||||
self::register("apple", new Apple(new IID(Ids::APPLE), "Apple"));
|
||||
self::register("arrow", new Arrow(new IID(Ids::ARROW), "Arrow"));
|
||||
self::register("baked_potato", new BakedPotato(new IID(Ids::BAKED_POTATO), "Baked Potato"));
|
||||
self::register("bamboo", new Bamboo(new IID(Ids::BAMBOO), "Bamboo"));
|
||||
self::register("banner", new Banner(new IID(Ids::BANNER), Blocks::BANNER(), Blocks::WALL_BANNER()));
|
||||
self::register("beetroot", new Beetroot(new IID(Ids::BEETROOT), "Beetroot"));
|
||||
self::register("beetroot_seeds", new BeetrootSeeds(new IID(Ids::BEETROOT_SEEDS), "Beetroot Seeds"));
|
||||
self::register("beetroot_soup", new BeetrootSoup(new IID(Ids::BEETROOT_SOUP), "Beetroot Soup"));
|
||||
self::register("birch_sign", new ItemBlockWallOrFloor(new IID(Ids::BIRCH_SIGN), Blocks::BIRCH_SIGN(), Blocks::BIRCH_WALL_SIGN()));
|
||||
self::register("blaze_powder", new Item(new IID(Ids::BLAZE_POWDER), "Blaze Powder"));
|
||||
self::register("blaze_rod", new BlazeRod(new IID(Ids::BLAZE_ROD), "Blaze Rod"));
|
||||
self::register("bleach", new Item(new IID(Ids::BLEACH), "Bleach"));
|
||||
self::register("bone", new Item(new IID(Ids::BONE), "Bone"));
|
||||
self::register("bone_meal", new Fertilizer(new IID(Ids::BONE_MEAL), "Bone Meal"));
|
||||
self::register("book", new Book(new IID(Ids::BOOK), "Book", [EnchantmentTags::ALL]));
|
||||
self::register("bow", new Bow(new IID(Ids::BOW), "Bow", [EnchantmentTags::BOW]));
|
||||
self::register("bowl", new Bowl(new IID(Ids::BOWL), "Bowl"));
|
||||
self::register("bread", new Bread(new IID(Ids::BREAD), "Bread"));
|
||||
self::register("brick", new Item(new IID(Ids::BRICK), "Brick"));
|
||||
self::register("bucket", new Bucket(new IID(Ids::BUCKET), "Bucket"));
|
||||
self::register("carrot", new Carrot(new IID(Ids::CARROT), "Carrot"));
|
||||
self::register("charcoal", new Coal(new IID(Ids::CHARCOAL), "Charcoal"));
|
||||
self::register("cherry_sign", new ItemBlockWallOrFloor(new IID(Ids::CHERRY_SIGN), Blocks::CHERRY_SIGN(), Blocks::CHERRY_WALL_SIGN()));
|
||||
self::register("chemical_aluminium_oxide", new Item(new IID(Ids::CHEMICAL_ALUMINIUM_OXIDE), "Aluminium Oxide"));
|
||||
self::register("chemical_ammonia", new Item(new IID(Ids::CHEMICAL_AMMONIA), "Ammonia"));
|
||||
self::register("chemical_barium_sulphate", new Item(new IID(Ids::CHEMICAL_BARIUM_SULPHATE), "Barium Sulphate"));
|
||||
self::register("chemical_benzene", new Item(new IID(Ids::CHEMICAL_BENZENE), "Benzene"));
|
||||
self::register("chemical_boron_trioxide", new Item(new IID(Ids::CHEMICAL_BORON_TRIOXIDE), "Boron Trioxide"));
|
||||
self::register("chemical_calcium_bromide", new Item(new IID(Ids::CHEMICAL_CALCIUM_BROMIDE), "Calcium Bromide"));
|
||||
self::register("chemical_calcium_chloride", new Item(new IID(Ids::CHEMICAL_CALCIUM_CHLORIDE), "Calcium Chloride"));
|
||||
self::register("chemical_cerium_chloride", new Item(new IID(Ids::CHEMICAL_CERIUM_CHLORIDE), "Cerium Chloride"));
|
||||
self::register("chemical_charcoal", new Item(new IID(Ids::CHEMICAL_CHARCOAL), "Charcoal"));
|
||||
self::register("chemical_crude_oil", new Item(new IID(Ids::CHEMICAL_CRUDE_OIL), "Crude Oil"));
|
||||
self::register("chemical_glue", new Item(new IID(Ids::CHEMICAL_GLUE), "Glue"));
|
||||
self::register("chemical_hydrogen_peroxide", new Item(new IID(Ids::CHEMICAL_HYDROGEN_PEROXIDE), "Hydrogen Peroxide"));
|
||||
self::register("chemical_hypochlorite", new Item(new IID(Ids::CHEMICAL_HYPOCHLORITE), "Hypochlorite"));
|
||||
self::register("chemical_ink", new Item(new IID(Ids::CHEMICAL_INK), "Ink"));
|
||||
self::register("chemical_iron_sulphide", new Item(new IID(Ids::CHEMICAL_IRON_SULPHIDE), "Iron Sulphide"));
|
||||
self::register("chemical_latex", new Item(new IID(Ids::CHEMICAL_LATEX), "Latex"));
|
||||
self::register("chemical_lithium_hydride", new Item(new IID(Ids::CHEMICAL_LITHIUM_HYDRIDE), "Lithium Hydride"));
|
||||
self::register("chemical_luminol", new Item(new IID(Ids::CHEMICAL_LUMINOL), "Luminol"));
|
||||
self::register("chemical_magnesium_nitrate", new Item(new IID(Ids::CHEMICAL_MAGNESIUM_NITRATE), "Magnesium Nitrate"));
|
||||
self::register("chemical_magnesium_oxide", new Item(new IID(Ids::CHEMICAL_MAGNESIUM_OXIDE), "Magnesium Oxide"));
|
||||
self::register("chemical_magnesium_salts", new Item(new IID(Ids::CHEMICAL_MAGNESIUM_SALTS), "Magnesium Salts"));
|
||||
self::register("chemical_mercuric_chloride", new Item(new IID(Ids::CHEMICAL_MERCURIC_CHLORIDE), "Mercuric Chloride"));
|
||||
self::register("chemical_polyethylene", new Item(new IID(Ids::CHEMICAL_POLYETHYLENE), "Polyethylene"));
|
||||
self::register("chemical_potassium_chloride", new Item(new IID(Ids::CHEMICAL_POTASSIUM_CHLORIDE), "Potassium Chloride"));
|
||||
self::register("chemical_potassium_iodide", new Item(new IID(Ids::CHEMICAL_POTASSIUM_IODIDE), "Potassium Iodide"));
|
||||
self::register("chemical_rubbish", new Item(new IID(Ids::CHEMICAL_RUBBISH), "Rubbish"));
|
||||
self::register("chemical_salt", new Item(new IID(Ids::CHEMICAL_SALT), "Salt"));
|
||||
self::register("chemical_soap", new Item(new IID(Ids::CHEMICAL_SOAP), "Soap"));
|
||||
self::register("chemical_sodium_acetate", new Item(new IID(Ids::CHEMICAL_SODIUM_ACETATE), "Sodium Acetate"));
|
||||
self::register("chemical_sodium_fluoride", new Item(new IID(Ids::CHEMICAL_SODIUM_FLUORIDE), "Sodium Fluoride"));
|
||||
self::register("chemical_sodium_hydride", new Item(new IID(Ids::CHEMICAL_SODIUM_HYDRIDE), "Sodium Hydride"));
|
||||
self::register("chemical_sodium_hydroxide", new Item(new IID(Ids::CHEMICAL_SODIUM_HYDROXIDE), "Sodium Hydroxide"));
|
||||
self::register("chemical_sodium_hypochlorite", new Item(new IID(Ids::CHEMICAL_SODIUM_HYPOCHLORITE), "Sodium Hypochlorite"));
|
||||
self::register("chemical_sodium_oxide", new Item(new IID(Ids::CHEMICAL_SODIUM_OXIDE), "Sodium Oxide"));
|
||||
self::register("chemical_sugar", new Item(new IID(Ids::CHEMICAL_SUGAR), "Sugar"));
|
||||
self::register("chemical_sulphate", new Item(new IID(Ids::CHEMICAL_SULPHATE), "Sulphate"));
|
||||
self::register("chemical_tungsten_chloride", new Item(new IID(Ids::CHEMICAL_TUNGSTEN_CHLORIDE), "Tungsten Chloride"));
|
||||
self::register("chemical_water", new Item(new IID(Ids::CHEMICAL_WATER), "Water"));
|
||||
self::register("chorus_fruit", new ChorusFruit(new IID(Ids::CHORUS_FRUIT), "Chorus Fruit"));
|
||||
self::register("clay", new Item(new IID(Ids::CLAY), "Clay"));
|
||||
self::register("clock", new Clock(new IID(Ids::CLOCK), "Clock"));
|
||||
self::register("clownfish", new Clownfish(new IID(Ids::CLOWNFISH), "Clownfish"));
|
||||
self::register("coal", new Coal(new IID(Ids::COAL), "Coal"));
|
||||
self::register("cocoa_beans", new CocoaBeans(new IID(Ids::COCOA_BEANS), "Cocoa Beans"));
|
||||
self::register("compass", new Compass(new IID(Ids::COMPASS), "Compass", [EnchantmentTags::COMPASS]));
|
||||
self::register("cooked_chicken", new CookedChicken(new IID(Ids::COOKED_CHICKEN), "Cooked Chicken"));
|
||||
self::register("cooked_fish", new CookedFish(new IID(Ids::COOKED_FISH), "Cooked Fish"));
|
||||
self::register("cooked_mutton", new CookedMutton(new IID(Ids::COOKED_MUTTON), "Cooked Mutton"));
|
||||
self::register("cooked_porkchop", new CookedPorkchop(new IID(Ids::COOKED_PORKCHOP), "Cooked Porkchop"));
|
||||
self::register("cooked_rabbit", new CookedRabbit(new IID(Ids::COOKED_RABBIT), "Cooked Rabbit"));
|
||||
self::register("cooked_salmon", new CookedSalmon(new IID(Ids::COOKED_SALMON), "Cooked Salmon"));
|
||||
self::register("cookie", new Cookie(new IID(Ids::COOKIE), "Cookie"));
|
||||
self::register("copper_ingot", new Item(new IID(Ids::COPPER_INGOT), "Copper Ingot"));
|
||||
self::register("coral_fan", new CoralFan(new IID(Ids::CORAL_FAN)));
|
||||
self::register("crimson_sign", new ItemBlockWallOrFloor(new IID(Ids::CRIMSON_SIGN), Blocks::CRIMSON_SIGN(), Blocks::CRIMSON_WALL_SIGN()));
|
||||
self::register("dark_oak_sign", new ItemBlockWallOrFloor(new IID(Ids::DARK_OAK_SIGN), Blocks::DARK_OAK_SIGN(), Blocks::DARK_OAK_WALL_SIGN()));
|
||||
self::register("diamond", new Item(new IID(Ids::DIAMOND), "Diamond"));
|
||||
self::register("disc_fragment_5", new Item(new IID(Ids::DISC_FRAGMENT_5), "Disc Fragment (5)"));
|
||||
self::register("dragon_breath", new Item(new IID(Ids::DRAGON_BREATH), "Dragon's Breath"));
|
||||
self::register("dried_kelp", new DriedKelp(new IID(Ids::DRIED_KELP), "Dried Kelp"));
|
||||
self::register("acacia_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::ACACIA_SIGN(), Blocks::ACACIA_WALL_SIGN()));
|
||||
self::register("amethyst_shard", fn(IID $id) => new Item($id, "Amethyst Shard"));
|
||||
self::register("apple", fn(IID $id) => new Apple($id, "Apple"));
|
||||
self::register("arrow", fn(IID $id) => new Arrow($id, "Arrow"));
|
||||
self::register("baked_potato", fn(IID $id) => new BakedPotato($id, "Baked Potato"));
|
||||
self::register("bamboo", fn(IID $id) => new Bamboo($id, "Bamboo"));
|
||||
self::register("banner", fn(IID $id) => new Banner($id, Blocks::BANNER(), Blocks::WALL_BANNER()));
|
||||
self::register("beetroot", fn(IID $id) => new Beetroot($id, "Beetroot"));
|
||||
self::register("beetroot_seeds", fn(IID $id) => new BeetrootSeeds($id, "Beetroot Seeds"));
|
||||
self::register("beetroot_soup", fn(IID $id) => new BeetrootSoup($id, "Beetroot Soup"));
|
||||
self::register("birch_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::BIRCH_SIGN(), Blocks::BIRCH_WALL_SIGN()));
|
||||
self::register("blaze_powder", fn(IID $id) => new Item($id, "Blaze Powder"));
|
||||
self::register("blaze_rod", fn(IID $id) => new BlazeRod($id, "Blaze Rod"));
|
||||
self::register("bleach", fn(IID $id) => new Item($id, "Bleach"));
|
||||
self::register("bone", fn(IID $id) => new Item($id, "Bone"));
|
||||
self::register("bone_meal", fn(IID $id) => new Fertilizer($id, "Bone Meal"));
|
||||
self::register("book", fn(IID $id) => new Book($id, "Book", [EnchantmentTags::ALL]));
|
||||
self::register("bow", fn(IID $id) => new Bow($id, "Bow", [EnchantmentTags::BOW]));
|
||||
self::register("bowl", fn(IID $id) => new Bowl($id, "Bowl"));
|
||||
self::register("bread", fn(IID $id) => new Bread($id, "Bread"));
|
||||
self::register("brick", fn(IID $id) => new Item($id, "Brick"));
|
||||
self::register("bucket", fn(IID $id) => new Bucket($id, "Bucket"));
|
||||
self::register("carrot", fn(IID $id) => new Carrot($id, "Carrot"));
|
||||
self::register("charcoal", fn(IID $id) => new Coal($id, "Charcoal"));
|
||||
self::register("cherry_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::CHERRY_SIGN(), Blocks::CHERRY_WALL_SIGN()));
|
||||
self::register("chemical_aluminium_oxide", fn(IID $id) => new Item($id, "Aluminium Oxide"));
|
||||
self::register("chemical_ammonia", fn(IID $id) => new Item($id, "Ammonia"));
|
||||
self::register("chemical_barium_sulphate", fn(IID $id) => new Item($id, "Barium Sulphate"));
|
||||
self::register("chemical_benzene", fn(IID $id) => new Item($id, "Benzene"));
|
||||
self::register("chemical_boron_trioxide", fn(IID $id) => new Item($id, "Boron Trioxide"));
|
||||
self::register("chemical_calcium_bromide", fn(IID $id) => new Item($id, "Calcium Bromide"));
|
||||
self::register("chemical_calcium_chloride", fn(IID $id) => new Item($id, "Calcium Chloride"));
|
||||
self::register("chemical_cerium_chloride", fn(IID $id) => new Item($id, "Cerium Chloride"));
|
||||
self::register("chemical_charcoal", fn(IID $id) => new Item($id, "Charcoal"));
|
||||
self::register("chemical_crude_oil", fn(IID $id) => new Item($id, "Crude Oil"));
|
||||
self::register("chemical_glue", fn(IID $id) => new Item($id, "Glue"));
|
||||
self::register("chemical_hydrogen_peroxide", fn(IID $id) => new Item($id, "Hydrogen Peroxide"));
|
||||
self::register("chemical_hypochlorite", fn(IID $id) => new Item($id, "Hypochlorite"));
|
||||
self::register("chemical_ink", fn(IID $id) => new Item($id, "Ink"));
|
||||
self::register("chemical_iron_sulphide", fn(IID $id) => new Item($id, "Iron Sulphide"));
|
||||
self::register("chemical_latex", fn(IID $id) => new Item($id, "Latex"));
|
||||
self::register("chemical_lithium_hydride", fn(IID $id) => new Item($id, "Lithium Hydride"));
|
||||
self::register("chemical_luminol", fn(IID $id) => new Item($id, "Luminol"));
|
||||
self::register("chemical_magnesium_nitrate", fn(IID $id) => new Item($id, "Magnesium Nitrate"));
|
||||
self::register("chemical_magnesium_oxide", fn(IID $id) => new Item($id, "Magnesium Oxide"));
|
||||
self::register("chemical_magnesium_salts", fn(IID $id) => new Item($id, "Magnesium Salts"));
|
||||
self::register("chemical_mercuric_chloride", fn(IID $id) => new Item($id, "Mercuric Chloride"));
|
||||
self::register("chemical_polyethylene", fn(IID $id) => new Item($id, "Polyethylene"));
|
||||
self::register("chemical_potassium_chloride", fn(IID $id) => new Item($id, "Potassium Chloride"));
|
||||
self::register("chemical_potassium_iodide", fn(IID $id) => new Item($id, "Potassium Iodide"));
|
||||
self::register("chemical_rubbish", fn(IID $id) => new Item($id, "Rubbish"));
|
||||
self::register("chemical_salt", fn(IID $id) => new Item($id, "Salt"));
|
||||
self::register("chemical_soap", fn(IID $id) => new Item($id, "Soap"));
|
||||
self::register("chemical_sodium_acetate", fn(IID $id) => new Item($id, "Sodium Acetate"));
|
||||
self::register("chemical_sodium_fluoride", fn(IID $id) => new Item($id, "Sodium Fluoride"));
|
||||
self::register("chemical_sodium_hydride", fn(IID $id) => new Item($id, "Sodium Hydride"));
|
||||
self::register("chemical_sodium_hydroxide", fn(IID $id) => new Item($id, "Sodium Hydroxide"));
|
||||
self::register("chemical_sodium_hypochlorite", fn(IID $id) => new Item($id, "Sodium Hypochlorite"));
|
||||
self::register("chemical_sodium_oxide", fn(IID $id) => new Item($id, "Sodium Oxide"));
|
||||
self::register("chemical_sugar", fn(IID $id) => new Item($id, "Sugar"));
|
||||
self::register("chemical_sulphate", fn(IID $id) => new Item($id, "Sulphate"));
|
||||
self::register("chemical_tungsten_chloride", fn(IID $id) => new Item($id, "Tungsten Chloride"));
|
||||
self::register("chemical_water", fn(IID $id) => new Item($id, "Water"));
|
||||
self::register("chorus_fruit", fn(IID $id) => new ChorusFruit($id, "Chorus Fruit"));
|
||||
self::register("clay", fn(IID $id) => new Item($id, "Clay"));
|
||||
self::register("clock", fn(IID $id) => new Clock($id, "Clock"));
|
||||
self::register("clownfish", fn(IID $id) => new Clownfish($id, "Clownfish"));
|
||||
self::register("coal", fn(IID $id) => new Coal($id, "Coal"));
|
||||
self::register("cocoa_beans", fn(IID $id) => new CocoaBeans($id, "Cocoa Beans"));
|
||||
self::register("compass", fn(IID $id) => new Compass($id, "Compass", [EnchantmentTags::COMPASS]));
|
||||
self::register("cooked_chicken", fn(IID $id) => new CookedChicken($id, "Cooked Chicken"));
|
||||
self::register("cooked_fish", fn(IID $id) => new CookedFish($id, "Cooked Fish"));
|
||||
self::register("cooked_mutton", fn(IID $id) => new CookedMutton($id, "Cooked Mutton"));
|
||||
self::register("cooked_porkchop", fn(IID $id) => new CookedPorkchop($id, "Cooked Porkchop"));
|
||||
self::register("cooked_rabbit", fn(IID $id) => new CookedRabbit($id, "Cooked Rabbit"));
|
||||
self::register("cooked_salmon", fn(IID $id) => new CookedSalmon($id, "Cooked Salmon"));
|
||||
self::register("cookie", fn(IID $id) => new Cookie($id, "Cookie"));
|
||||
self::register("copper_ingot", fn(IID $id) => new Item($id, "Copper Ingot"));
|
||||
self::register("coral_fan", fn(IID $id) => new CoralFan($id));
|
||||
self::register("crimson_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::CRIMSON_SIGN(), Blocks::CRIMSON_WALL_SIGN()));
|
||||
self::register("dark_oak_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::DARK_OAK_SIGN(), Blocks::DARK_OAK_WALL_SIGN()));
|
||||
self::register("diamond", fn(IID $id) => new Item($id, "Diamond"));
|
||||
self::register("disc_fragment_5", fn(IID $id) => new Item($id, "Disc Fragment (5)"));
|
||||
self::register("dragon_breath", fn(IID $id) => new Item($id, "Dragon's Breath"));
|
||||
self::register("dried_kelp", fn(IID $id) => new DriedKelp($id, "Dried Kelp"));
|
||||
//TODO: add interface to dye-colour objects
|
||||
self::register("dye", new Dye(new IID(Ids::DYE), "Dye"));
|
||||
self::register("echo_shard", new Item(new IID(Ids::ECHO_SHARD), "Echo Shard"));
|
||||
self::register("egg", new Egg(new IID(Ids::EGG), "Egg"));
|
||||
self::register("emerald", new Item(new IID(Ids::EMERALD), "Emerald"));
|
||||
self::register("enchanted_book", new EnchantedBook(new IID(Ids::ENCHANTED_BOOK), "Enchanted Book", [EnchantmentTags::ALL]));
|
||||
self::register("enchanted_golden_apple", new GoldenAppleEnchanted(new IID(Ids::ENCHANTED_GOLDEN_APPLE), "Enchanted Golden Apple"));
|
||||
self::register("ender_pearl", new EnderPearl(new IID(Ids::ENDER_PEARL), "Ender Pearl"));
|
||||
self::register("experience_bottle", new ExperienceBottle(new IID(Ids::EXPERIENCE_BOTTLE), "Bottle o' Enchanting"));
|
||||
self::register("feather", new Item(new IID(Ids::FEATHER), "Feather"));
|
||||
self::register("fermented_spider_eye", new Item(new IID(Ids::FERMENTED_SPIDER_EYE), "Fermented Spider Eye"));
|
||||
self::register("fire_charge", new FireCharge(new IID(Ids::FIRE_CHARGE), "Fire Charge"));
|
||||
self::register("fishing_rod", new FishingRod(new IID(Ids::FISHING_ROD), "Fishing Rod", [EnchantmentTags::FISHING_ROD]));
|
||||
self::register("flint", new Item(new IID(Ids::FLINT), "Flint"));
|
||||
self::register("flint_and_steel", new FlintSteel(new IID(Ids::FLINT_AND_STEEL), "Flint and Steel", [EnchantmentTags::FLINT_AND_STEEL]));
|
||||
self::register("ghast_tear", new Item(new IID(Ids::GHAST_TEAR), "Ghast Tear"));
|
||||
self::register("glass_bottle", new GlassBottle(new IID(Ids::GLASS_BOTTLE), "Glass Bottle"));
|
||||
self::register("glistering_melon", new Item(new IID(Ids::GLISTERING_MELON), "Glistering Melon"));
|
||||
self::register("glow_berries", new GlowBerries(new IID(Ids::GLOW_BERRIES), "Glow Berries"));
|
||||
self::register("glow_ink_sac", new Item(new IID(Ids::GLOW_INK_SAC), "Glow Ink Sac"));
|
||||
self::register("glowstone_dust", new Item(new IID(Ids::GLOWSTONE_DUST), "Glowstone Dust"));
|
||||
self::register("gold_ingot", new Item(new IID(Ids::GOLD_INGOT), "Gold Ingot"));
|
||||
self::register("gold_nugget", new Item(new IID(Ids::GOLD_NUGGET), "Gold Nugget"));
|
||||
self::register("golden_apple", new GoldenApple(new IID(Ids::GOLDEN_APPLE), "Golden Apple"));
|
||||
self::register("golden_carrot", new GoldenCarrot(new IID(Ids::GOLDEN_CARROT), "Golden Carrot"));
|
||||
self::register("gunpowder", new Item(new IID(Ids::GUNPOWDER), "Gunpowder"));
|
||||
self::register("heart_of_the_sea", new Item(new IID(Ids::HEART_OF_THE_SEA), "Heart of the Sea"));
|
||||
self::register("honey_bottle", new HoneyBottle(new IID(Ids::HONEY_BOTTLE), "Honey Bottle"));
|
||||
self::register("honeycomb", new Item(new IID(Ids::HONEYCOMB), "Honeycomb"));
|
||||
self::register("ink_sac", new Item(new IID(Ids::INK_SAC), "Ink Sac"));
|
||||
self::register("iron_ingot", new Item(new IID(Ids::IRON_INGOT), "Iron Ingot"));
|
||||
self::register("iron_nugget", new Item(new IID(Ids::IRON_NUGGET), "Iron Nugget"));
|
||||
self::register("jungle_sign", new ItemBlockWallOrFloor(new IID(Ids::JUNGLE_SIGN), Blocks::JUNGLE_SIGN(), Blocks::JUNGLE_WALL_SIGN()));
|
||||
self::register("lapis_lazuli", new Item(new IID(Ids::LAPIS_LAZULI), "Lapis Lazuli"));
|
||||
self::register("lava_bucket", new LiquidBucket(new IID(Ids::LAVA_BUCKET), "Lava Bucket", Blocks::LAVA()));
|
||||
self::register("leather", new Item(new IID(Ids::LEATHER), "Leather"));
|
||||
self::register("magma_cream", new Item(new IID(Ids::MAGMA_CREAM), "Magma Cream"));
|
||||
self::register("mangrove_sign", new ItemBlockWallOrFloor(new IID(Ids::MANGROVE_SIGN), Blocks::MANGROVE_SIGN(), Blocks::MANGROVE_WALL_SIGN()));
|
||||
self::register("medicine", new Medicine(new IID(Ids::MEDICINE), "Medicine"));
|
||||
self::register("melon", new Melon(new IID(Ids::MELON), "Melon"));
|
||||
self::register("melon_seeds", new MelonSeeds(new IID(Ids::MELON_SEEDS), "Melon Seeds"));
|
||||
self::register("milk_bucket", new MilkBucket(new IID(Ids::MILK_BUCKET), "Milk Bucket"));
|
||||
self::register("minecart", new Minecart(new IID(Ids::MINECART), "Minecart"));
|
||||
self::register("mushroom_stew", new MushroomStew(new IID(Ids::MUSHROOM_STEW), "Mushroom Stew"));
|
||||
self::register("name_tag", new NameTag(new IID(Ids::NAME_TAG), "Name Tag"));
|
||||
self::register("nautilus_shell", new Item(new IID(Ids::NAUTILUS_SHELL), "Nautilus Shell"));
|
||||
self::register("nether_brick", new Item(new IID(Ids::NETHER_BRICK), "Nether Brick"));
|
||||
self::register("nether_quartz", new Item(new IID(Ids::NETHER_QUARTZ), "Nether Quartz"));
|
||||
self::register("nether_star", new Item(new IID(Ids::NETHER_STAR), "Nether Star"));
|
||||
self::register("netherite_ingot", new class(new IID(Ids::NETHERITE_INGOT), "Netherite Ingot") extends Item{
|
||||
self::register("dye", fn(IID $id) => new Dye($id, "Dye"));
|
||||
self::register("echo_shard", fn(IID $id) => new Item($id, "Echo Shard"));
|
||||
self::register("egg", fn(IID $id) => new Egg($id, "Egg"));
|
||||
self::register("emerald", fn(IID $id) => new Item($id, "Emerald"));
|
||||
self::register("enchanted_book", fn(IID $id) => new EnchantedBook($id, "Enchanted Book", [EnchantmentTags::ALL]));
|
||||
self::register("enchanted_golden_apple", fn(IID $id) => new GoldenAppleEnchanted($id, "Enchanted Golden Apple"));
|
||||
self::register("end_crystal", fn(IID $id) => new EndCrystal($id, "End Crystal"));
|
||||
self::register("ender_pearl", fn(IID $id) => new EnderPearl($id, "Ender Pearl"));
|
||||
self::register("experience_bottle", fn(IID $id) => new ExperienceBottle($id, "Bottle o' Enchanting"));
|
||||
self::register("feather", fn(IID $id) => new Item($id, "Feather"));
|
||||
self::register("fermented_spider_eye", fn(IID $id) => new Item($id, "Fermented Spider Eye"));
|
||||
self::register("fire_charge", fn(IID $id) => new FireCharge($id, "Fire Charge"));
|
||||
self::register("fishing_rod", fn(IID $id) => new FishingRod($id, "Fishing Rod", [EnchantmentTags::FISHING_ROD]));
|
||||
self::register("flint", fn(IID $id) => new Item($id, "Flint"));
|
||||
self::register("flint_and_steel", fn(IID $id) => new FlintSteel($id, "Flint and Steel", [EnchantmentTags::FLINT_AND_STEEL]));
|
||||
self::register("ghast_tear", fn(IID $id) => new Item($id, "Ghast Tear"));
|
||||
self::register("glass_bottle", fn(IID $id) => new GlassBottle($id, "Glass Bottle"));
|
||||
self::register("glistering_melon", fn(IID $id) => new Item($id, "Glistering Melon"));
|
||||
self::register("glow_berries", fn(IID $id) => new GlowBerries($id, "Glow Berries"));
|
||||
self::register("glow_ink_sac", fn(IID $id) => new Item($id, "Glow Ink Sac"));
|
||||
self::register("glowstone_dust", fn(IID $id) => new Item($id, "Glowstone Dust"));
|
||||
self::register("goat_horn", fn(IID $id) => new GoatHorn($id, "Goat Horn"));
|
||||
self::register("gold_ingot", fn(IID $id) => new Item($id, "Gold Ingot"));
|
||||
self::register("gold_nugget", fn(IID $id) => new Item($id, "Gold Nugget"));
|
||||
self::register("golden_apple", fn(IID $id) => new GoldenApple($id, "Golden Apple"));
|
||||
self::register("golden_carrot", fn(IID $id) => new GoldenCarrot($id, "Golden Carrot"));
|
||||
self::register("gunpowder", fn(IID $id) => new Item($id, "Gunpowder"));
|
||||
self::register("heart_of_the_sea", fn(IID $id) => new Item($id, "Heart of the Sea"));
|
||||
self::register("honey_bottle", fn(IID $id) => new HoneyBottle($id, "Honey Bottle"));
|
||||
self::register("honeycomb", fn(IID $id) => new Item($id, "Honeycomb"));
|
||||
self::register("ink_sac", fn(IID $id) => new Item($id, "Ink Sac"));
|
||||
self::register("iron_ingot", fn(IID $id) => new Item($id, "Iron Ingot"));
|
||||
self::register("iron_nugget", fn(IID $id) => new Item($id, "Iron Nugget"));
|
||||
self::register("jungle_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::JUNGLE_SIGN(), Blocks::JUNGLE_WALL_SIGN()));
|
||||
self::register("lapis_lazuli", fn(IID $id) => new Item($id, "Lapis Lazuli"));
|
||||
self::register("lava_bucket", fn(IID $id) => new LiquidBucket($id, "Lava Bucket", Blocks::LAVA()));
|
||||
self::register("leather", fn(IID $id) => new Item($id, "Leather"));
|
||||
self::register("magma_cream", fn(IID $id) => new Item($id, "Magma Cream"));
|
||||
self::register("mangrove_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::MANGROVE_SIGN(), Blocks::MANGROVE_WALL_SIGN()));
|
||||
self::register("medicine", fn(IID $id) => new Medicine($id, "Medicine"));
|
||||
self::register("melon", fn(IID $id) => new Melon($id, "Melon"));
|
||||
self::register("melon_seeds", fn(IID $id) => new MelonSeeds($id, "Melon Seeds"));
|
||||
self::register("milk_bucket", fn(IID $id) => new MilkBucket($id, "Milk Bucket"));
|
||||
self::register("minecart", fn(IID $id) => new Minecart($id, "Minecart"));
|
||||
self::register("mushroom_stew", fn(IID $id) => new MushroomStew($id, "Mushroom Stew"));
|
||||
self::register("name_tag", fn(IID $id) => new NameTag($id, "Name Tag"));
|
||||
self::register("nautilus_shell", fn(IID $id) => new Item($id, "Nautilus Shell"));
|
||||
self::register("nether_brick", fn(IID $id) => new Item($id, "Nether Brick"));
|
||||
self::register("nether_quartz", fn(IID $id) => new Item($id, "Nether Quartz"));
|
||||
self::register("nether_star", fn(IID $id) => new Item($id, "Nether Star"));
|
||||
self::register("netherite_ingot", fn(IID $id) => new class($id, "Netherite Ingot") extends Item{
|
||||
public function isFireProof() : bool{ return true; }
|
||||
});
|
||||
self::register("netherite_scrap", new class(new IID(Ids::NETHERITE_SCRAP), "Netherite Scrap") extends Item{
|
||||
self::register("netherite_scrap", fn(IID $id) => new class($id, "Netherite Scrap") extends Item{
|
||||
public function isFireProof() : bool{ return true; }
|
||||
});
|
||||
self::register("oak_sign", new ItemBlockWallOrFloor(new IID(Ids::OAK_SIGN), Blocks::OAK_SIGN(), Blocks::OAK_WALL_SIGN()));
|
||||
self::register("painting", new PaintingItem(new IID(Ids::PAINTING), "Painting"));
|
||||
self::register("paper", new Item(new IID(Ids::PAPER), "Paper"));
|
||||
self::register("phantom_membrane", new Item(new IID(Ids::PHANTOM_MEMBRANE), "Phantom Membrane"));
|
||||
self::register("pitcher_pod", new PitcherPod(new IID(Ids::PITCHER_POD), "Pitcher Pod"));
|
||||
self::register("poisonous_potato", new PoisonousPotato(new IID(Ids::POISONOUS_POTATO), "Poisonous Potato"));
|
||||
self::register("popped_chorus_fruit", new Item(new IID(Ids::POPPED_CHORUS_FRUIT), "Popped Chorus Fruit"));
|
||||
self::register("potato", new Potato(new IID(Ids::POTATO), "Potato"));
|
||||
self::register("potion", new Potion(new IID(Ids::POTION), "Potion"));
|
||||
self::register("prismarine_crystals", new Item(new IID(Ids::PRISMARINE_CRYSTALS), "Prismarine Crystals"));
|
||||
self::register("prismarine_shard", new Item(new IID(Ids::PRISMARINE_SHARD), "Prismarine Shard"));
|
||||
self::register("pufferfish", new Pufferfish(new IID(Ids::PUFFERFISH), "Pufferfish"));
|
||||
self::register("pumpkin_pie", new PumpkinPie(new IID(Ids::PUMPKIN_PIE), "Pumpkin Pie"));
|
||||
self::register("pumpkin_seeds", new PumpkinSeeds(new IID(Ids::PUMPKIN_SEEDS), "Pumpkin Seeds"));
|
||||
self::register("rabbit_foot", new Item(new IID(Ids::RABBIT_FOOT), "Rabbit's Foot"));
|
||||
self::register("rabbit_hide", new Item(new IID(Ids::RABBIT_HIDE), "Rabbit Hide"));
|
||||
self::register("rabbit_stew", new RabbitStew(new IID(Ids::RABBIT_STEW), "Rabbit Stew"));
|
||||
self::register("raw_beef", new RawBeef(new IID(Ids::RAW_BEEF), "Raw Beef"));
|
||||
self::register("raw_chicken", new RawChicken(new IID(Ids::RAW_CHICKEN), "Raw Chicken"));
|
||||
self::register("raw_copper", new Item(new IID(Ids::RAW_COPPER), "Raw Copper"));
|
||||
self::register("raw_fish", new RawFish(new IID(Ids::RAW_FISH), "Raw Fish"));
|
||||
self::register("raw_gold", new Item(new IID(Ids::RAW_GOLD), "Raw Gold"));
|
||||
self::register("raw_iron", new Item(new IID(Ids::RAW_IRON), "Raw Iron"));
|
||||
self::register("raw_mutton", new RawMutton(new IID(Ids::RAW_MUTTON), "Raw Mutton"));
|
||||
self::register("raw_porkchop", new RawPorkchop(new IID(Ids::RAW_PORKCHOP), "Raw Porkchop"));
|
||||
self::register("raw_rabbit", new RawRabbit(new IID(Ids::RAW_RABBIT), "Raw Rabbit"));
|
||||
self::register("raw_salmon", new RawSalmon(new IID(Ids::RAW_SALMON), "Raw Salmon"));
|
||||
self::register("record_11", new Record(new IID(Ids::RECORD_11), RecordType::DISK_11, "Record 11"));
|
||||
self::register("record_13", new Record(new IID(Ids::RECORD_13), RecordType::DISK_13, "Record 13"));
|
||||
self::register("record_5", new Record(new IID(Ids::RECORD_5), RecordType::DISK_5, "Record 5"));
|
||||
self::register("record_blocks", new Record(new IID(Ids::RECORD_BLOCKS), RecordType::DISK_BLOCKS, "Record Blocks"));
|
||||
self::register("record_cat", new Record(new IID(Ids::RECORD_CAT), RecordType::DISK_CAT, "Record Cat"));
|
||||
self::register("record_chirp", new Record(new IID(Ids::RECORD_CHIRP), RecordType::DISK_CHIRP, "Record Chirp"));
|
||||
self::register("record_far", new Record(new IID(Ids::RECORD_FAR), RecordType::DISK_FAR, "Record Far"));
|
||||
self::register("record_mall", new Record(new IID(Ids::RECORD_MALL), RecordType::DISK_MALL, "Record Mall"));
|
||||
self::register("record_mellohi", new Record(new IID(Ids::RECORD_MELLOHI), RecordType::DISK_MELLOHI, "Record Mellohi"));
|
||||
self::register("record_otherside", new Record(new IID(Ids::RECORD_OTHERSIDE), RecordType::DISK_OTHERSIDE, "Record Otherside"));
|
||||
self::register("record_pigstep", new Record(new IID(Ids::RECORD_PIGSTEP), RecordType::DISK_PIGSTEP, "Record Pigstep"));
|
||||
self::register("record_stal", new Record(new IID(Ids::RECORD_STAL), RecordType::DISK_STAL, "Record Stal"));
|
||||
self::register("record_strad", new Record(new IID(Ids::RECORD_STRAD), RecordType::DISK_STRAD, "Record Strad"));
|
||||
self::register("record_wait", new Record(new IID(Ids::RECORD_WAIT), RecordType::DISK_WAIT, "Record Wait"));
|
||||
self::register("record_ward", new Record(new IID(Ids::RECORD_WARD), RecordType::DISK_WARD, "Record Ward"));
|
||||
self::register("redstone_dust", new Redstone(new IID(Ids::REDSTONE_DUST), "Redstone"));
|
||||
self::register("rotten_flesh", new RottenFlesh(new IID(Ids::ROTTEN_FLESH), "Rotten Flesh"));
|
||||
self::register("scute", new Item(new IID(Ids::SCUTE), "Scute"));
|
||||
self::register("shears", new Shears(new IID(Ids::SHEARS), "Shears", [EnchantmentTags::SHEARS]));
|
||||
self::register("shulker_shell", new Item(new IID(Ids::SHULKER_SHELL), "Shulker Shell"));
|
||||
self::register("slimeball", new Item(new IID(Ids::SLIMEBALL), "Slimeball"));
|
||||
self::register("snowball", new Snowball(new IID(Ids::SNOWBALL), "Snowball"));
|
||||
self::register("spider_eye", new SpiderEye(new IID(Ids::SPIDER_EYE), "Spider Eye"));
|
||||
self::register("splash_potion", new SplashPotion(new IID(Ids::SPLASH_POTION), "Splash Potion"));
|
||||
self::register("spruce_sign", new ItemBlockWallOrFloor(new IID(Ids::SPRUCE_SIGN), Blocks::SPRUCE_SIGN(), Blocks::SPRUCE_WALL_SIGN()));
|
||||
self::register("spyglass", new Spyglass(new IID(Ids::SPYGLASS), "Spyglass"));
|
||||
self::register("steak", new Steak(new IID(Ids::STEAK), "Steak"));
|
||||
self::register("stick", new Stick(new IID(Ids::STICK), "Stick"));
|
||||
self::register("string", new StringItem(new IID(Ids::STRING), "String"));
|
||||
self::register("sugar", new Item(new IID(Ids::SUGAR), "Sugar"));
|
||||
self::register("suspicious_stew", new SuspiciousStew(new IID(Ids::SUSPICIOUS_STEW), "Suspicious Stew"));
|
||||
self::register("sweet_berries", new SweetBerries(new IID(Ids::SWEET_BERRIES), "Sweet Berries"));
|
||||
self::register("torchflower_seeds", new TorchflowerSeeds(new IID(Ids::TORCHFLOWER_SEEDS), "Torchflower Seeds"));
|
||||
self::register("totem", new Totem(new IID(Ids::TOTEM), "Totem of Undying"));
|
||||
self::register("warped_sign", new ItemBlockWallOrFloor(new IID(Ids::WARPED_SIGN), Blocks::WARPED_SIGN(), Blocks::WARPED_WALL_SIGN()));
|
||||
self::register("water_bucket", new LiquidBucket(new IID(Ids::WATER_BUCKET), "Water Bucket", Blocks::WATER()));
|
||||
self::register("wheat", new Item(new IID(Ids::WHEAT), "Wheat"));
|
||||
self::register("wheat_seeds", new WheatSeeds(new IID(Ids::WHEAT_SEEDS), "Wheat Seeds"));
|
||||
self::register("writable_book", new WritableBook(new IID(Ids::WRITABLE_BOOK), "Book & Quill"));
|
||||
self::register("written_book", new WrittenBook(new IID(Ids::WRITTEN_BOOK), "Written Book"));
|
||||
self::register("oak_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::OAK_SIGN(), Blocks::OAK_WALL_SIGN()));
|
||||
self::register("painting", fn(IID $id) => new PaintingItem($id, "Painting"));
|
||||
self::register("paper", fn(IID $id) => new Item($id, "Paper"));
|
||||
self::register("phantom_membrane", fn(IID $id) => new Item($id, "Phantom Membrane"));
|
||||
self::register("pitcher_pod", fn(IID $id) => new PitcherPod($id, "Pitcher Pod"));
|
||||
self::register("poisonous_potato", fn(IID $id) => new PoisonousPotato($id, "Poisonous Potato"));
|
||||
self::register("popped_chorus_fruit", fn(IID $id) => new Item($id, "Popped Chorus Fruit"));
|
||||
self::register("potato", fn(IID $id) => new Potato($id, "Potato"));
|
||||
self::register("potion", fn(IID $id) => new Potion($id, "Potion"));
|
||||
self::register("prismarine_crystals", fn(IID $id) => new Item($id, "Prismarine Crystals"));
|
||||
self::register("prismarine_shard", fn(IID $id) => new Item($id, "Prismarine Shard"));
|
||||
self::register("pufferfish", fn(IID $id) => new Pufferfish($id, "Pufferfish"));
|
||||
self::register("pumpkin_pie", fn(IID $id) => new PumpkinPie($id, "Pumpkin Pie"));
|
||||
self::register("pumpkin_seeds", fn(IID $id) => new PumpkinSeeds($id, "Pumpkin Seeds"));
|
||||
self::register("rabbit_foot", fn(IID $id) => new Item($id, "Rabbit's Foot"));
|
||||
self::register("rabbit_hide", fn(IID $id) => new Item($id, "Rabbit Hide"));
|
||||
self::register("rabbit_stew", fn(IID $id) => new RabbitStew($id, "Rabbit Stew"));
|
||||
self::register("raw_beef", fn(IID $id) => new RawBeef($id, "Raw Beef"));
|
||||
self::register("raw_chicken", fn(IID $id) => new RawChicken($id, "Raw Chicken"));
|
||||
self::register("raw_copper", fn(IID $id) => new Item($id, "Raw Copper"));
|
||||
self::register("raw_fish", fn(IID $id) => new RawFish($id, "Raw Fish"));
|
||||
self::register("raw_gold", fn(IID $id) => new Item($id, "Raw Gold"));
|
||||
self::register("raw_iron", fn(IID $id) => new Item($id, "Raw Iron"));
|
||||
self::register("raw_mutton", fn(IID $id) => new RawMutton($id, "Raw Mutton"));
|
||||
self::register("raw_porkchop", fn(IID $id) => new RawPorkchop($id, "Raw Porkchop"));
|
||||
self::register("raw_rabbit", fn(IID $id) => new RawRabbit($id, "Raw Rabbit"));
|
||||
self::register("raw_salmon", fn(IID $id) => new RawSalmon($id, "Raw Salmon"));
|
||||
self::register("record_11", fn(IID $id) => new Record($id, RecordType::DISK_11, "Record 11"));
|
||||
self::register("record_13", fn(IID $id) => new Record($id, RecordType::DISK_13, "Record 13"));
|
||||
self::register("record_5", fn(IID $id) => new Record($id, RecordType::DISK_5, "Record 5"));
|
||||
self::register("record_blocks", fn(IID $id) => new Record($id, RecordType::DISK_BLOCKS, "Record Blocks"));
|
||||
self::register("record_cat", fn(IID $id) => new Record($id, RecordType::DISK_CAT, "Record Cat"));
|
||||
self::register("record_chirp", fn(IID $id) => new Record($id, RecordType::DISK_CHIRP, "Record Chirp"));
|
||||
self::register("record_far", fn(IID $id) => new Record($id, RecordType::DISK_FAR, "Record Far"));
|
||||
self::register("record_mall", fn(IID $id) => new Record($id, RecordType::DISK_MALL, "Record Mall"));
|
||||
self::register("record_mellohi", fn(IID $id) => new Record($id, RecordType::DISK_MELLOHI, "Record Mellohi"));
|
||||
self::register("record_otherside", fn(IID $id) => new Record($id, RecordType::DISK_OTHERSIDE, "Record Otherside"));
|
||||
self::register("record_pigstep", fn(IID $id) => new Record($id, RecordType::DISK_PIGSTEP, "Record Pigstep"));
|
||||
self::register("record_stal", fn(IID $id) => new Record($id, RecordType::DISK_STAL, "Record Stal"));
|
||||
self::register("record_strad", fn(IID $id) => new Record($id, RecordType::DISK_STRAD, "Record Strad"));
|
||||
self::register("record_wait", fn(IID $id) => new Record($id, RecordType::DISK_WAIT, "Record Wait"));
|
||||
self::register("record_ward", fn(IID $id) => new Record($id, RecordType::DISK_WARD, "Record Ward"));
|
||||
self::register("redstone_dust", fn(IID $id) => new Redstone($id, "Redstone"));
|
||||
self::register("rotten_flesh", fn(IID $id) => new RottenFlesh($id, "Rotten Flesh"));
|
||||
self::register("scute", fn(IID $id) => new Item($id, "Scute"));
|
||||
self::register("shears", fn(IID $id) => new Shears($id, "Shears", [EnchantmentTags::SHEARS]));
|
||||
self::register("shulker_shell", fn(IID $id) => new Item($id, "Shulker Shell"));
|
||||
self::register("slimeball", fn(IID $id) => new Item($id, "Slimeball"));
|
||||
self::register("snowball", fn(IID $id) => new Snowball($id, "Snowball"));
|
||||
self::register("spider_eye", fn(IID $id) => new SpiderEye($id, "Spider Eye"));
|
||||
self::register("splash_potion", fn(IID $id) => new SplashPotion($id, "Splash Potion"));
|
||||
self::register("spruce_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::SPRUCE_SIGN(), Blocks::SPRUCE_WALL_SIGN()));
|
||||
self::register("spyglass", fn(IID $id) => new Spyglass($id, "Spyglass"));
|
||||
self::register("steak", fn(IID $id) => new Steak($id, "Steak"));
|
||||
self::register("stick", fn(IID $id) => new Stick($id, "Stick"));
|
||||
self::register("string", fn(IID $id) => new StringItem($id, "String"));
|
||||
self::register("sugar", fn(IID $id) => new Item($id, "Sugar"));
|
||||
self::register("suspicious_stew", fn(IID $id) => new SuspiciousStew($id, "Suspicious Stew"));
|
||||
self::register("sweet_berries", fn(IID $id) => new SweetBerries($id, "Sweet Berries"));
|
||||
self::register("torchflower_seeds", fn(IID $id) => new TorchflowerSeeds($id, "Torchflower Seeds"));
|
||||
self::register("totem", fn(IID $id) => new Totem($id, "Totem of Undying"));
|
||||
self::register("warped_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::WARPED_SIGN(), Blocks::WARPED_WALL_SIGN()));
|
||||
self::register("water_bucket", fn(IID $id) => new LiquidBucket($id, "Water Bucket", Blocks::WATER()));
|
||||
self::register("wheat", fn(IID $id) => new Item($id, "Wheat"));
|
||||
self::register("wheat_seeds", fn(IID $id) => new WheatSeeds($id, "Wheat Seeds"));
|
||||
self::register("writable_book", fn(IID $id) => new WritableBook($id, "Book & Quill"));
|
||||
self::register("written_book", fn(IID $id) => new WrittenBook($id, "Written Book"));
|
||||
|
||||
foreach(BoatType::cases() as $type){
|
||||
//boat type is static, because different types of wood may have different properties
|
||||
self::register(strtolower($type->name) . "_boat", new Boat(new IID(match($type){
|
||||
BoatType::OAK => Ids::OAK_BOAT,
|
||||
BoatType::SPRUCE => Ids::SPRUCE_BOAT,
|
||||
BoatType::BIRCH => Ids::BIRCH_BOAT,
|
||||
BoatType::JUNGLE => Ids::JUNGLE_BOAT,
|
||||
BoatType::ACACIA => Ids::ACACIA_BOAT,
|
||||
BoatType::DARK_OAK => Ids::DARK_OAK_BOAT,
|
||||
BoatType::MANGROVE => Ids::MANGROVE_BOAT,
|
||||
}), $type->getDisplayName() . " Boat", $type));
|
||||
self::register(strtolower($type->name) . "_boat", fn(IID $id) => new Boat($id, $type->getDisplayName() . " Boat", $type));
|
||||
}
|
||||
}
|
||||
|
||||
private static function registerSpawnEggs() : void{
|
||||
self::register("zombie_spawn_egg", new class(new IID(Ids::ZOMBIE_SPAWN_EGG), "Zombie Spawn Egg") extends SpawnEgg{
|
||||
self::register("zombie_spawn_egg", fn(IID $id) => new class($id, "Zombie Spawn Egg") extends SpawnEgg{
|
||||
protected function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
|
||||
return new Zombie(Location::fromObject($pos, $world, $yaw, $pitch));
|
||||
}
|
||||
});
|
||||
self::register("squid_spawn_egg", new class(new IID(Ids::SQUID_SPAWN_EGG), "Squid Spawn Egg") extends SpawnEgg{
|
||||
self::register("squid_spawn_egg", fn(IID $id) => new class($id, "Squid Spawn Egg") extends SpawnEgg{
|
||||
protected function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
|
||||
return new Squid(Location::fromObject($pos, $world, $yaw, $pitch));
|
||||
}
|
||||
});
|
||||
self::register("villager_spawn_egg", new class(new IID(Ids::VILLAGER_SPAWN_EGG), "Villager Spawn Egg") extends SpawnEgg{
|
||||
self::register("villager_spawn_egg", fn(IID $id) => new class($id, "Villager Spawn Egg") extends SpawnEgg{
|
||||
protected function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
|
||||
return new Villager(Location::fromObject($pos, $world, $yaw, $pitch));
|
||||
}
|
||||
@ -603,87 +623,87 @@ final class VanillaItems{
|
||||
}
|
||||
|
||||
private static function registerTierToolItems() : void{
|
||||
self::register("diamond_axe", new Axe(new IID(Ids::DIAMOND_AXE), "Diamond Axe", ToolTier::DIAMOND, [EnchantmentTags::AXE]));
|
||||
self::register("golden_axe", new Axe(new IID(Ids::GOLDEN_AXE), "Golden Axe", ToolTier::GOLD, [EnchantmentTags::AXE]));
|
||||
self::register("iron_axe", new Axe(new IID(Ids::IRON_AXE), "Iron Axe", ToolTier::IRON, [EnchantmentTags::AXE]));
|
||||
self::register("netherite_axe", new Axe(new IID(Ids::NETHERITE_AXE), "Netherite Axe", ToolTier::NETHERITE, [EnchantmentTags::AXE]));
|
||||
self::register("stone_axe", new Axe(new IID(Ids::STONE_AXE), "Stone Axe", ToolTier::STONE, [EnchantmentTags::AXE]));
|
||||
self::register("wooden_axe", new Axe(new IID(Ids::WOODEN_AXE), "Wooden Axe", ToolTier::WOOD, [EnchantmentTags::AXE]));
|
||||
self::register("diamond_hoe", new Hoe(new IID(Ids::DIAMOND_HOE), "Diamond Hoe", ToolTier::DIAMOND, [EnchantmentTags::HOE]));
|
||||
self::register("golden_hoe", new Hoe(new IID(Ids::GOLDEN_HOE), "Golden Hoe", ToolTier::GOLD, [EnchantmentTags::HOE]));
|
||||
self::register("iron_hoe", new Hoe(new IID(Ids::IRON_HOE), "Iron Hoe", ToolTier::IRON, [EnchantmentTags::HOE]));
|
||||
self::register("netherite_hoe", new Hoe(new IID(Ids::NETHERITE_HOE), "Netherite Hoe", ToolTier::NETHERITE, [EnchantmentTags::HOE]));
|
||||
self::register("stone_hoe", new Hoe(new IID(Ids::STONE_HOE), "Stone Hoe", ToolTier::STONE, [EnchantmentTags::HOE]));
|
||||
self::register("wooden_hoe", new Hoe(new IID(Ids::WOODEN_HOE), "Wooden Hoe", ToolTier::WOOD, [EnchantmentTags::HOE]));
|
||||
self::register("diamond_pickaxe", new Pickaxe(new IID(Ids::DIAMOND_PICKAXE), "Diamond Pickaxe", ToolTier::DIAMOND, [EnchantmentTags::PICKAXE]));
|
||||
self::register("golden_pickaxe", new Pickaxe(new IID(Ids::GOLDEN_PICKAXE), "Golden Pickaxe", ToolTier::GOLD, [EnchantmentTags::PICKAXE]));
|
||||
self::register("iron_pickaxe", new Pickaxe(new IID(Ids::IRON_PICKAXE), "Iron Pickaxe", ToolTier::IRON, [EnchantmentTags::PICKAXE]));
|
||||
self::register("netherite_pickaxe", new Pickaxe(new IID(Ids::NETHERITE_PICKAXE), "Netherite Pickaxe", ToolTier::NETHERITE, [EnchantmentTags::PICKAXE]));
|
||||
self::register("stone_pickaxe", new Pickaxe(new IID(Ids::STONE_PICKAXE), "Stone Pickaxe", ToolTier::STONE, [EnchantmentTags::PICKAXE]));
|
||||
self::register("wooden_pickaxe", new Pickaxe(new IID(Ids::WOODEN_PICKAXE), "Wooden Pickaxe", ToolTier::WOOD, [EnchantmentTags::PICKAXE]));
|
||||
self::register("diamond_shovel", new Shovel(new IID(Ids::DIAMOND_SHOVEL), "Diamond Shovel", ToolTier::DIAMOND, [EnchantmentTags::SHOVEL]));
|
||||
self::register("golden_shovel", new Shovel(new IID(Ids::GOLDEN_SHOVEL), "Golden Shovel", ToolTier::GOLD, [EnchantmentTags::SHOVEL]));
|
||||
self::register("iron_shovel", new Shovel(new IID(Ids::IRON_SHOVEL), "Iron Shovel", ToolTier::IRON, [EnchantmentTags::SHOVEL]));
|
||||
self::register("netherite_shovel", new Shovel(new IID(Ids::NETHERITE_SHOVEL), "Netherite Shovel", ToolTier::NETHERITE, [EnchantmentTags::SHOVEL]));
|
||||
self::register("stone_shovel", new Shovel(new IID(Ids::STONE_SHOVEL), "Stone Shovel", ToolTier::STONE, [EnchantmentTags::SHOVEL]));
|
||||
self::register("wooden_shovel", new Shovel(new IID(Ids::WOODEN_SHOVEL), "Wooden Shovel", ToolTier::WOOD, [EnchantmentTags::SHOVEL]));
|
||||
self::register("diamond_sword", new Sword(new IID(Ids::DIAMOND_SWORD), "Diamond Sword", ToolTier::DIAMOND, [EnchantmentTags::SWORD]));
|
||||
self::register("golden_sword", new Sword(new IID(Ids::GOLDEN_SWORD), "Golden Sword", ToolTier::GOLD, [EnchantmentTags::SWORD]));
|
||||
self::register("iron_sword", new Sword(new IID(Ids::IRON_SWORD), "Iron Sword", ToolTier::IRON, [EnchantmentTags::SWORD]));
|
||||
self::register("netherite_sword", new Sword(new IID(Ids::NETHERITE_SWORD), "Netherite Sword", ToolTier::NETHERITE, [EnchantmentTags::SWORD]));
|
||||
self::register("stone_sword", new Sword(new IID(Ids::STONE_SWORD), "Stone Sword", ToolTier::STONE, [EnchantmentTags::SWORD]));
|
||||
self::register("wooden_sword", new Sword(new IID(Ids::WOODEN_SWORD), "Wooden Sword", ToolTier::WOOD, [EnchantmentTags::SWORD]));
|
||||
self::register("diamond_axe", fn(IID $id) => new Axe($id, "Diamond Axe", ToolTier::DIAMOND, [EnchantmentTags::AXE]));
|
||||
self::register("golden_axe", fn(IID $id) => new Axe($id, "Golden Axe", ToolTier::GOLD, [EnchantmentTags::AXE]));
|
||||
self::register("iron_axe", fn(IID $id) => new Axe($id, "Iron Axe", ToolTier::IRON, [EnchantmentTags::AXE]));
|
||||
self::register("netherite_axe", fn(IID $id) => new Axe($id, "Netherite Axe", ToolTier::NETHERITE, [EnchantmentTags::AXE]));
|
||||
self::register("stone_axe", fn(IID $id) => new Axe($id, "Stone Axe", ToolTier::STONE, [EnchantmentTags::AXE]));
|
||||
self::register("wooden_axe", fn(IID $id) => new Axe($id, "Wooden Axe", ToolTier::WOOD, [EnchantmentTags::AXE]));
|
||||
self::register("diamond_hoe", fn(IID $id) => new Hoe($id, "Diamond Hoe", ToolTier::DIAMOND, [EnchantmentTags::HOE]));
|
||||
self::register("golden_hoe", fn(IID $id) => new Hoe($id, "Golden Hoe", ToolTier::GOLD, [EnchantmentTags::HOE]));
|
||||
self::register("iron_hoe", fn(IID $id) => new Hoe($id, "Iron Hoe", ToolTier::IRON, [EnchantmentTags::HOE]));
|
||||
self::register("netherite_hoe", fn(IID $id) => new Hoe($id, "Netherite Hoe", ToolTier::NETHERITE, [EnchantmentTags::HOE]));
|
||||
self::register("stone_hoe", fn(IID $id) => new Hoe($id, "Stone Hoe", ToolTier::STONE, [EnchantmentTags::HOE]));
|
||||
self::register("wooden_hoe", fn(IID $id) => new Hoe($id, "Wooden Hoe", ToolTier::WOOD, [EnchantmentTags::HOE]));
|
||||
self::register("diamond_pickaxe", fn(IID $id) => new Pickaxe($id, "Diamond Pickaxe", ToolTier::DIAMOND, [EnchantmentTags::PICKAXE]));
|
||||
self::register("golden_pickaxe", fn(IID $id) => new Pickaxe($id, "Golden Pickaxe", ToolTier::GOLD, [EnchantmentTags::PICKAXE]));
|
||||
self::register("iron_pickaxe", fn(IID $id) => new Pickaxe($id, "Iron Pickaxe", ToolTier::IRON, [EnchantmentTags::PICKAXE]));
|
||||
self::register("netherite_pickaxe", fn(IID $id) => new Pickaxe($id, "Netherite Pickaxe", ToolTier::NETHERITE, [EnchantmentTags::PICKAXE]));
|
||||
self::register("stone_pickaxe", fn(IID $id) => new Pickaxe($id, "Stone Pickaxe", ToolTier::STONE, [EnchantmentTags::PICKAXE]));
|
||||
self::register("wooden_pickaxe", fn(IID $id) => new Pickaxe($id, "Wooden Pickaxe", ToolTier::WOOD, [EnchantmentTags::PICKAXE]));
|
||||
self::register("diamond_shovel", fn(IID $id) => new Shovel($id, "Diamond Shovel", ToolTier::DIAMOND, [EnchantmentTags::SHOVEL]));
|
||||
self::register("golden_shovel", fn(IID $id) => new Shovel($id, "Golden Shovel", ToolTier::GOLD, [EnchantmentTags::SHOVEL]));
|
||||
self::register("iron_shovel", fn(IID $id) => new Shovel($id, "Iron Shovel", ToolTier::IRON, [EnchantmentTags::SHOVEL]));
|
||||
self::register("netherite_shovel", fn(IID $id) => new Shovel($id, "Netherite Shovel", ToolTier::NETHERITE, [EnchantmentTags::SHOVEL]));
|
||||
self::register("stone_shovel", fn(IID $id) => new Shovel($id, "Stone Shovel", ToolTier::STONE, [EnchantmentTags::SHOVEL]));
|
||||
self::register("wooden_shovel", fn(IID $id) => new Shovel($id, "Wooden Shovel", ToolTier::WOOD, [EnchantmentTags::SHOVEL]));
|
||||
self::register("diamond_sword", fn(IID $id) => new Sword($id, "Diamond Sword", ToolTier::DIAMOND, [EnchantmentTags::SWORD]));
|
||||
self::register("golden_sword", fn(IID $id) => new Sword($id, "Golden Sword", ToolTier::GOLD, [EnchantmentTags::SWORD]));
|
||||
self::register("iron_sword", fn(IID $id) => new Sword($id, "Iron Sword", ToolTier::IRON, [EnchantmentTags::SWORD]));
|
||||
self::register("netherite_sword", fn(IID $id) => new Sword($id, "Netherite Sword", ToolTier::NETHERITE, [EnchantmentTags::SWORD]));
|
||||
self::register("stone_sword", fn(IID $id) => new Sword($id, "Stone Sword", ToolTier::STONE, [EnchantmentTags::SWORD]));
|
||||
self::register("wooden_sword", fn(IID $id) => new Sword($id, "Wooden Sword", ToolTier::WOOD, [EnchantmentTags::SWORD]));
|
||||
}
|
||||
|
||||
private static function registerArmorItems() : void{
|
||||
self::register("chainmail_boots", new Armor(new IID(Ids::CHAINMAIL_BOOTS), "Chainmail Boots", new ArmorTypeInfo(1, 196, ArmorInventory::SLOT_FEET, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::BOOTS]));
|
||||
self::register("diamond_boots", new Armor(new IID(Ids::DIAMOND_BOOTS), "Diamond Boots", new ArmorTypeInfo(3, 430, ArmorInventory::SLOT_FEET, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::BOOTS]));
|
||||
self::register("golden_boots", new Armor(new IID(Ids::GOLDEN_BOOTS), "Golden Boots", new ArmorTypeInfo(1, 92, ArmorInventory::SLOT_FEET, material: ArmorMaterials::GOLD()), [EnchantmentTags::BOOTS]));
|
||||
self::register("iron_boots", new Armor(new IID(Ids::IRON_BOOTS), "Iron Boots", new ArmorTypeInfo(2, 196, ArmorInventory::SLOT_FEET, material: ArmorMaterials::IRON()), [EnchantmentTags::BOOTS]));
|
||||
self::register("leather_boots", new Armor(new IID(Ids::LEATHER_BOOTS), "Leather Boots", new ArmorTypeInfo(1, 66, ArmorInventory::SLOT_FEET, material: ArmorMaterials::LEATHER()), [EnchantmentTags::BOOTS]));
|
||||
self::register("netherite_boots", new Armor(new IID(Ids::NETHERITE_BOOTS), "Netherite Boots", new ArmorTypeInfo(3, 482, ArmorInventory::SLOT_FEET, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::BOOTS]));
|
||||
self::register("chainmail_boots", fn(IID $id) => new Armor($id, "Chainmail Boots", new ArmorTypeInfo(1, 196, ArmorInventory::SLOT_FEET, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::BOOTS]));
|
||||
self::register("diamond_boots", fn(IID $id) => new Armor($id, "Diamond Boots", new ArmorTypeInfo(3, 430, ArmorInventory::SLOT_FEET, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::BOOTS]));
|
||||
self::register("golden_boots", fn(IID $id) => new Armor($id, "Golden Boots", new ArmorTypeInfo(1, 92, ArmorInventory::SLOT_FEET, material: ArmorMaterials::GOLD()), [EnchantmentTags::BOOTS]));
|
||||
self::register("iron_boots", fn(IID $id) => new Armor($id, "Iron Boots", new ArmorTypeInfo(2, 196, ArmorInventory::SLOT_FEET, material: ArmorMaterials::IRON()), [EnchantmentTags::BOOTS]));
|
||||
self::register("leather_boots", fn(IID $id) => new Armor($id, "Leather Boots", new ArmorTypeInfo(1, 66, ArmorInventory::SLOT_FEET, material: ArmorMaterials::LEATHER()), [EnchantmentTags::BOOTS]));
|
||||
self::register("netherite_boots", fn(IID $id) => new Armor($id, "Netherite Boots", new ArmorTypeInfo(3, 482, ArmorInventory::SLOT_FEET, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::BOOTS]));
|
||||
|
||||
self::register("chainmail_chestplate", new Armor(new IID(Ids::CHAINMAIL_CHESTPLATE), "Chainmail Chestplate", new ArmorTypeInfo(5, 241, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("diamond_chestplate", new Armor(new IID(Ids::DIAMOND_CHESTPLATE), "Diamond Chestplate", new ArmorTypeInfo(8, 529, ArmorInventory::SLOT_CHEST, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("golden_chestplate", new Armor(new IID(Ids::GOLDEN_CHESTPLATE), "Golden Chestplate", new ArmorTypeInfo(5, 113, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::GOLD()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("iron_chestplate", new Armor(new IID(Ids::IRON_CHESTPLATE), "Iron Chestplate", new ArmorTypeInfo(6, 241, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::IRON()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("leather_tunic", new Armor(new IID(Ids::LEATHER_TUNIC), "Leather Tunic", new ArmorTypeInfo(3, 81, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::LEATHER()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("netherite_chestplate", new Armor(new IID(Ids::NETHERITE_CHESTPLATE), "Netherite Chestplate", new ArmorTypeInfo(8, 593, ArmorInventory::SLOT_CHEST, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("chainmail_chestplate", fn(IID $id) => new Armor($id, "Chainmail Chestplate", new ArmorTypeInfo(5, 241, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("diamond_chestplate", fn(IID $id) => new Armor($id, "Diamond Chestplate", new ArmorTypeInfo(8, 529, ArmorInventory::SLOT_CHEST, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("golden_chestplate", fn(IID $id) => new Armor($id, "Golden Chestplate", new ArmorTypeInfo(5, 113, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::GOLD()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("iron_chestplate", fn(IID $id) => new Armor($id, "Iron Chestplate", new ArmorTypeInfo(6, 241, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::IRON()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("leather_tunic", fn(IID $id) => new Armor($id, "Leather Tunic", new ArmorTypeInfo(3, 81, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::LEATHER()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("netherite_chestplate", fn(IID $id) => new Armor($id, "Netherite Chestplate", new ArmorTypeInfo(8, 593, ArmorInventory::SLOT_CHEST, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::CHESTPLATE]));
|
||||
|
||||
self::register("chainmail_helmet", new Armor(new IID(Ids::CHAINMAIL_HELMET), "Chainmail Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::HELMET]));
|
||||
self::register("diamond_helmet", new Armor(new IID(Ids::DIAMOND_HELMET), "Diamond Helmet", new ArmorTypeInfo(3, 364, ArmorInventory::SLOT_HEAD, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::HELMET]));
|
||||
self::register("golden_helmet", new Armor(new IID(Ids::GOLDEN_HELMET), "Golden Helmet", new ArmorTypeInfo(2, 78, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::GOLD()), [EnchantmentTags::HELMET]));
|
||||
self::register("iron_helmet", new Armor(new IID(Ids::IRON_HELMET), "Iron Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::IRON()), [EnchantmentTags::HELMET]));
|
||||
self::register("leather_cap", new Armor(new IID(Ids::LEATHER_CAP), "Leather Cap", new ArmorTypeInfo(1, 56, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::LEATHER()), [EnchantmentTags::HELMET]));
|
||||
self::register("netherite_helmet", new Armor(new IID(Ids::NETHERITE_HELMET), "Netherite Helmet", new ArmorTypeInfo(3, 408, ArmorInventory::SLOT_HEAD, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::HELMET]));
|
||||
self::register("turtle_helmet", new TurtleHelmet(new IID(Ids::TURTLE_HELMET), "Turtle Shell", new ArmorTypeInfo(2, 276, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::TURTLE()), [EnchantmentTags::HELMET]));
|
||||
self::register("chainmail_helmet", fn(IID $id) => new Armor($id, "Chainmail Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::HELMET]));
|
||||
self::register("diamond_helmet", fn(IID $id) => new Armor($id, "Diamond Helmet", new ArmorTypeInfo(3, 364, ArmorInventory::SLOT_HEAD, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::HELMET]));
|
||||
self::register("golden_helmet", fn(IID $id) => new Armor($id, "Golden Helmet", new ArmorTypeInfo(2, 78, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::GOLD()), [EnchantmentTags::HELMET]));
|
||||
self::register("iron_helmet", fn(IID $id) => new Armor($id, "Iron Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::IRON()), [EnchantmentTags::HELMET]));
|
||||
self::register("leather_cap", fn(IID $id) => new Armor($id, "Leather Cap", new ArmorTypeInfo(1, 56, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::LEATHER()), [EnchantmentTags::HELMET]));
|
||||
self::register("netherite_helmet", fn(IID $id) => new Armor($id, "Netherite Helmet", new ArmorTypeInfo(3, 408, ArmorInventory::SLOT_HEAD, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::HELMET]));
|
||||
self::register("turtle_helmet", fn(IID $id) => new TurtleHelmet($id, "Turtle Shell", new ArmorTypeInfo(2, 276, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::TURTLE()), [EnchantmentTags::HELMET]));
|
||||
|
||||
self::register("chainmail_leggings", new Armor(new IID(Ids::CHAINMAIL_LEGGINGS), "Chainmail Leggings", new ArmorTypeInfo(4, 226, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("diamond_leggings", new Armor(new IID(Ids::DIAMOND_LEGGINGS), "Diamond Leggings", new ArmorTypeInfo(6, 496, ArmorInventory::SLOT_LEGS, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("golden_leggings", new Armor(new IID(Ids::GOLDEN_LEGGINGS), "Golden Leggings", new ArmorTypeInfo(3, 106, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::GOLD()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("iron_leggings", new Armor(new IID(Ids::IRON_LEGGINGS), "Iron Leggings", new ArmorTypeInfo(5, 226, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::IRON()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("leather_pants", new Armor(new IID(Ids::LEATHER_PANTS), "Leather Pants", new ArmorTypeInfo(2, 76, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::LEATHER()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("netherite_leggings", new Armor(new IID(Ids::NETHERITE_LEGGINGS), "Netherite Leggings", new ArmorTypeInfo(6, 556, ArmorInventory::SLOT_LEGS, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("chainmail_leggings", fn(IID $id) => new Armor($id, "Chainmail Leggings", new ArmorTypeInfo(4, 226, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("diamond_leggings", fn(IID $id) => new Armor($id, "Diamond Leggings", new ArmorTypeInfo(6, 496, ArmorInventory::SLOT_LEGS, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("golden_leggings", fn(IID $id) => new Armor($id, "Golden Leggings", new ArmorTypeInfo(3, 106, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::GOLD()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("iron_leggings", fn(IID $id) => new Armor($id, "Iron Leggings", new ArmorTypeInfo(5, 226, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::IRON()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("leather_pants", fn(IID $id) => new Armor($id, "Leather Pants", new ArmorTypeInfo(2, 76, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::LEATHER()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("netherite_leggings", fn(IID $id) => new Armor($id, "Netherite Leggings", new ArmorTypeInfo(6, 556, ArmorInventory::SLOT_LEGS, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::LEGGINGS]));
|
||||
}
|
||||
|
||||
private static function registerSmithingTemplates() : void{
|
||||
self::register("netherite_upgrade_smithing_template", new Item(new IID(Ids::NETHERITE_UPGRADE_SMITHING_TEMPLATE), "Netherite Upgrade Smithing Template"));
|
||||
self::register("coast_armor_trim_smithing_template", new Item(new IID(Ids::COAST_ARMOR_TRIM_SMITHING_TEMPLATE), "Coast Armor Trim Smithing Template"));
|
||||
self::register("dune_armor_trim_smithing_template", new Item(new IID(Ids::DUNE_ARMOR_TRIM_SMITHING_TEMPLATE), "Dune Armor Trim Smithing Template"));
|
||||
self::register("eye_armor_trim_smithing_template", new Item(new IID(Ids::EYE_ARMOR_TRIM_SMITHING_TEMPLATE), "Eye Armor Trim Smithing Template"));
|
||||
self::register("host_armor_trim_smithing_template", new Item(new IID(Ids::HOST_ARMOR_TRIM_SMITHING_TEMPLATE), "Host Armor Trim Smithing Template"));
|
||||
self::register("raiser_armor_trim_smithing_template", new Item(new IID(Ids::RAISER_ARMOR_TRIM_SMITHING_TEMPLATE), "Raiser Armor Trim Smithing Template"));
|
||||
self::register("rib_armor_trim_smithing_template", new Item(new IID(Ids::RIB_ARMOR_TRIM_SMITHING_TEMPLATE), "Rib Armor Trim Smithing Template"));
|
||||
self::register("sentry_armor_trim_smithing_template", new Item(new IID(Ids::SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE), "Sentry Armor Trim Smithing Template"));
|
||||
self::register("shaper_armor_trim_smithing_template", new Item(new IID(Ids::SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE), "Shaper Armor Trim Smithing Template"));
|
||||
self::register("silence_armor_trim_smithing_template", new Item(new IID(Ids::SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE), "Silence Armor Trim Smithing Template"));
|
||||
self::register("snout_armor_trim_smithing_template", new Item(new IID(Ids::SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE), "Snout Armor Trim Smithing Template"));
|
||||
self::register("spire_armor_trim_smithing_template", new Item(new IID(Ids::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE), "Spire Armor Trim Smithing Template"));
|
||||
self::register("tide_armor_trim_smithing_template", new Item(new IID(Ids::TIDE_ARMOR_TRIM_SMITHING_TEMPLATE), "Tide Armor Trim Smithing Template"));
|
||||
self::register("vex_armor_trim_smithing_template", new Item(new IID(Ids::VEX_ARMOR_TRIM_SMITHING_TEMPLATE), "Vex Armor Trim Smithing Template"));
|
||||
self::register("ward_armor_trim_smithing_template", new Item(new IID(Ids::WARD_ARMOR_TRIM_SMITHING_TEMPLATE), "Ward Armor Trim Smithing Template"));
|
||||
self::register("wayfinder_armor_trim_smithing_template", new Item(new IID(Ids::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE), "Wayfinder Armor Trim Smithing Template"));
|
||||
self::register("wild_armor_trim_smithing_template", new Item(new IID(Ids::WILD_ARMOR_TRIM_SMITHING_TEMPLATE), "Wild Armor Trim Smithing Template"));
|
||||
self::register("netherite_upgrade_smithing_template", fn(IID $id) => new Item($id, "Netherite Upgrade Smithing Template"));
|
||||
self::register("coast_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Coast Armor Trim Smithing Template"));
|
||||
self::register("dune_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Dune Armor Trim Smithing Template"));
|
||||
self::register("eye_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Eye Armor Trim Smithing Template"));
|
||||
self::register("host_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Host Armor Trim Smithing Template"));
|
||||
self::register("raiser_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Raiser Armor Trim Smithing Template"));
|
||||
self::register("rib_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Rib Armor Trim Smithing Template"));
|
||||
self::register("sentry_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Sentry Armor Trim Smithing Template"));
|
||||
self::register("shaper_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Shaper Armor Trim Smithing Template"));
|
||||
self::register("silence_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Silence Armor Trim Smithing Template"));
|
||||
self::register("snout_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Snout Armor Trim Smithing Template"));
|
||||
self::register("spire_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Spire Armor Trim Smithing Template"));
|
||||
self::register("tide_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Tide Armor Trim Smithing Template"));
|
||||
self::register("vex_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Vex Armor Trim Smithing Template"));
|
||||
self::register("ward_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Ward Armor Trim Smithing Template"));
|
||||
self::register("wayfinder_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Wayfinder Armor Trim Smithing Template"));
|
||||
self::register("wild_armor_trim_smithing_template", fn(IID $id) => new Item($id, "Wild Armor Trim Smithing Template"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -603,6 +603,31 @@ final class KnownTranslationFactory{
|
||||
return new Translatable(KnownTranslationKeys::COMMANDS_WHITELIST_USAGE, []);
|
||||
}
|
||||
|
||||
public static function commands_xp_failure_widthdrawXp() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::COMMANDS_XP_FAILURE_WIDTHDRAWXP, []);
|
||||
}
|
||||
|
||||
public static function commands_xp_success(Translatable|string $param0, Translatable|string $param1) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::COMMANDS_XP_SUCCESS, [
|
||||
0 => $param0,
|
||||
1 => $param1,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function commands_xp_success_levels(Translatable|string $param0, Translatable|string $param1) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::COMMANDS_XP_SUCCESS_LEVELS, [
|
||||
0 => $param0,
|
||||
1 => $param1,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function commands_xp_success_negative_levels(Translatable|string $param0, Translatable|string $param1) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::COMMANDS_XP_SUCCESS_NEGATIVE_LEVELS, [
|
||||
0 => $param0,
|
||||
1 => $param1,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function death_attack_anvil(Translatable|string $param0) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::DEATH_ATTACK_ANVIL, [
|
||||
0 => $param0,
|
||||
@ -667,6 +692,12 @@ final class KnownTranslationFactory{
|
||||
]);
|
||||
}
|
||||
|
||||
public static function death_attack_flyIntoWall(Translatable|string $param0) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::DEATH_ATTACK_FLYINTOWALL, [
|
||||
0 => $param0,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function death_attack_generic(Translatable|string $param0) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::DEATH_ATTACK_GENERIC, [
|
||||
0 => $param0,
|
||||
@ -1025,6 +1056,14 @@ final class KnownTranslationFactory{
|
||||
return new Translatable(KnownTranslationKeys::ITEM_RECORD_CHIRP_DESC, []);
|
||||
}
|
||||
|
||||
public static function item_record_creator_desc() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::ITEM_RECORD_CREATOR_DESC, []);
|
||||
}
|
||||
|
||||
public static function item_record_creator_music_box_desc() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::ITEM_RECORD_CREATOR_MUSIC_BOX_DESC, []);
|
||||
}
|
||||
|
||||
public static function item_record_far_desc() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::ITEM_RECORD_FAR_DESC, []);
|
||||
}
|
||||
@ -1045,6 +1084,14 @@ final class KnownTranslationFactory{
|
||||
return new Translatable(KnownTranslationKeys::ITEM_RECORD_PIGSTEP_DESC, []);
|
||||
}
|
||||
|
||||
public static function item_record_precipice_desc() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::ITEM_RECORD_PRECIPICE_DESC, []);
|
||||
}
|
||||
|
||||
public static function item_record_relic_desc() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::ITEM_RECORD_RELIC_DESC, []);
|
||||
}
|
||||
|
||||
public static function item_record_stal_desc() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::ITEM_RECORD_STAL_DESC, []);
|
||||
}
|
||||
@ -1536,6 +1583,14 @@ final class KnownTranslationFactory{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_WHITELIST_DESCRIPTION, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_command_xp_description() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_XP_DESCRIPTION, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_command_xp_usage() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_XP_USAGE, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_crash_archive(Translatable|string $param0, Translatable|string $param1) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_CRASH_ARCHIVE, [
|
||||
0 => $param0,
|
||||
@ -2056,6 +2111,14 @@ final class KnownTranslationFactory{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_PERMISSION_COMMAND_WHITELIST_REMOVE, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_permission_command_xp_other() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_PERMISSION_COMMAND_XP_OTHER, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_permission_command_xp_self() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_PERMISSION_COMMAND_XP_SELF, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_permission_group_console() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_PERMISSION_GROUP_CONSOLE, []);
|
||||
}
|
||||
|
@ -137,6 +137,10 @@ final class KnownTranslationKeys{
|
||||
public const COMMANDS_WHITELIST_REMOVE_SUCCESS = "commands.whitelist.remove.success";
|
||||
public const COMMANDS_WHITELIST_REMOVE_USAGE = "commands.whitelist.remove.usage";
|
||||
public const COMMANDS_WHITELIST_USAGE = "commands.whitelist.usage";
|
||||
public const COMMANDS_XP_FAILURE_WIDTHDRAWXP = "commands.xp.failure.widthdrawXp";
|
||||
public const COMMANDS_XP_SUCCESS = "commands.xp.success";
|
||||
public const COMMANDS_XP_SUCCESS_LEVELS = "commands.xp.success.levels";
|
||||
public const COMMANDS_XP_SUCCESS_NEGATIVE_LEVELS = "commands.xp.success.negative.levels";
|
||||
public const DEATH_ATTACK_ANVIL = "death.attack.anvil";
|
||||
public const DEATH_ATTACK_ARROW = "death.attack.arrow";
|
||||
public const DEATH_ATTACK_ARROW_ITEM = "death.attack.arrow.item";
|
||||
@ -147,6 +151,7 @@ final class KnownTranslationKeys{
|
||||
public const DEATH_ATTACK_FALL = "death.attack.fall";
|
||||
public const DEATH_ATTACK_FALLINGBLOCK = "death.attack.fallingBlock";
|
||||
public const DEATH_ATTACK_FIREWORKS = "death.attack.fireworks";
|
||||
public const DEATH_ATTACK_FLYINTOWALL = "death.attack.flyIntoWall";
|
||||
public const DEATH_ATTACK_GENERIC = "death.attack.generic";
|
||||
public const DEATH_ATTACK_INFIRE = "death.attack.inFire";
|
||||
public const DEATH_ATTACK_INWALL = "death.attack.inWall";
|
||||
@ -227,11 +232,15 @@ final class KnownTranslationKeys{
|
||||
public const ITEM_RECORD_BLOCKS_DESC = "item.record_blocks.desc";
|
||||
public const ITEM_RECORD_CAT_DESC = "item.record_cat.desc";
|
||||
public const ITEM_RECORD_CHIRP_DESC = "item.record_chirp.desc";
|
||||
public const ITEM_RECORD_CREATOR_DESC = "item.record_creator.desc";
|
||||
public const ITEM_RECORD_CREATOR_MUSIC_BOX_DESC = "item.record_creator_music_box.desc";
|
||||
public const ITEM_RECORD_FAR_DESC = "item.record_far.desc";
|
||||
public const ITEM_RECORD_MALL_DESC = "item.record_mall.desc";
|
||||
public const ITEM_RECORD_MELLOHI_DESC = "item.record_mellohi.desc";
|
||||
public const ITEM_RECORD_OTHERSIDE_DESC = "item.record_otherside.desc";
|
||||
public const ITEM_RECORD_PIGSTEP_DESC = "item.record_pigstep.desc";
|
||||
public const ITEM_RECORD_PRECIPICE_DESC = "item.record_precipice.desc";
|
||||
public const ITEM_RECORD_RELIC_DESC = "item.record_relic.desc";
|
||||
public const ITEM_RECORD_STAL_DESC = "item.record_stal.desc";
|
||||
public const ITEM_RECORD_STRAD_DESC = "item.record_strad.desc";
|
||||
public const ITEM_RECORD_WAIT_DESC = "item.record_wait.desc";
|
||||
@ -336,6 +345,8 @@ final class KnownTranslationKeys{
|
||||
public const POCKETMINE_COMMAND_VERSION_SERVERSOFTWAREVERSION = "pocketmine.command.version.serverSoftwareVersion";
|
||||
public const POCKETMINE_COMMAND_VERSION_USAGE = "pocketmine.command.version.usage";
|
||||
public const POCKETMINE_COMMAND_WHITELIST_DESCRIPTION = "pocketmine.command.whitelist.description";
|
||||
public const POCKETMINE_COMMAND_XP_DESCRIPTION = "pocketmine.command.xp.description";
|
||||
public const POCKETMINE_COMMAND_XP_USAGE = "pocketmine.command.xp.usage";
|
||||
public const POCKETMINE_CRASH_ARCHIVE = "pocketmine.crash.archive";
|
||||
public const POCKETMINE_CRASH_CREATE = "pocketmine.crash.create";
|
||||
public const POCKETMINE_CRASH_ERROR = "pocketmine.crash.error";
|
||||
@ -449,6 +460,8 @@ final class KnownTranslationKeys{
|
||||
public const POCKETMINE_PERMISSION_COMMAND_WHITELIST_LIST = "pocketmine.permission.command.whitelist.list";
|
||||
public const POCKETMINE_PERMISSION_COMMAND_WHITELIST_RELOAD = "pocketmine.permission.command.whitelist.reload";
|
||||
public const POCKETMINE_PERMISSION_COMMAND_WHITELIST_REMOVE = "pocketmine.permission.command.whitelist.remove";
|
||||
public const POCKETMINE_PERMISSION_COMMAND_XP_OTHER = "pocketmine.permission.command.xp.other";
|
||||
public const POCKETMINE_PERMISSION_COMMAND_XP_SELF = "pocketmine.permission.command.xp.self";
|
||||
public const POCKETMINE_PERMISSION_GROUP_CONSOLE = "pocketmine.permission.group.console";
|
||||
public const POCKETMINE_PERMISSION_GROUP_OPERATOR = "pocketmine.permission.group.operator";
|
||||
public const POCKETMINE_PERMISSION_GROUP_USER = "pocketmine.permission.group.user";
|
||||
|
@ -493,15 +493,18 @@ class InGamePacketHandler extends PacketHandler{
|
||||
|
||||
$blockPos = $data->getBlockPosition();
|
||||
$vBlockPos = new Vector3($blockPos->getX(), $blockPos->getY(), $blockPos->getZ());
|
||||
if(!$this->player->interactBlock($vBlockPos, $data->getFace(), $clickPos)){
|
||||
$this->onFailedBlockAction($vBlockPos, $data->getFace());
|
||||
}
|
||||
$this->player->interactBlock($vBlockPos, $data->getFace(), $clickPos);
|
||||
//always sync this in case plugins caused a different result than the client expected
|
||||
//we *could* try to enhance detection of plugin-altered behaviour, but this would require propagating
|
||||
//more information up the stack. For now I think this is good enough.
|
||||
//if only the client would tell us what blocks it thinks changed...
|
||||
$this->syncBlocksNearby($vBlockPos, $data->getFace());
|
||||
return true;
|
||||
case UseItemTransactionData::ACTION_BREAK_BLOCK:
|
||||
$blockPos = $data->getBlockPosition();
|
||||
$vBlockPos = new Vector3($blockPos->getX(), $blockPos->getY(), $blockPos->getZ());
|
||||
if(!$this->player->breakBlock($vBlockPos)){
|
||||
$this->onFailedBlockAction($vBlockPos, null);
|
||||
$this->syncBlocksNearby($vBlockPos, null);
|
||||
}
|
||||
return true;
|
||||
case UseItemTransactionData::ACTION_CLICK_AIR:
|
||||
@ -529,9 +532,9 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function used to execute rollbacks when an action fails on a block.
|
||||
* Syncs blocks nearby to ensure that the client and server agree on the world's blocks after a block interaction.
|
||||
*/
|
||||
private function onFailedBlockAction(Vector3 $blockPos, ?int $face) : void{
|
||||
private function syncBlocksNearby(Vector3 $blockPos, ?int $face) : void{
|
||||
if($blockPos->distanceSquared($this->player->getLocation()) < 10000){
|
||||
$blocks = $blockPos->sidesArray();
|
||||
if($face !== null){
|
||||
@ -668,7 +671,7 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
public function handleActorPickRequest(ActorPickRequestPacket $packet) : bool{
|
||||
return false; //TODO
|
||||
return $this->player->pickEntity($packet->actorUniqueId);
|
||||
}
|
||||
|
||||
public function handlePlayerAction(PlayerActionPacket $packet) : bool{
|
||||
@ -682,7 +685,7 @@ class InGamePacketHandler extends PacketHandler{
|
||||
case PlayerAction::START_BREAK:
|
||||
self::validateFacing($face);
|
||||
if(!$this->player->attackBlock($pos, $face)){
|
||||
$this->onFailedBlockAction($pos, $face);
|
||||
$this->syncBlocksNearby($pos, $face);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -998,7 +1001,7 @@ class InGamePacketHandler extends PacketHandler{
|
||||
$lectern = $world->getBlockAt($pos->getX(), $pos->getY(), $pos->getZ());
|
||||
if($lectern instanceof Lectern && $this->player->canInteract($lectern->getPosition(), 15)){
|
||||
if(!$lectern->onPageTurn($packet->page)){
|
||||
$this->onFailedBlockAction($lectern->getPosition(), null);
|
||||
$this->syncBlocksNearby($lectern->getPosition(), null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -84,6 +84,8 @@ final class DefaultPermissionNames{
|
||||
public const COMMAND_WHITELIST_LIST = "pocketmine.command.whitelist.list";
|
||||
public const COMMAND_WHITELIST_RELOAD = "pocketmine.command.whitelist.reload";
|
||||
public const COMMAND_WHITELIST_REMOVE = "pocketmine.command.whitelist.remove";
|
||||
public const COMMAND_XP_OTHER = "pocketmine.command.xp.other";
|
||||
public const COMMAND_XP_SELF = "pocketmine.command.xp.self";
|
||||
public const GROUP_CONSOLE = "pocketmine.group.console";
|
||||
public const GROUP_OPERATOR = "pocketmine.group.operator";
|
||||
public const GROUP_USER = "pocketmine.group.user";
|
||||
|
@ -112,5 +112,7 @@ abstract class DefaultPermissions{
|
||||
self::registerPermission(new Permission(Names::COMMAND_WHITELIST_LIST, l10n::pocketmine_permission_command_whitelist_list()), [$operatorRoot]);
|
||||
self::registerPermission(new Permission(Names::COMMAND_WHITELIST_RELOAD, l10n::pocketmine_permission_command_whitelist_reload()), [$operatorRoot]);
|
||||
self::registerPermission(new Permission(Names::COMMAND_WHITELIST_REMOVE, l10n::pocketmine_permission_command_whitelist_remove()), [$operatorRoot]);
|
||||
self::registerPermission(new Permission(Names::COMMAND_XP_OTHER, l10n::pocketmine_permission_command_xp_other()), [$operatorRoot]);
|
||||
self::registerPermission(new Permission(Names::COMMAND_XP_SELF, l10n::pocketmine_permission_command_xp_self()), [$operatorRoot]);
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ use pocketmine\event\player\PlayerDisplayNameChangeEvent;
|
||||
use pocketmine\event\player\PlayerDropItemEvent;
|
||||
use pocketmine\event\player\PlayerEmoteEvent;
|
||||
use pocketmine\event\player\PlayerEntityInteractEvent;
|
||||
use pocketmine\event\player\PlayerEntityPickEvent;
|
||||
use pocketmine\event\player\PlayerExhaustEvent;
|
||||
use pocketmine\event\player\PlayerGameModeChangeEvent;
|
||||
use pocketmine\event\player\PlayerInteractEvent;
|
||||
@ -1709,29 +1710,58 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$ev->call();
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
if($existingSlot !== -1){
|
||||
if($existingSlot < $this->inventory->getHotbarSize()){
|
||||
$this->inventory->setHeldItemIndex($existingSlot);
|
||||
}else{
|
||||
$this->inventory->swap($this->inventory->getHeldItemIndex(), $existingSlot);
|
||||
}
|
||||
}else{
|
||||
$firstEmpty = $this->inventory->firstEmpty();
|
||||
if($firstEmpty === -1){ //full inventory
|
||||
$this->inventory->setItemInHand($item);
|
||||
}elseif($firstEmpty < $this->inventory->getHotbarSize()){
|
||||
$this->inventory->setItem($firstEmpty, $item);
|
||||
$this->inventory->setHeldItemIndex($firstEmpty);
|
||||
}else{
|
||||
$this->inventory->swap($this->inventory->getHeldItemIndex(), $firstEmpty);
|
||||
$this->inventory->setItemInHand($item);
|
||||
}
|
||||
}
|
||||
$this->equipOrAddPickedItem($existingSlot, $item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function pickEntity(int $entityId) : bool{
|
||||
$entity = $this->getWorld()->getEntity($entityId);
|
||||
if($entity === null){
|
||||
return true;
|
||||
}
|
||||
|
||||
$item = $entity->getPickedItem();
|
||||
if($item === null){
|
||||
return true;
|
||||
}
|
||||
|
||||
$ev = new PlayerEntityPickEvent($this, $entity, $item);
|
||||
$existingSlot = $this->inventory->first($item);
|
||||
if($existingSlot === -1 && ($this->hasFiniteResources() || $this->isSpectator())){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
$this->equipOrAddPickedItem($existingSlot, $item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function equipOrAddPickedItem(int $existingSlot, Item $item) : void{
|
||||
if($existingSlot !== -1){
|
||||
if($existingSlot < $this->inventory->getHotbarSize()){
|
||||
$this->inventory->setHeldItemIndex($existingSlot);
|
||||
}else{
|
||||
$this->inventory->swap($this->inventory->getHeldItemIndex(), $existingSlot);
|
||||
}
|
||||
}else{
|
||||
$firstEmpty = $this->inventory->firstEmpty();
|
||||
if($firstEmpty === -1){ //full inventory
|
||||
$this->inventory->setItemInHand($item);
|
||||
}elseif($firstEmpty < $this->inventory->getHotbarSize()){
|
||||
$this->inventory->setItem($firstEmpty, $item);
|
||||
$this->inventory->setHeldItemIndex($firstEmpty);
|
||||
}else{
|
||||
$this->inventory->swap($this->inventory->getHeldItemIndex(), $firstEmpty);
|
||||
$this->inventory->setItemInHand($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a left-click (attack) action on the block.
|
||||
*
|
||||
|
@ -80,7 +80,7 @@ use function preg_match_all;
|
||||
use function preg_replace;
|
||||
use function shell_exec;
|
||||
use function spl_object_id;
|
||||
use function str_ends_with;
|
||||
use function str_contains;
|
||||
use function str_pad;
|
||||
use function str_split;
|
||||
use function str_starts_with;
|
||||
@ -121,7 +121,7 @@ final class Utils{
|
||||
*/
|
||||
public static function getNiceClosureName(\Closure $closure) : string{
|
||||
$func = new \ReflectionFunction($closure);
|
||||
if(!str_ends_with($func->getName(), '{closure}')){
|
||||
if(!str_contains($func->getName(), '{closure')){
|
||||
//closure wraps a named function, can be done with reflection or fromCallable()
|
||||
//isClosure() is useless here because it just tells us if $func is reflecting a Closure object
|
||||
|
||||
|
@ -2037,7 +2037,7 @@ class World implements ChunkManager{
|
||||
* @param Item[] &$returnedItems Items to be added to the target's inventory (or dropped, if the inventory is full)
|
||||
* @phpstan-param-out Item $item
|
||||
*/
|
||||
public function useBreakOn(Vector3 $vector, Item &$item = null, ?Player $player = null, bool $createParticles = false, array &$returnedItems = []) : bool{
|
||||
public function useBreakOn(Vector3 $vector, ?Item &$item = null, ?Player $player = null, bool $createParticles = false, array &$returnedItems = []) : bool{
|
||||
$vector = $vector->floor();
|
||||
|
||||
$chunkX = $vector->getFloorX() >> Chunk::COORD_BIT_SIZE;
|
||||
@ -2173,19 +2173,25 @@ class World implements ChunkManager{
|
||||
|
||||
if($player !== null){
|
||||
$ev = new PlayerInteractEvent($player, $item, $blockClicked, $clickVector, $face, PlayerInteractEvent::RIGHT_CLICK_BLOCK);
|
||||
if($player->isSneaking()){
|
||||
$ev->setUseItem(false);
|
||||
$ev->setUseBlock($item->isNull()); //opening doors is still possible when sneaking if using an empty hand
|
||||
}
|
||||
if($player->isSpectator()){
|
||||
$ev->cancel(); //set it to cancelled so plugins can bypass this
|
||||
}
|
||||
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
if((!$player->isSneaking() || $item->isNull()) && $blockClicked->onInteract($item, $face, $clickVector, $player, $returnedItems)){
|
||||
if($ev->useBlock() && $blockClicked->onInteract($item, $face, $clickVector, $player, $returnedItems)){
|
||||
return true;
|
||||
}
|
||||
|
||||
$result = $item->onInteractBlock($player, $blockReplace, $blockClicked, $face, $clickVector, $returnedItems);
|
||||
if($result !== ItemUseResult::NONE){
|
||||
return $result === ItemUseResult::SUCCESS;
|
||||
if($ev->useItem()){
|
||||
$result = $item->onInteractBlock($player, $blockReplace, $blockClicked, $face, $clickVector, $returnedItems);
|
||||
if($result !== ItemUseResult::NONE){
|
||||
return $result === ItemUseResult::SUCCESS;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
|
46
src/world/sound/GoatHornSound.php
Normal file
46
src/world/sound/GoatHornSound.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?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\item\GoatHornType;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
|
||||
|
||||
class GoatHornSound implements Sound{
|
||||
public function __construct(private GoatHornType $goatHornType){}
|
||||
|
||||
public function encode(Vector3 $pos) : array{
|
||||
return [LevelSoundEventPacket::nonActorSound(match($this->goatHornType){
|
||||
GoatHornType::PONDER => LevelSoundEvent::HORN_CALL0,
|
||||
GoatHornType::SING => LevelSoundEvent::HORN_CALL1,
|
||||
GoatHornType::SEEK => LevelSoundEvent::HORN_CALL2,
|
||||
GoatHornType::FEEL => LevelSoundEvent::HORN_CALL3,
|
||||
GoatHornType::ADMIRE => LevelSoundEvent::HORN_CALL4,
|
||||
GoatHornType::CALL => LevelSoundEvent::HORN_CALL5,
|
||||
GoatHornType::YEARN => LevelSoundEvent::HORN_CALL6,
|
||||
GoatHornType::DREAM => LevelSoundEvent::HORN_CALL7
|
||||
}, $pos, false)];
|
||||
}
|
||||
}
|
27
start.sh
27
start.sh
@ -44,6 +44,27 @@ fi
|
||||
|
||||
LOOPS=0
|
||||
|
||||
handle_exit_code() {
|
||||
local exitcode=$1
|
||||
if [ "$exitcode" -eq 134 ] || [ "$exitcode" -eq 139 ]; then #SIGABRT/SIGSEGV
|
||||
echo ""
|
||||
echo "ERROR: The server process was killed due to a critical error (code $exitcode) which could indicate a problem with PHP."
|
||||
echo "Updating your PHP binary is recommended."
|
||||
echo "If this keeps happening, please open a bug report."
|
||||
echo ""
|
||||
elif [ "$exitcode" -eq 143 ]; then #SIGKILL, maybe user intervention
|
||||
echo ""
|
||||
echo "WARNING: Server was forcibly killed!"
|
||||
echo "If you didn't kill the server manually, this probably means the server used too much memory and was killed by the system's OOM Killer."
|
||||
echo "Please ensure your system has enough available RAM."
|
||||
echo ""
|
||||
elif [ "$exitcode" -ne 0 ] && [ "$exitcode" -ne 137 ]; then #normal exit / SIGTERM
|
||||
echo ""
|
||||
echo "WARNING: Server did not shut down correctly! (code $exitcode)"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
set +e
|
||||
|
||||
if [ "$DO_LOOP" == "yes" ]; then
|
||||
@ -52,11 +73,15 @@ if [ "$DO_LOOP" == "yes" ]; then
|
||||
echo "Restarted $LOOPS times"
|
||||
fi
|
||||
"$PHP_BINARY" "$POCKETMINE_FILE" "$@"
|
||||
handle_exit_code $?
|
||||
echo "To escape the loop, press CTRL+C now. Otherwise, wait 5 seconds for the server to restart."
|
||||
echo ""
|
||||
sleep 5
|
||||
((LOOPS++))
|
||||
done
|
||||
else
|
||||
exec "$PHP_BINARY" "$POCKETMINE_FILE" "$@"
|
||||
"$PHP_BINARY" "$POCKETMINE_FILE" "$@"
|
||||
exitcode=$?
|
||||
handle_exit_code $exitcode
|
||||
exit $exitcode
|
||||
fi
|
||||
|
@ -20,6 +20,56 @@ parameters:
|
||||
count: 1
|
||||
path: ../../../src/block/DoubleTallGrass.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:ACACIA_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:BIRCH_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:CHERRY_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:CRIMSON_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:DARK_OAK_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:JUNGLE_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:MANGROVE_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:OAK_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:SPRUCE_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:WARPED_SIGN\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/VanillaBlocks.php
|
||||
|
||||
-
|
||||
message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#"
|
||||
count: 1
|
||||
|
@ -51,6 +51,7 @@ class BlockTypeIdsTest extends TestCase{
|
||||
foreach(Utils::stringifyKeys(VanillaBlocks::getAll()) as $name => $block){
|
||||
$expected = $block->getTypeId();
|
||||
$actual = $reflect->getConstant($name);
|
||||
self::assertNotFalse($actual, "VanillaBlocks::$name() does not have a BlockTypeIds constant");
|
||||
self::assertSame($expected, $actual, "VanillaBlocks::$name() does not match BlockTypeIds::$name");
|
||||
}
|
||||
}
|
||||
|
92
tests/phpunit/console/ConsoleReaderChildProcessUtilsTest.php
Normal file
92
tests/phpunit/console/ConsoleReaderChildProcessUtilsTest.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?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\console;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function mt_rand;
|
||||
use function str_repeat;
|
||||
|
||||
final class ConsoleReaderChildProcessUtilsTest extends TestCase{
|
||||
|
||||
/**
|
||||
* @phpstan-return \Generator<int, array{string}, void, void>
|
||||
*/
|
||||
public static function commandStringProvider() : \Generator{
|
||||
yield ["stop"];
|
||||
yield ["pocketmine:status"];
|
||||
yield [str_repeat("s", 1000)];
|
||||
yield ["time set day"];
|
||||
yield ["give \"Steve\" golden_apple"];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider commandStringProvider
|
||||
*/
|
||||
public function testCreateParseSymmetry(string $input) : void{
|
||||
$counterCreate = $counterParse = mt_rand();
|
||||
$message = ConsoleReaderChildProcessUtils::createMessage($input, $counterCreate);
|
||||
$parsedInput = ConsoleReaderChildProcessUtils::parseMessage($message, $counterParse);
|
||||
|
||||
self::assertSame($input, $parsedInput);
|
||||
}
|
||||
|
||||
public function testCreateMessage() : void{
|
||||
$counter = 0;
|
||||
|
||||
ConsoleReaderChildProcessUtils::createMessage("", $counter);
|
||||
self::assertSame(1, $counter, "createMessage should always bump the counter");
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-return \Generator<int, array{string, bool}, void, void>
|
||||
*/
|
||||
public static function parseMessageProvider() : \Generator{
|
||||
$counter = 0;
|
||||
yield [ConsoleReaderChildProcessUtils::createMessage("", $counter), true];
|
||||
|
||||
yield ["", false]; //keepalive message, doesn't bump counter
|
||||
|
||||
$counter = 1;
|
||||
yield [ConsoleReaderChildProcessUtils::createMessage("", $counter), false]; //mismatched counter
|
||||
|
||||
$counter = 0;
|
||||
yield ["a" . ConsoleReaderChildProcessUtils::TOKEN_DELIMITER . "b", false]; //message with delimiter but not a valid IPC message
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider parseMessageProvider
|
||||
*/
|
||||
public static function testParseMessage(string $message, bool $valid) : void{
|
||||
$counter = $oldCounter = 0;
|
||||
|
||||
$input = ConsoleReaderChildProcessUtils::parseMessage($message, $counter);
|
||||
if(!$valid){
|
||||
self::assertNull($input, "Result should be null on invalid message");
|
||||
self::assertSame($oldCounter, $counter, "Counter shouldn't be bumped on invalid message");
|
||||
}else{
|
||||
self::assertNotNull($input, "This was a valid message, expected a result");
|
||||
self::assertSame($oldCounter + 1, $counter, "Counter should be bumped on valid message parse");
|
||||
}
|
||||
}
|
||||
}
|
68
tests/phpunit/event/EventTest.php
Normal file
68
tests/phpunit/event/EventTest.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?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;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use pocketmine\event\fixtures\TestChildEvent;
|
||||
use pocketmine\event\fixtures\TestGrandchildEvent;
|
||||
use pocketmine\event\fixtures\TestParentEvent;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use pocketmine\plugin\PluginManager;
|
||||
use pocketmine\Server;
|
||||
|
||||
final class EventTest extends TestCase{
|
||||
|
||||
public function testHandlerInheritance() : void{
|
||||
//TODO: this is a really bad hack and could break any time if PluginManager decides to access its Server field
|
||||
//we really need to make it possible to register events without a Plugin or Server context
|
||||
$mockServer = $this->createMock(Server::class);
|
||||
$mockPlugin = self::createStub(Plugin::class);
|
||||
$mockPlugin->method('isEnabled')->willReturn(true);
|
||||
|
||||
$pluginManager = new PluginManager($mockServer, null);
|
||||
|
||||
$expectedOrder = [
|
||||
TestGrandchildEvent::class,
|
||||
TestChildEvent::class,
|
||||
TestParentEvent::class
|
||||
];
|
||||
$actualOrder = [];
|
||||
|
||||
foreach($expectedOrder as $class){
|
||||
$pluginManager->registerEvent(
|
||||
$class,
|
||||
function(TestParentEvent $event) use (&$actualOrder, $class) : void{
|
||||
$actualOrder[] = $class;
|
||||
},
|
||||
EventPriority::NORMAL,
|
||||
$mockPlugin
|
||||
);
|
||||
}
|
||||
|
||||
$event = new TestGrandchildEvent();
|
||||
$event->call();
|
||||
|
||||
self::assertSame($expectedOrder, $actualOrder, "Expected event handlers to be called from most specific to least specific");
|
||||
}
|
||||
}
|
@ -24,6 +24,12 @@ declare(strict_types=1);
|
||||
namespace pocketmine\event;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use pocketmine\event\fixtures\TestAbstractAllowHandleEvent;
|
||||
use pocketmine\event\fixtures\TestAbstractEvent;
|
||||
use pocketmine\event\fixtures\TestConcreteEvent;
|
||||
use pocketmine\event\fixtures\TestConcreteExtendsAbstractEvent;
|
||||
use pocketmine\event\fixtures\TestConcreteExtendsAllowHandleEvent;
|
||||
use pocketmine\event\fixtures\TestConcreteExtendsConcreteEvent;
|
||||
|
||||
class HandlerListManagerTest extends TestCase{
|
||||
|
||||
|
@ -21,7 +21,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event;
|
||||
namespace pocketmine\event\fixtures;
|
||||
|
||||
use pocketmine\event\Event;
|
||||
|
||||
/**
|
||||
* @allowHandle
|
@ -21,7 +21,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event;
|
||||
namespace pocketmine\event\fixtures;
|
||||
|
||||
use pocketmine\event\Event;
|
||||
|
||||
abstract class TestAbstractEvent extends Event{
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pmmp\TesterPlugin\event;
|
||||
namespace pocketmine\event\fixtures;
|
||||
|
||||
class ChildEvent extends ParentEvent{
|
||||
class TestChildEvent extends TestParentEvent{
|
||||
|
||||
}
|
@ -21,7 +21,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event;
|
||||
namespace pocketmine\event\fixtures;
|
||||
|
||||
use pocketmine\event\Event;
|
||||
|
||||
class TestConcreteEvent extends Event{
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event;
|
||||
namespace pocketmine\event\fixtures;
|
||||
|
||||
class TestConcreteExtendsAbstractEvent extends TestAbstractEvent{
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event;
|
||||
namespace pocketmine\event\fixtures;
|
||||
|
||||
class TestConcreteExtendsAllowHandleEvent extends TestAbstractAllowHandleEvent{
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event;
|
||||
namespace pocketmine\event\fixtures;
|
||||
|
||||
class TestConcreteExtendsConcreteEvent extends TestConcreteEvent{
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pmmp\TesterPlugin\event;
|
||||
namespace pocketmine\event\fixtures;
|
||||
|
||||
class ParentEvent extends \pocketmine\event\Event{
|
||||
class TestGrandchildEvent extends TestChildEvent{
|
||||
|
||||
}
|
@ -21,8 +21,10 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pmmp\TesterPlugin\event;
|
||||
namespace pocketmine\event\fixtures;
|
||||
|
||||
class GrandchildEvent extends ChildEvent{
|
||||
use pocketmine\event\Event;
|
||||
|
||||
class TestParentEvent extends Event{
|
||||
|
||||
}
|
@ -54,6 +54,7 @@ class ItemTypeIdsTest extends TestCase{
|
||||
}
|
||||
$expected = $item->getTypeId();
|
||||
$actual = $reflect->getConstant($name);
|
||||
self::assertNotFalse($actual, "VanillaItems::$name() does not have an ItemTypeIds constant");
|
||||
self::assertSame($expected, $actual, "VanillaItems::$name() type ID does not match ItemTypeIds::$name");
|
||||
}
|
||||
}
|
||||
|
@ -1,88 +0,0 @@
|
||||
<?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 pmmp\TesterPlugin;
|
||||
|
||||
use pmmp\TesterPlugin\event\ChildEvent;
|
||||
use pmmp\TesterPlugin\event\GrandchildEvent;
|
||||
use pmmp\TesterPlugin\event\ParentEvent;
|
||||
use pocketmine\event\EventPriority;
|
||||
use function implode;
|
||||
|
||||
final class EventHandlerInheritanceTest extends Test{
|
||||
|
||||
private const EXPECTED_ORDER = [
|
||||
GrandchildEvent::class,
|
||||
ChildEvent::class,
|
||||
ParentEvent::class
|
||||
];
|
||||
|
||||
/** @var string[] */
|
||||
private array $callOrder = [];
|
||||
|
||||
public function getName() : string{
|
||||
return "Event Handler Inheritance Test";
|
||||
}
|
||||
|
||||
public function getDescription() : string{
|
||||
return "Tests that child events are correctly passed to parent event handlers";
|
||||
}
|
||||
|
||||
public function run() : void{
|
||||
$plugin = $this->getPlugin();
|
||||
$plugin->getServer()->getPluginManager()->registerEvent(
|
||||
ParentEvent::class,
|
||||
function(ParentEvent $event) : void{
|
||||
$this->callOrder[] = ParentEvent::class;
|
||||
},
|
||||
EventPriority::NORMAL,
|
||||
$plugin
|
||||
);
|
||||
$plugin->getServer()->getPluginManager()->registerEvent(
|
||||
ChildEvent::class,
|
||||
function(ChildEvent $event) : void{
|
||||
$this->callOrder[] = ChildEvent::class;
|
||||
},
|
||||
EventPriority::NORMAL,
|
||||
$plugin
|
||||
);
|
||||
$plugin->getServer()->getPluginManager()->registerEvent(
|
||||
GrandchildEvent::class,
|
||||
function(GrandchildEvent $event) : void{
|
||||
$this->callOrder[] = GrandchildEvent::class;
|
||||
},
|
||||
EventPriority::NORMAL,
|
||||
$plugin
|
||||
);
|
||||
|
||||
$event = new GrandchildEvent();
|
||||
$event->call();
|
||||
|
||||
if($this->callOrder === self::EXPECTED_ORDER){
|
||||
$this->setResult(Test::RESULT_OK);
|
||||
}else{
|
||||
$plugin->getLogger()->error("Expected order: " . implode(", ", self::EXPECTED_ORDER) . ", got: " . implode(", ", $this->callOrder));
|
||||
$this->setResult(Test::RESULT_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
@ -57,7 +57,6 @@ class Main extends PluginBase implements Listener{
|
||||
}), 10);
|
||||
|
||||
$this->waitingTests = [
|
||||
new EventHandlerInheritanceTest($this),
|
||||
new AsyncEventInheritanceTest($this),
|
||||
new AsyncEventConcurrencyTest($this),
|
||||
new AsyncEventPriorityTest($this)
|
||||
|
Loading…
x
Reference in New Issue
Block a user