mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-10-17 19:50:18 +00:00
RuntimeDataDescriber: Support dynamically describing arbitrary enums (#6039)
Previously, we were using codegen to support describing a fixed set of enums. Instead, we implement an enum() function, allowing any native PHP enum to be described. All enums used in runtime data have been migrated to native PHP 8.1 enums in minor-next to facilitate this. This implementation: - is faster (in extreme cases by 40x, such as with PotionType) - requires way less code - does not require a build step - is way more flexible This fixes #5877, increasing the range of stuff that plugins are now able to do. EnumTrait enums are not supported, as it's easier and cleaner to just support native enums. Most core EnumTrait enums have been migrated to native enums by now to facilitate this.
This commit is contained in:
@@ -24,67 +24,71 @@ declare(strict_types=1);
|
||||
namespace pocketmine\data\runtime;
|
||||
|
||||
/**
|
||||
* This class is auto-generated. Do not edit it manually.
|
||||
* @see build/generate-runtime-enum-serializers.php
|
||||
* Provides backwards-compatible shims for the old codegen'd enum describer methods.
|
||||
* This is kept for plugin backwards compatibility, but these functions should not be used in new code.
|
||||
* @deprecated
|
||||
*/
|
||||
trait RuntimeEnumSizeCalculatorTrait{
|
||||
trait LegacyRuntimeEnumDescriberTrait{
|
||||
|
||||
abstract protected function addBits(int $bits) : void;
|
||||
/**
|
||||
* @phpstan-template T of \UnitEnum
|
||||
* @phpstan-param T $case
|
||||
*/
|
||||
abstract protected function enum(\UnitEnum &$case) : void;
|
||||
|
||||
public function bellAttachmentType(\pocketmine\block\utils\BellAttachmentType &$value) : void{
|
||||
$this->addBits(2);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function copperOxidation(\pocketmine\block\utils\CopperOxidation &$value) : void{
|
||||
$this->addBits(2);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function coralType(\pocketmine\block\utils\CoralType &$value) : void{
|
||||
$this->addBits(3);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function dirtType(\pocketmine\block\utils\DirtType &$value) : void{
|
||||
$this->addBits(2);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function dripleafState(\pocketmine\block\utils\DripleafState &$value) : void{
|
||||
$this->addBits(2);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function dyeColor(\pocketmine\block\utils\DyeColor &$value) : void{
|
||||
$this->addBits(4);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function froglightType(\pocketmine\block\utils\FroglightType &$value) : void{
|
||||
$this->addBits(2);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function leverFacing(\pocketmine\block\utils\LeverFacing &$value) : void{
|
||||
$this->addBits(3);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function medicineType(\pocketmine\item\MedicineType &$value) : void{
|
||||
$this->addBits(2);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function mobHeadType(\pocketmine\block\utils\MobHeadType &$value) : void{
|
||||
$this->addBits(3);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function mushroomBlockType(\pocketmine\block\utils\MushroomBlockType &$value) : void{
|
||||
$this->addBits(4);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function potionType(\pocketmine\item\PotionType &$value) : void{
|
||||
$this->addBits(6);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function slabType(\pocketmine\block\utils\SlabType &$value) : void{
|
||||
$this->addBits(2);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
public function suspiciousStewType(\pocketmine\item\SuspiciousStewType &$value) : void{
|
||||
$this->addBits(4);
|
||||
$this->enum($value);
|
||||
}
|
||||
|
||||
}
|
@@ -77,4 +77,10 @@ interface RuntimeDataDescriber extends RuntimeEnumDescriber{
|
||||
public function railShape(int &$railShape) : void;
|
||||
|
||||
public function straightOnlyRailShape(int &$railShape) : void;
|
||||
|
||||
/**
|
||||
* @phpstan-template T of \UnitEnum
|
||||
* @phpstan-param T $case
|
||||
*/
|
||||
public function enum(\UnitEnum &$case) : void;
|
||||
}
|
||||
|
@@ -29,11 +29,12 @@ use pocketmine\block\utils\WallConnectionType;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use function get_class;
|
||||
use function intdiv;
|
||||
use function spl_object_id;
|
||||
|
||||
final class RuntimeDataReader implements RuntimeDataDescriber{
|
||||
use RuntimeEnumDeserializerTrait;
|
||||
use LegacyRuntimeEnumDescriberTrait;
|
||||
|
||||
private int $offset = 0;
|
||||
|
||||
@@ -210,5 +211,16 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
|
||||
$railShape = $result;
|
||||
}
|
||||
|
||||
public function enum(\UnitEnum &$case) : void{
|
||||
$metadata = RuntimeEnumMetadata::from($case);
|
||||
$raw = $this->readInt($metadata->bits);
|
||||
$result = $metadata->intToEnum($raw);
|
||||
if($result === null){
|
||||
throw new InvalidSerializedRuntimeDataException("Invalid serialized value $raw for " . get_class($case));
|
||||
}
|
||||
|
||||
$case = $result;
|
||||
}
|
||||
|
||||
public function getOffset() : int{ return $this->offset; }
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ use pocketmine\math\Facing;
|
||||
use function count;
|
||||
|
||||
final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
|
||||
use RuntimeEnumSizeCalculatorTrait;
|
||||
use LegacyRuntimeEnumDescriberTrait;
|
||||
|
||||
private int $bits = 0;
|
||||
|
||||
@@ -95,4 +95,9 @@ final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
|
||||
public function straightOnlyRailShape(int &$railShape) : void{
|
||||
$this->addBits(3);
|
||||
}
|
||||
|
||||
public function enum(\UnitEnum &$case) : void{
|
||||
$metadata = RuntimeEnumMetadata::from($case);
|
||||
$this->addBits($metadata->bits);
|
||||
}
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ use function array_flip;
|
||||
use function spl_object_id;
|
||||
|
||||
final class RuntimeDataWriter implements RuntimeDataDescriber{
|
||||
use RuntimeEnumSerializerTrait;
|
||||
use LegacyRuntimeEnumDescriberTrait;
|
||||
|
||||
private int $value = 0;
|
||||
private int $offset = 0;
|
||||
@@ -174,6 +174,11 @@ final class RuntimeDataWriter implements RuntimeDataDescriber{
|
||||
$this->int(3, $railShape);
|
||||
}
|
||||
|
||||
public function enum(\UnitEnum &$case) : void{
|
||||
$metadata = RuntimeEnumMetadata::from($case);
|
||||
$this->writeInt($metadata->bits, $metadata->enumToInt($case));
|
||||
}
|
||||
|
||||
public function getValue() : int{ return $this->value; }
|
||||
|
||||
public function getOffset() : int{ return $this->offset; }
|
||||
|
@@ -24,8 +24,9 @@ declare(strict_types=1);
|
||||
namespace pocketmine\data\runtime;
|
||||
|
||||
/**
|
||||
* This class is auto-generated. Do not edit it manually.
|
||||
* @see build/generate-runtime-enum-serializers.php
|
||||
* Provides backwards-compatible shims for the old codegen'd enum describer methods.
|
||||
* This is kept for plugin backwards compatibility, but these functions should not be used in new code.
|
||||
* @deprecated
|
||||
*/
|
||||
interface RuntimeEnumDescriber{
|
||||
|
||||
|
@@ -1,243 +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\data\runtime;
|
||||
|
||||
/**
|
||||
* This class is auto-generated. Do not edit it manually.
|
||||
* @see build/generate-runtime-enum-serializers.php
|
||||
*/
|
||||
trait RuntimeEnumDeserializerTrait{
|
||||
|
||||
abstract protected function readInt(int $bits) : int;
|
||||
|
||||
public function bellAttachmentType(\pocketmine\block\utils\BellAttachmentType &$value) : void{
|
||||
$value = match($this->readInt(2)){
|
||||
0 => \pocketmine\block\utils\BellAttachmentType::CEILING,
|
||||
1 => \pocketmine\block\utils\BellAttachmentType::FLOOR,
|
||||
2 => \pocketmine\block\utils\BellAttachmentType::ONE_WALL,
|
||||
3 => \pocketmine\block\utils\BellAttachmentType::TWO_WALLS,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for BellAttachmentType")
|
||||
};
|
||||
}
|
||||
|
||||
public function copperOxidation(\pocketmine\block\utils\CopperOxidation &$value) : void{
|
||||
$value = match($this->readInt(2)){
|
||||
0 => \pocketmine\block\utils\CopperOxidation::EXPOSED,
|
||||
1 => \pocketmine\block\utils\CopperOxidation::NONE,
|
||||
2 => \pocketmine\block\utils\CopperOxidation::OXIDIZED,
|
||||
3 => \pocketmine\block\utils\CopperOxidation::WEATHERED,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for CopperOxidation")
|
||||
};
|
||||
}
|
||||
|
||||
public function coralType(\pocketmine\block\utils\CoralType &$value) : void{
|
||||
$value = match($this->readInt(3)){
|
||||
0 => \pocketmine\block\utils\CoralType::BRAIN,
|
||||
1 => \pocketmine\block\utils\CoralType::BUBBLE,
|
||||
2 => \pocketmine\block\utils\CoralType::FIRE,
|
||||
3 => \pocketmine\block\utils\CoralType::HORN,
|
||||
4 => \pocketmine\block\utils\CoralType::TUBE,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for CoralType")
|
||||
};
|
||||
}
|
||||
|
||||
public function dirtType(\pocketmine\block\utils\DirtType &$value) : void{
|
||||
$value = match($this->readInt(2)){
|
||||
0 => \pocketmine\block\utils\DirtType::COARSE,
|
||||
1 => \pocketmine\block\utils\DirtType::NORMAL,
|
||||
2 => \pocketmine\block\utils\DirtType::ROOTED,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for DirtType")
|
||||
};
|
||||
}
|
||||
|
||||
public function dripleafState(\pocketmine\block\utils\DripleafState &$value) : void{
|
||||
$value = match($this->readInt(2)){
|
||||
0 => \pocketmine\block\utils\DripleafState::FULL_TILT,
|
||||
1 => \pocketmine\block\utils\DripleafState::PARTIAL_TILT,
|
||||
2 => \pocketmine\block\utils\DripleafState::STABLE,
|
||||
3 => \pocketmine\block\utils\DripleafState::UNSTABLE,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for DripleafState")
|
||||
};
|
||||
}
|
||||
|
||||
public function dyeColor(\pocketmine\block\utils\DyeColor &$value) : void{
|
||||
$value = match($this->readInt(4)){
|
||||
0 => \pocketmine\block\utils\DyeColor::BLACK,
|
||||
1 => \pocketmine\block\utils\DyeColor::BLUE,
|
||||
2 => \pocketmine\block\utils\DyeColor::BROWN,
|
||||
3 => \pocketmine\block\utils\DyeColor::CYAN,
|
||||
4 => \pocketmine\block\utils\DyeColor::GRAY,
|
||||
5 => \pocketmine\block\utils\DyeColor::GREEN,
|
||||
6 => \pocketmine\block\utils\DyeColor::LIGHT_BLUE,
|
||||
7 => \pocketmine\block\utils\DyeColor::LIGHT_GRAY,
|
||||
8 => \pocketmine\block\utils\DyeColor::LIME,
|
||||
9 => \pocketmine\block\utils\DyeColor::MAGENTA,
|
||||
10 => \pocketmine\block\utils\DyeColor::ORANGE,
|
||||
11 => \pocketmine\block\utils\DyeColor::PINK,
|
||||
12 => \pocketmine\block\utils\DyeColor::PURPLE,
|
||||
13 => \pocketmine\block\utils\DyeColor::RED,
|
||||
14 => \pocketmine\block\utils\DyeColor::WHITE,
|
||||
15 => \pocketmine\block\utils\DyeColor::YELLOW,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for DyeColor")
|
||||
};
|
||||
}
|
||||
|
||||
public function froglightType(\pocketmine\block\utils\FroglightType &$value) : void{
|
||||
$value = match($this->readInt(2)){
|
||||
0 => \pocketmine\block\utils\FroglightType::OCHRE,
|
||||
1 => \pocketmine\block\utils\FroglightType::PEARLESCENT,
|
||||
2 => \pocketmine\block\utils\FroglightType::VERDANT,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for FroglightType")
|
||||
};
|
||||
}
|
||||
|
||||
public function leverFacing(\pocketmine\block\utils\LeverFacing &$value) : void{
|
||||
$value = match($this->readInt(3)){
|
||||
0 => \pocketmine\block\utils\LeverFacing::DOWN_AXIS_X,
|
||||
1 => \pocketmine\block\utils\LeverFacing::DOWN_AXIS_Z,
|
||||
2 => \pocketmine\block\utils\LeverFacing::EAST,
|
||||
3 => \pocketmine\block\utils\LeverFacing::NORTH,
|
||||
4 => \pocketmine\block\utils\LeverFacing::SOUTH,
|
||||
5 => \pocketmine\block\utils\LeverFacing::UP_AXIS_X,
|
||||
6 => \pocketmine\block\utils\LeverFacing::UP_AXIS_Z,
|
||||
7 => \pocketmine\block\utils\LeverFacing::WEST,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for LeverFacing")
|
||||
};
|
||||
}
|
||||
|
||||
public function medicineType(\pocketmine\item\MedicineType &$value) : void{
|
||||
$value = match($this->readInt(2)){
|
||||
0 => \pocketmine\item\MedicineType::ANTIDOTE,
|
||||
1 => \pocketmine\item\MedicineType::ELIXIR,
|
||||
2 => \pocketmine\item\MedicineType::EYE_DROPS,
|
||||
3 => \pocketmine\item\MedicineType::TONIC,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for MedicineType")
|
||||
};
|
||||
}
|
||||
|
||||
public function mobHeadType(\pocketmine\block\utils\MobHeadType &$value) : void{
|
||||
$value = match($this->readInt(3)){
|
||||
0 => \pocketmine\block\utils\MobHeadType::CREEPER,
|
||||
1 => \pocketmine\block\utils\MobHeadType::DRAGON,
|
||||
2 => \pocketmine\block\utils\MobHeadType::PIGLIN,
|
||||
3 => \pocketmine\block\utils\MobHeadType::PLAYER,
|
||||
4 => \pocketmine\block\utils\MobHeadType::SKELETON,
|
||||
5 => \pocketmine\block\utils\MobHeadType::WITHER_SKELETON,
|
||||
6 => \pocketmine\block\utils\MobHeadType::ZOMBIE,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for MobHeadType")
|
||||
};
|
||||
}
|
||||
|
||||
public function mushroomBlockType(\pocketmine\block\utils\MushroomBlockType &$value) : void{
|
||||
$value = match($this->readInt(4)){
|
||||
0 => \pocketmine\block\utils\MushroomBlockType::ALL_CAP,
|
||||
1 => \pocketmine\block\utils\MushroomBlockType::CAP_EAST,
|
||||
2 => \pocketmine\block\utils\MushroomBlockType::CAP_MIDDLE,
|
||||
3 => \pocketmine\block\utils\MushroomBlockType::CAP_NORTH,
|
||||
4 => \pocketmine\block\utils\MushroomBlockType::CAP_NORTHEAST,
|
||||
5 => \pocketmine\block\utils\MushroomBlockType::CAP_NORTHWEST,
|
||||
6 => \pocketmine\block\utils\MushroomBlockType::CAP_SOUTH,
|
||||
7 => \pocketmine\block\utils\MushroomBlockType::CAP_SOUTHEAST,
|
||||
8 => \pocketmine\block\utils\MushroomBlockType::CAP_SOUTHWEST,
|
||||
9 => \pocketmine\block\utils\MushroomBlockType::CAP_WEST,
|
||||
10 => \pocketmine\block\utils\MushroomBlockType::PORES,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for MushroomBlockType")
|
||||
};
|
||||
}
|
||||
|
||||
public function potionType(\pocketmine\item\PotionType &$value) : void{
|
||||
$value = match($this->readInt(6)){
|
||||
0 => \pocketmine\item\PotionType::AWKWARD,
|
||||
1 => \pocketmine\item\PotionType::FIRE_RESISTANCE,
|
||||
2 => \pocketmine\item\PotionType::HARMING,
|
||||
3 => \pocketmine\item\PotionType::HEALING,
|
||||
4 => \pocketmine\item\PotionType::INVISIBILITY,
|
||||
5 => \pocketmine\item\PotionType::LEAPING,
|
||||
6 => \pocketmine\item\PotionType::LONG_FIRE_RESISTANCE,
|
||||
7 => \pocketmine\item\PotionType::LONG_INVISIBILITY,
|
||||
8 => \pocketmine\item\PotionType::LONG_LEAPING,
|
||||
9 => \pocketmine\item\PotionType::LONG_MUNDANE,
|
||||
10 => \pocketmine\item\PotionType::LONG_NIGHT_VISION,
|
||||
11 => \pocketmine\item\PotionType::LONG_POISON,
|
||||
12 => \pocketmine\item\PotionType::LONG_REGENERATION,
|
||||
13 => \pocketmine\item\PotionType::LONG_SLOWNESS,
|
||||
14 => \pocketmine\item\PotionType::LONG_SLOW_FALLING,
|
||||
15 => \pocketmine\item\PotionType::LONG_STRENGTH,
|
||||
16 => \pocketmine\item\PotionType::LONG_SWIFTNESS,
|
||||
17 => \pocketmine\item\PotionType::LONG_TURTLE_MASTER,
|
||||
18 => \pocketmine\item\PotionType::LONG_WATER_BREATHING,
|
||||
19 => \pocketmine\item\PotionType::LONG_WEAKNESS,
|
||||
20 => \pocketmine\item\PotionType::MUNDANE,
|
||||
21 => \pocketmine\item\PotionType::NIGHT_VISION,
|
||||
22 => \pocketmine\item\PotionType::POISON,
|
||||
23 => \pocketmine\item\PotionType::REGENERATION,
|
||||
24 => \pocketmine\item\PotionType::SLOWNESS,
|
||||
25 => \pocketmine\item\PotionType::SLOW_FALLING,
|
||||
26 => \pocketmine\item\PotionType::STRENGTH,
|
||||
27 => \pocketmine\item\PotionType::STRONG_HARMING,
|
||||
28 => \pocketmine\item\PotionType::STRONG_HEALING,
|
||||
29 => \pocketmine\item\PotionType::STRONG_LEAPING,
|
||||
30 => \pocketmine\item\PotionType::STRONG_POISON,
|
||||
31 => \pocketmine\item\PotionType::STRONG_REGENERATION,
|
||||
32 => \pocketmine\item\PotionType::STRONG_SLOWNESS,
|
||||
33 => \pocketmine\item\PotionType::STRONG_STRENGTH,
|
||||
34 => \pocketmine\item\PotionType::STRONG_SWIFTNESS,
|
||||
35 => \pocketmine\item\PotionType::STRONG_TURTLE_MASTER,
|
||||
36 => \pocketmine\item\PotionType::SWIFTNESS,
|
||||
37 => \pocketmine\item\PotionType::THICK,
|
||||
38 => \pocketmine\item\PotionType::TURTLE_MASTER,
|
||||
39 => \pocketmine\item\PotionType::WATER,
|
||||
40 => \pocketmine\item\PotionType::WATER_BREATHING,
|
||||
41 => \pocketmine\item\PotionType::WEAKNESS,
|
||||
42 => \pocketmine\item\PotionType::WITHER,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for PotionType")
|
||||
};
|
||||
}
|
||||
|
||||
public function slabType(\pocketmine\block\utils\SlabType &$value) : void{
|
||||
$value = match($this->readInt(2)){
|
||||
0 => \pocketmine\block\utils\SlabType::BOTTOM,
|
||||
1 => \pocketmine\block\utils\SlabType::DOUBLE,
|
||||
2 => \pocketmine\block\utils\SlabType::TOP,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for SlabType")
|
||||
};
|
||||
}
|
||||
|
||||
public function suspiciousStewType(\pocketmine\item\SuspiciousStewType &$value) : void{
|
||||
$value = match($this->readInt(4)){
|
||||
0 => \pocketmine\item\SuspiciousStewType::ALLIUM,
|
||||
1 => \pocketmine\item\SuspiciousStewType::AZURE_BLUET,
|
||||
2 => \pocketmine\item\SuspiciousStewType::BLUE_ORCHID,
|
||||
3 => \pocketmine\item\SuspiciousStewType::CORNFLOWER,
|
||||
4 => \pocketmine\item\SuspiciousStewType::DANDELION,
|
||||
5 => \pocketmine\item\SuspiciousStewType::LILY_OF_THE_VALLEY,
|
||||
6 => \pocketmine\item\SuspiciousStewType::OXEYE_DAISY,
|
||||
7 => \pocketmine\item\SuspiciousStewType::POPPY,
|
||||
8 => \pocketmine\item\SuspiciousStewType::TULIP,
|
||||
9 => \pocketmine\item\SuspiciousStewType::WITHER_ROSE,
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for SuspiciousStewType")
|
||||
};
|
||||
}
|
||||
|
||||
}
|
114
src/data/runtime/RuntimeEnumMetadata.php
Normal file
114
src/data/runtime/RuntimeEnumMetadata.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?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\runtime;
|
||||
|
||||
use function array_values;
|
||||
use function ceil;
|
||||
use function count;
|
||||
use function log;
|
||||
use function spl_object_id;
|
||||
use function usort;
|
||||
|
||||
/**
|
||||
* A big hack to allow lazily associating enum cases with packed bit values for RuntimeDataDescriber :)
|
||||
*
|
||||
* @internal
|
||||
* @phpstan-template T of \UnitEnum
|
||||
*/
|
||||
final class RuntimeEnumMetadata{
|
||||
public readonly int $bits;
|
||||
|
||||
/**
|
||||
* @var object[]
|
||||
* @phpstan-var list<T>
|
||||
*/
|
||||
private readonly array $intToEnum;
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private readonly array $enumToInt;
|
||||
|
||||
/**
|
||||
* @param \UnitEnum[] $members
|
||||
* @phpstan-param list<T> $members
|
||||
*/
|
||||
public function __construct(
|
||||
array $members
|
||||
){
|
||||
usort($members, fn(\UnitEnum $a, \UnitEnum $b) => $a->name <=> $b->name); //sort by name to ensure consistent ordering (and thus consistent bit assignments)
|
||||
|
||||
$this->bits = (int) ceil(log(count($members), 2));
|
||||
$this->intToEnum = array_values($members);
|
||||
|
||||
$reversed = [];
|
||||
foreach($this->intToEnum as $int => $enum){
|
||||
$reversed[spl_object_id($enum)] = $int;
|
||||
}
|
||||
|
||||
$this->enumToInt = $reversed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-return T|null
|
||||
*/
|
||||
public function intToEnum(int $value) : ?object{
|
||||
return $this->intToEnum[$value] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param T $enum
|
||||
*/
|
||||
public function enumToInt(object $enum) : int{
|
||||
return $this->enumToInt[spl_object_id($enum)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @var self[]
|
||||
* @phpstan-var array<class-string, object>
|
||||
*/
|
||||
private static array $cache = [];
|
||||
|
||||
/**
|
||||
* @phpstan-template TEnum of \UnitEnum
|
||||
* @phpstan-param TEnum $case
|
||||
*
|
||||
* @phpstan-return self<TEnum>
|
||||
*/
|
||||
public static function from(\UnitEnum $case) : self{
|
||||
$class = $case::class;
|
||||
/** @phpstan-var self<TEnum>|null $metadata */
|
||||
$metadata = self::$cache[$class] ?? null;
|
||||
if($metadata === null){
|
||||
/**
|
||||
* PHPStan can't infer this correctly :( https://github.com/phpstan/phpstan/issues/7162
|
||||
* @phpstan-var list<TEnum> $cases
|
||||
*/
|
||||
$cases = $case::cases();
|
||||
self::$cache[$class] = $metadata = new self($cases);
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
}
|
@@ -1,243 +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\data\runtime;
|
||||
|
||||
/**
|
||||
* This class is auto-generated. Do not edit it manually.
|
||||
* @see build/generate-runtime-enum-serializers.php
|
||||
*/
|
||||
trait RuntimeEnumSerializerTrait{
|
||||
|
||||
abstract protected function writeInt(int $bits, int $value) : void;
|
||||
|
||||
public function bellAttachmentType(\pocketmine\block\utils\BellAttachmentType &$value) : void{
|
||||
$this->writeInt(2, match($value){
|
||||
\pocketmine\block\utils\BellAttachmentType::CEILING => 0,
|
||||
\pocketmine\block\utils\BellAttachmentType::FLOOR => 1,
|
||||
\pocketmine\block\utils\BellAttachmentType::ONE_WALL => 2,
|
||||
\pocketmine\block\utils\BellAttachmentType::TWO_WALLS => 3,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All BellAttachmentType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function copperOxidation(\pocketmine\block\utils\CopperOxidation &$value) : void{
|
||||
$this->writeInt(2, match($value){
|
||||
\pocketmine\block\utils\CopperOxidation::EXPOSED => 0,
|
||||
\pocketmine\block\utils\CopperOxidation::NONE => 1,
|
||||
\pocketmine\block\utils\CopperOxidation::OXIDIZED => 2,
|
||||
\pocketmine\block\utils\CopperOxidation::WEATHERED => 3,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All CopperOxidation cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function coralType(\pocketmine\block\utils\CoralType &$value) : void{
|
||||
$this->writeInt(3, match($value){
|
||||
\pocketmine\block\utils\CoralType::BRAIN => 0,
|
||||
\pocketmine\block\utils\CoralType::BUBBLE => 1,
|
||||
\pocketmine\block\utils\CoralType::FIRE => 2,
|
||||
\pocketmine\block\utils\CoralType::HORN => 3,
|
||||
\pocketmine\block\utils\CoralType::TUBE => 4,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All CoralType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function dirtType(\pocketmine\block\utils\DirtType &$value) : void{
|
||||
$this->writeInt(2, match($value){
|
||||
\pocketmine\block\utils\DirtType::COARSE => 0,
|
||||
\pocketmine\block\utils\DirtType::NORMAL => 1,
|
||||
\pocketmine\block\utils\DirtType::ROOTED => 2,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All DirtType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function dripleafState(\pocketmine\block\utils\DripleafState &$value) : void{
|
||||
$this->writeInt(2, match($value){
|
||||
\pocketmine\block\utils\DripleafState::FULL_TILT => 0,
|
||||
\pocketmine\block\utils\DripleafState::PARTIAL_TILT => 1,
|
||||
\pocketmine\block\utils\DripleafState::STABLE => 2,
|
||||
\pocketmine\block\utils\DripleafState::UNSTABLE => 3,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All DripleafState cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function dyeColor(\pocketmine\block\utils\DyeColor &$value) : void{
|
||||
$this->writeInt(4, match($value){
|
||||
\pocketmine\block\utils\DyeColor::BLACK => 0,
|
||||
\pocketmine\block\utils\DyeColor::BLUE => 1,
|
||||
\pocketmine\block\utils\DyeColor::BROWN => 2,
|
||||
\pocketmine\block\utils\DyeColor::CYAN => 3,
|
||||
\pocketmine\block\utils\DyeColor::GRAY => 4,
|
||||
\pocketmine\block\utils\DyeColor::GREEN => 5,
|
||||
\pocketmine\block\utils\DyeColor::LIGHT_BLUE => 6,
|
||||
\pocketmine\block\utils\DyeColor::LIGHT_GRAY => 7,
|
||||
\pocketmine\block\utils\DyeColor::LIME => 8,
|
||||
\pocketmine\block\utils\DyeColor::MAGENTA => 9,
|
||||
\pocketmine\block\utils\DyeColor::ORANGE => 10,
|
||||
\pocketmine\block\utils\DyeColor::PINK => 11,
|
||||
\pocketmine\block\utils\DyeColor::PURPLE => 12,
|
||||
\pocketmine\block\utils\DyeColor::RED => 13,
|
||||
\pocketmine\block\utils\DyeColor::WHITE => 14,
|
||||
\pocketmine\block\utils\DyeColor::YELLOW => 15,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All DyeColor cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function froglightType(\pocketmine\block\utils\FroglightType &$value) : void{
|
||||
$this->writeInt(2, match($value){
|
||||
\pocketmine\block\utils\FroglightType::OCHRE => 0,
|
||||
\pocketmine\block\utils\FroglightType::PEARLESCENT => 1,
|
||||
\pocketmine\block\utils\FroglightType::VERDANT => 2,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All FroglightType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function leverFacing(\pocketmine\block\utils\LeverFacing &$value) : void{
|
||||
$this->writeInt(3, match($value){
|
||||
\pocketmine\block\utils\LeverFacing::DOWN_AXIS_X => 0,
|
||||
\pocketmine\block\utils\LeverFacing::DOWN_AXIS_Z => 1,
|
||||
\pocketmine\block\utils\LeverFacing::EAST => 2,
|
||||
\pocketmine\block\utils\LeverFacing::NORTH => 3,
|
||||
\pocketmine\block\utils\LeverFacing::SOUTH => 4,
|
||||
\pocketmine\block\utils\LeverFacing::UP_AXIS_X => 5,
|
||||
\pocketmine\block\utils\LeverFacing::UP_AXIS_Z => 6,
|
||||
\pocketmine\block\utils\LeverFacing::WEST => 7,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All LeverFacing cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function medicineType(\pocketmine\item\MedicineType &$value) : void{
|
||||
$this->writeInt(2, match($value){
|
||||
\pocketmine\item\MedicineType::ANTIDOTE => 0,
|
||||
\pocketmine\item\MedicineType::ELIXIR => 1,
|
||||
\pocketmine\item\MedicineType::EYE_DROPS => 2,
|
||||
\pocketmine\item\MedicineType::TONIC => 3,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All MedicineType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function mobHeadType(\pocketmine\block\utils\MobHeadType &$value) : void{
|
||||
$this->writeInt(3, match($value){
|
||||
\pocketmine\block\utils\MobHeadType::CREEPER => 0,
|
||||
\pocketmine\block\utils\MobHeadType::DRAGON => 1,
|
||||
\pocketmine\block\utils\MobHeadType::PIGLIN => 2,
|
||||
\pocketmine\block\utils\MobHeadType::PLAYER => 3,
|
||||
\pocketmine\block\utils\MobHeadType::SKELETON => 4,
|
||||
\pocketmine\block\utils\MobHeadType::WITHER_SKELETON => 5,
|
||||
\pocketmine\block\utils\MobHeadType::ZOMBIE => 6,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All MobHeadType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function mushroomBlockType(\pocketmine\block\utils\MushroomBlockType &$value) : void{
|
||||
$this->writeInt(4, match($value){
|
||||
\pocketmine\block\utils\MushroomBlockType::ALL_CAP => 0,
|
||||
\pocketmine\block\utils\MushroomBlockType::CAP_EAST => 1,
|
||||
\pocketmine\block\utils\MushroomBlockType::CAP_MIDDLE => 2,
|
||||
\pocketmine\block\utils\MushroomBlockType::CAP_NORTH => 3,
|
||||
\pocketmine\block\utils\MushroomBlockType::CAP_NORTHEAST => 4,
|
||||
\pocketmine\block\utils\MushroomBlockType::CAP_NORTHWEST => 5,
|
||||
\pocketmine\block\utils\MushroomBlockType::CAP_SOUTH => 6,
|
||||
\pocketmine\block\utils\MushroomBlockType::CAP_SOUTHEAST => 7,
|
||||
\pocketmine\block\utils\MushroomBlockType::CAP_SOUTHWEST => 8,
|
||||
\pocketmine\block\utils\MushroomBlockType::CAP_WEST => 9,
|
||||
\pocketmine\block\utils\MushroomBlockType::PORES => 10,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All MushroomBlockType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function potionType(\pocketmine\item\PotionType &$value) : void{
|
||||
$this->writeInt(6, match($value){
|
||||
\pocketmine\item\PotionType::AWKWARD => 0,
|
||||
\pocketmine\item\PotionType::FIRE_RESISTANCE => 1,
|
||||
\pocketmine\item\PotionType::HARMING => 2,
|
||||
\pocketmine\item\PotionType::HEALING => 3,
|
||||
\pocketmine\item\PotionType::INVISIBILITY => 4,
|
||||
\pocketmine\item\PotionType::LEAPING => 5,
|
||||
\pocketmine\item\PotionType::LONG_FIRE_RESISTANCE => 6,
|
||||
\pocketmine\item\PotionType::LONG_INVISIBILITY => 7,
|
||||
\pocketmine\item\PotionType::LONG_LEAPING => 8,
|
||||
\pocketmine\item\PotionType::LONG_MUNDANE => 9,
|
||||
\pocketmine\item\PotionType::LONG_NIGHT_VISION => 10,
|
||||
\pocketmine\item\PotionType::LONG_POISON => 11,
|
||||
\pocketmine\item\PotionType::LONG_REGENERATION => 12,
|
||||
\pocketmine\item\PotionType::LONG_SLOWNESS => 13,
|
||||
\pocketmine\item\PotionType::LONG_SLOW_FALLING => 14,
|
||||
\pocketmine\item\PotionType::LONG_STRENGTH => 15,
|
||||
\pocketmine\item\PotionType::LONG_SWIFTNESS => 16,
|
||||
\pocketmine\item\PotionType::LONG_TURTLE_MASTER => 17,
|
||||
\pocketmine\item\PotionType::LONG_WATER_BREATHING => 18,
|
||||
\pocketmine\item\PotionType::LONG_WEAKNESS => 19,
|
||||
\pocketmine\item\PotionType::MUNDANE => 20,
|
||||
\pocketmine\item\PotionType::NIGHT_VISION => 21,
|
||||
\pocketmine\item\PotionType::POISON => 22,
|
||||
\pocketmine\item\PotionType::REGENERATION => 23,
|
||||
\pocketmine\item\PotionType::SLOWNESS => 24,
|
||||
\pocketmine\item\PotionType::SLOW_FALLING => 25,
|
||||
\pocketmine\item\PotionType::STRENGTH => 26,
|
||||
\pocketmine\item\PotionType::STRONG_HARMING => 27,
|
||||
\pocketmine\item\PotionType::STRONG_HEALING => 28,
|
||||
\pocketmine\item\PotionType::STRONG_LEAPING => 29,
|
||||
\pocketmine\item\PotionType::STRONG_POISON => 30,
|
||||
\pocketmine\item\PotionType::STRONG_REGENERATION => 31,
|
||||
\pocketmine\item\PotionType::STRONG_SLOWNESS => 32,
|
||||
\pocketmine\item\PotionType::STRONG_STRENGTH => 33,
|
||||
\pocketmine\item\PotionType::STRONG_SWIFTNESS => 34,
|
||||
\pocketmine\item\PotionType::STRONG_TURTLE_MASTER => 35,
|
||||
\pocketmine\item\PotionType::SWIFTNESS => 36,
|
||||
\pocketmine\item\PotionType::THICK => 37,
|
||||
\pocketmine\item\PotionType::TURTLE_MASTER => 38,
|
||||
\pocketmine\item\PotionType::WATER => 39,
|
||||
\pocketmine\item\PotionType::WATER_BREATHING => 40,
|
||||
\pocketmine\item\PotionType::WEAKNESS => 41,
|
||||
\pocketmine\item\PotionType::WITHER => 42,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All PotionType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function slabType(\pocketmine\block\utils\SlabType &$value) : void{
|
||||
$this->writeInt(2, match($value){
|
||||
\pocketmine\block\utils\SlabType::BOTTOM => 0,
|
||||
\pocketmine\block\utils\SlabType::DOUBLE => 1,
|
||||
\pocketmine\block\utils\SlabType::TOP => 2,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All SlabType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
public function suspiciousStewType(\pocketmine\item\SuspiciousStewType &$value) : void{
|
||||
$this->writeInt(4, match($value){
|
||||
\pocketmine\item\SuspiciousStewType::ALLIUM => 0,
|
||||
\pocketmine\item\SuspiciousStewType::AZURE_BLUET => 1,
|
||||
\pocketmine\item\SuspiciousStewType::BLUE_ORCHID => 2,
|
||||
\pocketmine\item\SuspiciousStewType::CORNFLOWER => 3,
|
||||
\pocketmine\item\SuspiciousStewType::DANDELION => 4,
|
||||
\pocketmine\item\SuspiciousStewType::LILY_OF_THE_VALLEY => 5,
|
||||
\pocketmine\item\SuspiciousStewType::OXEYE_DAISY => 6,
|
||||
\pocketmine\item\SuspiciousStewType::POPPY => 7,
|
||||
\pocketmine\item\SuspiciousStewType::TULIP => 8,
|
||||
\pocketmine\item\SuspiciousStewType::WITHER_ROSE => 9,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All SuspiciousStewType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user