mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 19:24:12 +00:00
Compare commits
54 Commits
Author | SHA1 | Date | |
---|---|---|---|
a7fc245291 | |||
9bd6d5c67e | |||
aaa23361d1 | |||
691d92a959 | |||
50101663f2 | |||
e369966890 | |||
63f57841de | |||
ac3bba0a11 | |||
1ff3df6ff0 | |||
4e29b216bf | |||
809dad2ac8 | |||
e238d583b8 | |||
3f89bd7bff | |||
8da7e789fd | |||
0766952f39 | |||
eeee1fbe73 | |||
46c224da86 | |||
3c001b310f | |||
198a106b9f | |||
1f5e0bc96d | |||
41f7c07703 | |||
f0a0c9a85f | |||
5b620d964e | |||
756840f11d | |||
df2c3136c9 | |||
a6b5cddd5a | |||
5b9453af43 | |||
8bba25f4f5 | |||
f9bd7016aa | |||
213406fc60 | |||
7ff6e5895e | |||
2e6b62fdec | |||
4fc5b9772a | |||
5d4880b0a7 | |||
2b1a0e1e72 | |||
cd022f1592 | |||
4ae3fd7734 | |||
b2249f93c0 | |||
303344783a | |||
75e0844ff5 | |||
18fabf5466 | |||
2751c59979 | |||
d99ffbd66c | |||
a34f3261cb | |||
8ce0022de6 | |||
fb6491ddeb | |||
3b961d0e5f | |||
a60fc4cc28 | |||
b747899fdd | |||
57b6451e16 | |||
8cf025a2df | |||
8480ee82ea | |||
a6c1b7bf9c | |||
c267137fde |
8
.gitmodules
vendored
8
.gitmodules
vendored
@ -1,12 +1,12 @@
|
||||
[submodule "src/pocketmine/lang/locale"]
|
||||
path = src/pocketmine/lang/locale
|
||||
url = https://github.com/pmmp/PocketMine-Language.git
|
||||
url = https://github.com/pmmp/Language.git
|
||||
[submodule "tests/preprocessor"]
|
||||
path = build/preprocessor
|
||||
url = https://github.com/pmmp/preprocessor.git
|
||||
[submodule "tests/plugins/PocketMine-DevTools"]
|
||||
path = tests/plugins/PocketMine-DevTools
|
||||
url = https://github.com/pmmp/PocketMine-DevTools.git
|
||||
[submodule "tests/plugins/DevTools"]
|
||||
path = tests/plugins/DevTools
|
||||
url = https://github.com/pmmp/DevTools.git
|
||||
[submodule "build/php"]
|
||||
path = build/php
|
||||
url = https://github.com/pmmp/php-build-scripts.git
|
||||
|
@ -8,7 +8,7 @@ before_script:
|
||||
- echo | pecl install channel://pecl.php.net/yaml-2.1.0
|
||||
- git clone https://github.com/pmmp/pthreads.git
|
||||
- cd pthreads
|
||||
- git checkout 646dac62ae0d48c1ada7b007e15575fb84f7d71d
|
||||
- git checkout 45579e1e622acd80f9c880f3a025ba3b98b8ebef
|
||||
- phpize
|
||||
- ./configure
|
||||
- make
|
||||
|
@ -19,7 +19,7 @@
|
||||
## For developers
|
||||
* [Building and running from source](BUILDING.md)
|
||||
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development
|
||||
* [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins
|
||||
* [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
|
||||
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
||||
* [Contributing Guidelines](CONTRIBUTING.md)
|
||||
|
||||
|
@ -15,3 +15,26 @@ Plugin developers should **only** update their required API to this version if y
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
|
||||
# 3.14.1
|
||||
- All skins are now trusted, bypassing the client-side trusted skin setting. Note that this means that NSFW skin filtering will **not** apply.
|
||||
- Fixed projectile motion being altered by ladders.
|
||||
- Fixed client-sided crashes when pressing E repeatedly very quickly on a high-latency connection.
|
||||
- `/plugins`, `/whitelist list`, `/banlist` and `/list` now show output in alphabetical order.
|
||||
- Some `pocketmine\event` APIs which accept arrays now have more robust type checking, fixing type errors caused by plugin input occurring in core code.
|
||||
- `Attribute::getAttributeByName()` is now aware of the `minecraft:lava_movement` attribute.
|
||||
|
||||
# 3.14.2
|
||||
- Exception stack traces are now logged as CRITICAL. It's hoped that users will recognize that they are just as important as the error message and not leave them out when asking for help with errors on Discord.
|
||||
- `TaskScheduler` no longer accepts tasks that already have a handler. This fixes undefined behaviour which occurs when scheduling the same task instance twice, but it does break plugins such as **MyPlot** which unintentionally used this buggy behaviour.
|
||||
- Players will now correctly receive the needed number of spawn chunks if they are teleported between `PlayerLoginEvent` and `PlayerJoinEvent`. This fixes a bug that could occur when teleporting players in delayed tasks between login and join.
|
||||
- `PlayerRespawnEvent->setRespawnPosition()` now throws an exception if the provided `Position` has an invalid world associated with it (null or unloaded).
|
||||
- Fixed a crash that occurred when stats reporting was enabled.
|
||||
|
||||
# 3.14.3
|
||||
- Fixed deprecation error when running `/whitelist list` on PHP 7.4.
|
||||
- Fixed podzol breaking animation being incorrect (incorrect hardness).
|
||||
- `Entity::getSaveId()` now reports the class name in the message thrown for unregistered entities.
|
||||
- Fixed `CraftingManager->validate()` producing different results when called multiple times for the same transaction.
|
||||
- Fixed various issues with batch-crafting items using the recipe book and shift-clicking.
|
||||
- `tests/plugins/PocketMine-DevTools` submodule has been renamed to `tests/plugins/DevTools`.
|
||||
|
@ -38,7 +38,7 @@
|
||||
"ocramius/package-versions": "^1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "0.12.29",
|
||||
"phpstan/phpstan": "0.12.36",
|
||||
"phpstan/phpstan-phpunit": "^0.12.6",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.2",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
|
753
composer.lock
generated
753
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,6 @@ This site contains auto-generated API documentation for PocketMine-MP (and depen
|
||||
This site can be accessed via https://apidoc.pmmp.io.
|
||||
|
||||
### Additional developer resources
|
||||
- [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins
|
||||
- [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
|
||||
- [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
||||
- [DeveloperDocs](https://github.com/pmmp/DeveloperDocs/) - Reference, guides and specifications for the PocketMine-MP API
|
||||
|
@ -149,6 +149,7 @@ use pocketmine\network\mcpe\protocol\types\CommandParameter;
|
||||
use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||
use pocketmine\network\mcpe\protocol\types\GameMode;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
use pocketmine\network\mcpe\protocol\types\PersonaPieceTintColor;
|
||||
use pocketmine\network\mcpe\protocol\types\PersonaSkinPiece;
|
||||
@ -176,6 +177,7 @@ use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\UUID;
|
||||
use function abs;
|
||||
use function array_key_exists;
|
||||
use function array_merge;
|
||||
use function array_values;
|
||||
use function assert;
|
||||
@ -315,6 +317,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
/** @var CraftingTransaction|null */
|
||||
protected $craftingTransaction = null;
|
||||
|
||||
/**
|
||||
* TODO: HACK! This tracks GUIs for inventories that the server considers "always open" so that the client can't
|
||||
* open them twice. (1.16 hack)
|
||||
* @var true[]
|
||||
* @phpstan-var array<int, true>
|
||||
* @internal
|
||||
*/
|
||||
public $openHardcodedWindows = [];
|
||||
|
||||
/** @var int */
|
||||
protected $messageCounter = 2;
|
||||
/** @var bool */
|
||||
@ -1887,7 +1898,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
|
||||
$this->close("", $this->server->getLanguage()->translateString("pocketmine.disconnect.incompatibleProtocol", [$packet->protocol ?? "unknown"]), false);
|
||||
$this->close("", $this->server->getLanguage()->translateString("pocketmine.disconnect.incompatibleProtocol", [$packet->protocol]), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2382,18 +2393,20 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
/** @var InventoryAction[] $actions */
|
||||
$actions = [];
|
||||
$isCraftingPart = false;
|
||||
$isFinalCraftingPart = false;
|
||||
foreach($packet->actions as $networkInventoryAction){
|
||||
if(
|
||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_TODO and (
|
||||
$networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT or
|
||||
$networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_USE_INGREDIENT
|
||||
) or (
|
||||
$this->craftingTransaction !== null &&
|
||||
!$networkInventoryAction->oldItem->equalsExact($networkInventoryAction->newItem) &&
|
||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER &&
|
||||
$networkInventoryAction->windowId === ContainerIds::UI &&
|
||||
$networkInventoryAction->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT
|
||||
)
|
||||
){
|
||||
$isCraftingPart = true;
|
||||
if($networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT){
|
||||
$isFinalCraftingPart = true;
|
||||
}
|
||||
}
|
||||
try{
|
||||
$action = $networkInventoryAction->createInventoryAction($this);
|
||||
@ -2416,23 +2429,23 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
if($isFinalCraftingPart){
|
||||
//we get the actions for this in several packets, so we need to wait until we have all the pieces before
|
||||
//trying to execute it
|
||||
|
||||
$ret = true;
|
||||
try{
|
||||
$this->craftingTransaction->execute();
|
||||
}catch(TransactionValidationException $e){
|
||||
$this->server->getLogger()->debug("Failed to execute crafting transaction for " . $this->getName() . ": " . $e->getMessage());
|
||||
$ret = false;
|
||||
}
|
||||
|
||||
$this->craftingTransaction = null;
|
||||
return $ret;
|
||||
try{
|
||||
$this->craftingTransaction->validate();
|
||||
}catch(TransactionValidationException $e){
|
||||
//transaction is incomplete - crafting transaction comes in lots of little bits, so we have to collect
|
||||
//all of the parts before we can execute it
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
try{
|
||||
$this->craftingTransaction->execute();
|
||||
return true;
|
||||
}catch(TransactionValidationException $e){
|
||||
$this->server->getLogger()->debug("Failed to execute crafting transaction for " . $this->getName() . ": " . $e->getMessage());
|
||||
return false;
|
||||
}finally{
|
||||
$this->craftingTransaction = null;
|
||||
}
|
||||
}elseif($this->craftingTransaction !== null){
|
||||
$this->server->getLogger()->debug("Got unexpected normal inventory action with incomplete crafting transaction from " . $this->getName() . ", refusing to execute crafting");
|
||||
$this->craftingTransaction = null;
|
||||
@ -2795,12 +2808,13 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
case InteractPacket::ACTION_MOUSEOVER:
|
||||
break; //TODO: handle these
|
||||
case InteractPacket::ACTION_OPEN_INVENTORY:
|
||||
if($target === $this){
|
||||
if($target === $this && !array_key_exists($windowId = self::HARDCODED_INVENTORY_WINDOW_ID, $this->openHardcodedWindows)){
|
||||
//TODO: HACK! this restores 1.14ish behaviour, but this should be able to be listened to and
|
||||
//controlled by plugins. However, the player is always a subscriber to their own inventory so it
|
||||
//doesn't integrate well with the regular container system right now.
|
||||
$this->openHardcodedWindows[$windowId] = true;
|
||||
$pk = new ContainerOpenPacket();
|
||||
$pk->windowId = self::HARDCODED_INVENTORY_WINDOW_ID;
|
||||
$pk->windowId = $windowId;
|
||||
$pk->type = WindowTypes::INVENTORY;
|
||||
$pk->x = $pk->y = $pk->z = 0;
|
||||
$pk->entityUniqueId = $this->getId();
|
||||
@ -3027,7 +3041,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$this->doCloseInventory();
|
||||
|
||||
if($packet->windowId >= self::RESERVED_WINDOW_ID_RANGE_START and $packet->windowId <= self::RESERVED_WINDOW_ID_RANGE_END){
|
||||
if(array_key_exists($packet->windowId, $this->openHardcodedWindows)){
|
||||
unset($this->openHardcodedWindows[$packet->windowId]);
|
||||
$pk = new ContainerClosePacket();
|
||||
$pk->windowId = $packet->windowId;
|
||||
$this->sendDataPacket($pk);
|
||||
@ -3911,6 +3926,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$this->resetFallDistance();
|
||||
$this->nextChunkOrderRun = 0;
|
||||
if($this->spawnChunkLoadCount !== -1){
|
||||
$this->spawnChunkLoadCount = 0;
|
||||
}
|
||||
$this->stopSleep();
|
||||
|
||||
//TODO: workaround for player last pos not getting updated
|
||||
|
@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
|
||||
const _VERSION_INFO_INCLUDED = true;
|
||||
|
||||
const NAME = "PocketMine-MP";
|
||||
const BASE_VERSION = "3.14.0";
|
||||
const BASE_VERSION = "3.14.3";
|
||||
const IS_DEVELOPMENT_BUILD = false;
|
||||
const BUILD_NUMBER = 0;
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
use pocketmine\Player;
|
||||
use function array_key_exists;
|
||||
|
||||
class CraftingTable extends Solid{
|
||||
|
||||
@ -53,15 +54,18 @@ class CraftingTable extends Solid{
|
||||
if($player instanceof Player){
|
||||
$player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG));
|
||||
|
||||
//TODO: HACK! crafting grid doesn't fit very well into the current PM container system, so this hack allows
|
||||
//it to carry on working approximately the same way as it did in 1.14
|
||||
$pk = new ContainerOpenPacket();
|
||||
$pk->windowId = Player::HARDCODED_CRAFTING_GRID_WINDOW_ID;
|
||||
$pk->type = WindowTypes::WORKBENCH;
|
||||
$pk->x = $this->getFloorX();
|
||||
$pk->y = $this->getFloorY();
|
||||
$pk->z = $this->getFloorZ();
|
||||
$player->sendDataPacket($pk);
|
||||
if(!array_key_exists($windowId = Player::HARDCODED_CRAFTING_GRID_WINDOW_ID, $player->openHardcodedWindows)){
|
||||
//TODO: HACK! crafting grid doesn't fit very well into the current PM container system, so this hack allows
|
||||
//it to carry on working approximately the same way as it did in 1.14
|
||||
$pk = new ContainerOpenPacket();
|
||||
$pk->windowId = $windowId;
|
||||
$pk->type = WindowTypes::WORKBENCH;
|
||||
$pk->x = $this->getFloorX();
|
||||
$pk->y = $this->getFloorY();
|
||||
$pk->z = $this->getFloorZ();
|
||||
$player->sendDataPacket($pk);
|
||||
$player->openHardcodedWindows[$windowId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -58,7 +59,7 @@ class Ladder extends Transparent{
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
if($entity->asVector3()->floor()->distanceSquared($this) < 1){ //entity coordinates must be inside block
|
||||
if($entity instanceof Living and $entity->asVector3()->floor()->distanceSquared($this) < 1){ //entity coordinates must be inside block
|
||||
$entity->resetFallDistance();
|
||||
$entity->onGround = true;
|
||||
}
|
||||
|
@ -40,6 +40,6 @@ class Podzol extends Solid{
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2.5;
|
||||
return 0.5;
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,9 @@ use pocketmine\permission\BanEntry;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sort;
|
||||
use function strtolower;
|
||||
use const SORT_STRING;
|
||||
|
||||
class BanListCommand extends VanillaCommand{
|
||||
|
||||
@ -62,10 +64,11 @@ class BanListCommand extends VanillaCommand{
|
||||
$args[0] = "players";
|
||||
}
|
||||
|
||||
$list = $list->getEntries();
|
||||
$message = implode(", ", array_map(function(BanEntry $entry) : string{
|
||||
$list = array_map(function(BanEntry $entry) : string{
|
||||
return $entry->getName();
|
||||
}, $list));
|
||||
}, $list->getEntries());
|
||||
sort($list, SORT_STRING);
|
||||
$message = implode(", ", $list);
|
||||
|
||||
if($args[0] === "ips"){
|
||||
$sender->sendMessage(new TranslationContainer("commands.banlist.ips", [count($list)]));
|
||||
|
@ -30,6 +30,8 @@ use function array_filter;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sort;
|
||||
use const SORT_STRING;
|
||||
|
||||
class ListCommand extends VanillaCommand{
|
||||
|
||||
@ -52,6 +54,7 @@ class ListCommand extends VanillaCommand{
|
||||
}, array_filter($sender->getServer()->getOnlinePlayers(), function(Player $player) use ($sender) : bool{
|
||||
return $player->isOnline() and (!($sender instanceof Player) or $sender->canSee($player));
|
||||
}));
|
||||
sort($playerNames, SORT_STRING);
|
||||
|
||||
$sender->sendMessage(new TranslationContainer("commands.players.list", [count($playerNames), $sender->getServer()->getMaxPlayers()]));
|
||||
$sender->sendMessage(implode(", ", $playerNames));
|
||||
|
@ -30,6 +30,8 @@ use pocketmine\utils\TextFormat;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sort;
|
||||
use const SORT_STRING;
|
||||
|
||||
class PluginsCommand extends VanillaCommand{
|
||||
|
||||
@ -51,6 +53,7 @@ class PluginsCommand extends VanillaCommand{
|
||||
$list = array_map(function(Plugin $plugin) : string{
|
||||
return ($plugin->isEnabled() ? TextFormat::GREEN : TextFormat::RED) . $plugin->getDescription()->getFullName();
|
||||
}, $sender->getServer()->getPluginManager()->getPlugins());
|
||||
sort($list, SORT_STRING);
|
||||
|
||||
$sender->sendMessage(new TranslationContainer("pocketmine.command.plugins.success", [count($list), implode(TextFormat::WHITE . ", ", $list)]));
|
||||
return true;
|
||||
|
@ -31,7 +31,9 @@ use pocketmine\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sort;
|
||||
use function strtolower;
|
||||
use const SORT_STRING;
|
||||
|
||||
class WhitelistCommand extends VanillaCommand{
|
||||
|
||||
@ -71,7 +73,8 @@ class WhitelistCommand extends VanillaCommand{
|
||||
return true;
|
||||
case "list":
|
||||
$entries = $sender->getServer()->getWhitelisted()->getAll(true);
|
||||
$result = implode($entries, ", ");
|
||||
sort($entries, SORT_STRING);
|
||||
$result = implode(", ", $entries);
|
||||
$count = count($entries);
|
||||
|
||||
$sender->sendMessage(new TranslationContainer("commands.whitelist.list", [$count, $count]));
|
||||
|
@ -45,6 +45,7 @@ class Attribute{
|
||||
public const FALL_DAMAGE = 13;
|
||||
public const HORSE_JUMP_STRENGTH = 14;
|
||||
public const ZOMBIE_SPAWN_REINFORCEMENTS = 15;
|
||||
public const LAVA_MOVEMENT = 16;
|
||||
|
||||
/** @var int */
|
||||
private $id;
|
||||
@ -84,6 +85,7 @@ class Attribute{
|
||||
self::addAttribute(self::FALL_DAMAGE, "minecraft:fall_damage", 0.0, 340282346638528859811704183484516925440.0, 1.0);
|
||||
self::addAttribute(self::HORSE_JUMP_STRENGTH, "minecraft:horse.jump_strength", 0.0, 2.0, 0.7);
|
||||
self::addAttribute(self::ZOMBIE_SPAWN_REINFORCEMENTS, "minecraft:zombie.spawn_reinforcements", 0.0, 1.0, 0.0);
|
||||
self::addAttribute(self::LAVA_MOVEMENT, "minecraft:lava_movement", 0.0, 340282346638528859811704183484516925440.0, 0.02);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -868,7 +868,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
*/
|
||||
public function getSaveId() : string{
|
||||
if(!isset(self::$saveNames[static::class])){
|
||||
throw new \InvalidStateException("Entity is not registered");
|
||||
throw new \InvalidStateException("Entity " . static::class . " is not registered");
|
||||
}
|
||||
reset(self::$saveNames[static::class]);
|
||||
return current(self::$saveNames[static::class]);
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\event\block;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
@ -79,6 +80,7 @@ class SignChangeEvent extends BlockEvent implements Cancellable{
|
||||
if(count($lines) !== 4){
|
||||
throw new \InvalidArgumentException("Array size must be 4!");
|
||||
}
|
||||
Utils::validateArrayValueType($lines, function(string $_) : void{});
|
||||
$this->lines = $lines;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
/**
|
||||
* @phpstan-extends EntityEvent<Living>
|
||||
@ -62,6 +63,7 @@ class EntityDeathEvent extends EntityEvent{
|
||||
* @param Item[] $drops
|
||||
*/
|
||||
public function setDrops(array $drops) : void{
|
||||
Utils::validateArrayValueType($drops, function(Item $_) : void{});
|
||||
$this->drops = $drops;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\block\Block;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
/**
|
||||
* Called when a entity explodes
|
||||
@ -67,6 +68,7 @@ class EntityExplodeEvent extends EntityEvent implements Cancellable{
|
||||
* @param Block[] $blocks
|
||||
*/
|
||||
public function setBlockList(array $blocks) : void{
|
||||
Utils::validateArrayValueType($blocks, function(Block $_) : void{});
|
||||
$this->blocks = $blocks;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\event\Cancellable;
|
||||
use pocketmine\permission\PermissionManager;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\Utils;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
@ -97,6 +98,7 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{
|
||||
* @param CommandSender[] $recipients
|
||||
*/
|
||||
public function setRecipients(array $recipients) : void{
|
||||
Utils::validateArrayValueType($recipients, function(CommandSender $_) : void{});
|
||||
$this->recipients = $recipients;
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,9 @@ class PlayerRespawnEvent extends PlayerEvent{
|
||||
}
|
||||
|
||||
public function setRespawnPosition(Position $position) : void{
|
||||
if(!$position->isValid()){
|
||||
throw new \InvalidArgumentException("Spawn position must reference a valid and loaded World");
|
||||
}
|
||||
$this->position = $position;
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\Utils;
|
||||
use function chr;
|
||||
use function count;
|
||||
use function str_replace;
|
||||
@ -145,6 +146,7 @@ class QueryRegenerateEvent extends ServerEvent{
|
||||
* @param Plugin[] $plugins
|
||||
*/
|
||||
public function setPlugins(array $plugins) : void{
|
||||
Utils::validateArrayValueType($plugins, function(Plugin $_) : void{});
|
||||
$this->plugins = $plugins;
|
||||
$this->destroyCache();
|
||||
}
|
||||
@ -160,6 +162,7 @@ class QueryRegenerateEvent extends ServerEvent{
|
||||
* @param Player[] $players
|
||||
*/
|
||||
public function setPlayerList(array $players) : void{
|
||||
Utils::validateArrayValueType($players, function(Player $_) : void{});
|
||||
$this->players = $players;
|
||||
$this->destroyCache();
|
||||
}
|
||||
|
@ -28,8 +28,10 @@ use pocketmine\network\mcpe\protocol\BatchPacket;
|
||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use function array_map;
|
||||
use function file_get_contents;
|
||||
use function is_array;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function usort;
|
||||
@ -52,41 +54,39 @@ class CraftingManager{
|
||||
|
||||
public function init() : void{
|
||||
$recipes = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla" . DIRECTORY_SEPARATOR . "recipes.json"), true);
|
||||
if(!is_array($recipes)){
|
||||
throw new AssumptionFailedError("recipes.json root should contain a map of recipe types");
|
||||
}
|
||||
|
||||
$itemDeserializerFunc = \Closure::fromCallable([Item::class, 'jsonDeserialize']);
|
||||
foreach($recipes as $recipe){
|
||||
switch($recipe["type"]){
|
||||
case "shapeless":
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
break;
|
||||
}
|
||||
$this->registerShapelessRecipe(new ShapelessRecipe(
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
));
|
||||
break;
|
||||
case "shaped":
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
break;
|
||||
}
|
||||
$this->registerShapedRecipe(new ShapedRecipe(
|
||||
$recipe["shape"],
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
));
|
||||
break;
|
||||
case "smelting":
|
||||
if($recipe["block"] !== "furnace"){ //TODO: filter others out for now to avoid breaking economics
|
||||
break;
|
||||
}
|
||||
$this->registerFurnaceRecipe(new FurnaceRecipe(
|
||||
Item::jsonDeserialize($recipe["output"]),
|
||||
Item::jsonDeserialize($recipe["input"]))
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
foreach($recipes["shapeless"] as $recipe){
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
continue;
|
||||
}
|
||||
$this->registerShapelessRecipe(new ShapelessRecipe(
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
));
|
||||
}
|
||||
foreach($recipes["shaped"] as $recipe){
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
continue;
|
||||
}
|
||||
$this->registerShapedRecipe(new ShapedRecipe(
|
||||
$recipe["shape"],
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
));
|
||||
}
|
||||
foreach($recipes["smelting"] as $recipe){
|
||||
if($recipe["block"] !== "furnace"){ //TODO: filter others out for now to avoid breaking economics
|
||||
continue;
|
||||
}
|
||||
$this->registerFurnaceRecipe(new FurnaceRecipe(
|
||||
Item::jsonDeserialize($recipe["output"]),
|
||||
Item::jsonDeserialize($recipe["input"]))
|
||||
);
|
||||
}
|
||||
|
||||
$this->buildCraftingDataCache();
|
||||
|
@ -136,6 +136,8 @@ class InventoryTransaction{
|
||||
* @throws TransactionValidationException
|
||||
*/
|
||||
protected function matchItems(array &$needItems, array &$haveItems) : void{
|
||||
$needItems = [];
|
||||
$haveItems = [];
|
||||
foreach($this->actions as $key => $action){
|
||||
if(!$action->getTargetItem()->isNull()){
|
||||
$needItems[] = $action->getTargetItem();
|
||||
|
@ -30,7 +30,7 @@ use pocketmine\network\mcpe\NetworkSession;
|
||||
class EmotePacket extends DataPacket/* implements ClientboundPacket, ServerboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::EMOTE_PACKET;
|
||||
|
||||
private const FLAG_SERVER = 1 << 0;
|
||||
public const FLAG_SERVER = 1 << 0;
|
||||
|
||||
/** @var int */
|
||||
private $entityRuntimeId;
|
||||
|
@ -129,6 +129,8 @@ class InventoryTransactionPacket extends DataPacket{
|
||||
|
||||
$this->putUnsignedVarInt($this->transactionType);
|
||||
|
||||
$this->putBool($this->hasItemStackIds);
|
||||
|
||||
$this->putUnsignedVarInt(count($this->actions));
|
||||
foreach($this->actions as $action){
|
||||
$action->write($this, $this->hasItemStackIds);
|
||||
|
@ -78,7 +78,7 @@ class LoginPacket extends DataPacket{
|
||||
}
|
||||
|
||||
public function mayHaveUnreadBytes() : bool{
|
||||
return $this->protocol !== null and $this->protocol !== ProtocolInfo::CURRENT_PROTOCOL;
|
||||
return $this->protocol !== ProtocolInfo::CURRENT_PROTOCOL;
|
||||
}
|
||||
|
||||
protected function decodePayload(){
|
||||
@ -92,7 +92,7 @@ class LoginPacket extends DataPacket{
|
||||
}
|
||||
|
||||
$logger = MainLogger::getLogger();
|
||||
$logger->debug(get_class($e) . " was thrown while decoding connection request in login (protocol version " . ($this->protocol ?? "unknown") . "): " . $e->getMessage());
|
||||
$logger->debug(get_class($e) . " was thrown while decoding connection request in login (protocol version $this->protocol): " . $e->getMessage());
|
||||
foreach(Utils::printableTrace($e->getTrace()) as $line){
|
||||
$logger->debug($line);
|
||||
}
|
||||
|
@ -128,8 +128,8 @@ class PlayerAuthInputPacket extends DataPacket/* implements ServerboundPacket*/{
|
||||
}
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->yaw = $this->getLFloat();
|
||||
$this->pitch = $this->getLFloat();
|
||||
$this->yaw = $this->getLFloat();
|
||||
$this->position = $this->getVector3();
|
||||
$this->moveVecX = $this->getLFloat();
|
||||
$this->moveVecZ = $this->getLFloat();
|
||||
@ -143,8 +143,8 @@ class PlayerAuthInputPacket extends DataPacket/* implements ServerboundPacket*/{
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putLFloat($this->yaw);
|
||||
$this->putLFloat($this->pitch);
|
||||
$this->putLFloat($this->yaw);
|
||||
$this->putVector3($this->position);
|
||||
$this->putLFloat($this->moveVecX);
|
||||
$this->putLFloat($this->moveVecZ);
|
||||
|
@ -30,7 +30,9 @@ use pocketmine\inventory\transaction\action\InventoryAction;
|
||||
use pocketmine\inventory\transaction\action\SlotChangeAction;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
|
||||
use pocketmine\Player;
|
||||
use function array_key_exists;
|
||||
|
||||
class NetworkInventoryAction{
|
||||
public const SOURCE_CONTAINER = 0;
|
||||
@ -162,21 +164,21 @@ class NetworkInventoryAction{
|
||||
switch($this->sourceType){
|
||||
case self::SOURCE_CONTAINER:
|
||||
if($this->windowId === ContainerIds::UI and $this->inventorySlot > 0){
|
||||
if($this->inventorySlot === 50){
|
||||
if($this->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT){
|
||||
return null; //useless noise
|
||||
}
|
||||
if($this->inventorySlot >= 28 and $this->inventorySlot <= 31){
|
||||
if(array_key_exists($this->inventorySlot, UIInventorySlotOffset::CRAFTING2X2_INPUT)){
|
||||
$window = $player->getCraftingGrid();
|
||||
if($window->getGridWidth() !== CraftingGrid::SIZE_SMALL){
|
||||
throw new \UnexpectedValueException("Expected small crafting grid");
|
||||
}
|
||||
$slot = $this->inventorySlot - 28;
|
||||
}elseif($this->inventorySlot >= 32 and $this->inventorySlot <= 40){
|
||||
$slot = UIInventorySlotOffset::CRAFTING2X2_INPUT[$this->inventorySlot];
|
||||
}elseif(array_key_exists($this->inventorySlot, UIInventorySlotOffset::CRAFTING3X3_INPUT)){
|
||||
$window = $player->getCraftingGrid();
|
||||
if($window->getGridWidth() !== CraftingGrid::SIZE_BIG){
|
||||
throw new \UnexpectedValueException("Expected big crafting grid");
|
||||
}
|
||||
$slot = $this->inventorySlot - 32;
|
||||
$slot = UIInventorySlotOffset::CRAFTING3X3_INPUT[$this->inventorySlot];
|
||||
}else{
|
||||
throw new \UnexpectedValueException("Unhandled magic UI slot offset $this->inventorySlot");
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ class SkinData{
|
||||
* @param PersonaSkinPiece[] $personaPieces
|
||||
* @param PersonaPieceTintColor[] $pieceTintColors
|
||||
*/
|
||||
public function __construct(string $skinId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = "", ?string $fullSkinId = null, string $armSize = self::ARM_SIZE_WIDE, string $skinColor = "", array $personaPieces = [], array $pieceTintColors = [], bool $isVerified = false){
|
||||
public function __construct(string $skinId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = "", ?string $fullSkinId = null, string $armSize = self::ARM_SIZE_WIDE, string $skinColor = "", array $personaPieces = [], array $pieceTintColors = [], bool $isVerified = true){
|
||||
$this->skinId = $skinId;
|
||||
$this->resourcePatch = $resourcePatch;
|
||||
$this->skinImage = $skinImage;
|
||||
|
@ -0,0 +1,105 @@
|
||||
<?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\network\mcpe\protocol\types\inventory;
|
||||
|
||||
final class UIInventorySlotOffset{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public const CURSOR = 0;
|
||||
public const ANVIL = [
|
||||
1 => 0,
|
||||
2 => 1,
|
||||
];
|
||||
public const STONE_CUTTER_INPUT = 3;
|
||||
public const TRADE2_INGREDIENT = [
|
||||
4 => 0,
|
||||
5 => 1,
|
||||
];
|
||||
public const TRADE_INGREDIENT = [
|
||||
6 => 0,
|
||||
7 => 1,
|
||||
];
|
||||
public const MATERIAL_REDUCER_INPUT = 8;
|
||||
public const LOOM = [
|
||||
9 => 0,
|
||||
10 => 1,
|
||||
11 => 2,
|
||||
];
|
||||
public const CARTOGRAPHY_TABLE = [
|
||||
12 => 0,
|
||||
13 => 1,
|
||||
];
|
||||
public const ENCHANTING_TABLE = [
|
||||
14 => 0,
|
||||
15 => 1,
|
||||
];
|
||||
public const GRINDSTONE = [
|
||||
16 => 0,
|
||||
17 => 1,
|
||||
];
|
||||
public const COMPOUND_CREATOR_INPUT = [
|
||||
18 => 0,
|
||||
19 => 1,
|
||||
20 => 2,
|
||||
21 => 3,
|
||||
22 => 4,
|
||||
23 => 5,
|
||||
24 => 6,
|
||||
25 => 7,
|
||||
26 => 8,
|
||||
];
|
||||
public const BEACON_PAYMENT = 27;
|
||||
public const CRAFTING2X2_INPUT = [
|
||||
28 => 0,
|
||||
29 => 1,
|
||||
30 => 2,
|
||||
31 => 3,
|
||||
];
|
||||
public const CRAFTING3X3_INPUT = [
|
||||
32 => 0,
|
||||
33 => 1,
|
||||
34 => 2,
|
||||
35 => 3,
|
||||
36 => 4,
|
||||
37 => 5,
|
||||
38 => 6,
|
||||
39 => 7,
|
||||
40 => 8,
|
||||
];
|
||||
public const MATERIAL_REDUCER_OUTPUT = [
|
||||
41 => 0,
|
||||
42 => 1,
|
||||
43 => 2,
|
||||
44 => 3,
|
||||
45 => 4,
|
||||
46 => 5,
|
||||
47 => 6,
|
||||
48 => 7,
|
||||
49 => 8,
|
||||
];
|
||||
public const CREATED_ITEM_OUTPUT = 50;
|
||||
}
|
Submodule src/pocketmine/resources/vanilla updated: 43edcfde6b...767676e2b9
@ -134,7 +134,7 @@ class SendUsageTask extends AsyncTask{
|
||||
$data["players"] = [
|
||||
"count" => count($players),
|
||||
"limit" => $server->getMaxPlayers(),
|
||||
"currentList" => $players,
|
||||
"currentList" => array_values($players),
|
||||
"historyList" => array_values($playerList)
|
||||
];
|
||||
|
||||
|
@ -55,6 +55,9 @@ class TaskHandler{
|
||||
private $ownerName;
|
||||
|
||||
public function __construct(Task $task, int $taskId, int $delay = -1, int $period = -1, ?string $ownerName = null){
|
||||
if($task->getHandler() !== null){
|
||||
throw new \InvalidArgumentException("Cannot assign multiple handlers to the same task");
|
||||
}
|
||||
$this->task = $task;
|
||||
$this->taskId = $taskId;
|
||||
$this->delay = $delay;
|
||||
|
@ -149,7 +149,7 @@ abstract class Timings{
|
||||
}
|
||||
|
||||
public static function getScheduledTaskTimings(TaskHandler $task, int $period) : TimingsHandler{
|
||||
$name = "Task: " . ($task->getOwnerName() ?? "Unknown") . " Runnable: " . $task->getTaskName();
|
||||
$name = "Task: " . $task->getOwnerName() . " Runnable: " . $task->getTaskName();
|
||||
|
||||
if($period > 0){
|
||||
$name .= "(interval:" . $period . ")";
|
||||
|
@ -201,12 +201,12 @@ class MainLogger extends \AttachableThreadedLogger{
|
||||
$this->synchronized(function() use ($e, $trace) : void{
|
||||
$this->critical(self::printExceptionMessage($e));
|
||||
foreach(Utils::printableTrace($trace) as $line){
|
||||
$this->debug($line, true);
|
||||
$this->critical($line);
|
||||
}
|
||||
for($prev = $e->getPrevious(); $prev !== null; $prev = $prev->getPrevious()){
|
||||
$this->debug("Previous: " . self::printExceptionMessage($prev), true);
|
||||
$this->critical("Previous: " . self::printExceptionMessage($prev));
|
||||
foreach(Utils::printableTrace($prev->getTrace()) as $line){
|
||||
$this->debug(" " . $line, true);
|
||||
$this->critical(" " . $line);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -685,6 +685,21 @@ class Utils{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-template TMemberType
|
||||
* @phpstan-param array<mixed, TMemberType> $array
|
||||
* @phpstan-param \Closure(TMemberType) : void $validator
|
||||
*/
|
||||
public static function validateArrayValueType(array $array, \Closure $validator) : void{
|
||||
foreach($array as $k => $v){
|
||||
try{
|
||||
$validator($v);
|
||||
}catch(\TypeError $e){
|
||||
throw new \TypeError("Incorrect type of element at \"$k\": " . $e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function recursiveUnlink(string $dir) : void{
|
||||
if(is_dir($dir)){
|
||||
$objects = scandir($dir, SCANDIR_SORT_NONE);
|
||||
|
@ -52,7 +52,7 @@ class VersionString{
|
||||
$this->development = $isDevBuild;
|
||||
$this->build = $buildNumber;
|
||||
|
||||
preg_match('/(\d+)\.(\d+)\.(\d+)(?:-(.*))?$/', $this->baseVersion, $matches);
|
||||
preg_match('/^(\d+)\.(\d+)\.(\d+)(?:-(.*))?$/', $this->baseVersion, $matches);
|
||||
if(count($matches) < 4){
|
||||
throw new \InvalidArgumentException("Invalid base version \"$baseVersion\", should contain at least 3 version digits");
|
||||
}
|
||||
|
@ -205,11 +205,6 @@ parameters:
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/event/EventPriority.php
|
||||
|
||||
-
|
||||
message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/inventory/CraftingManager.php
|
||||
|
||||
-
|
||||
message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#"
|
||||
count: 1
|
||||
|
@ -35,6 +35,11 @@ parameters:
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/utils/Utils.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$ of closure expects TMemberType, TMemberType given\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/pocketmine/utils/Utils.php
|
||||
|
||||
-
|
||||
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertNotNull\\(\\) with int and string will always evaluate to true\\.$#"
|
||||
count: 1
|
||||
|
@ -38,7 +38,7 @@ class CheckTestCompletionTask extends Task{
|
||||
$test = $this->plugin->getCurrentTest();
|
||||
if($test === null){
|
||||
if(!$this->plugin->startNextTest()){
|
||||
$this->plugin->getScheduler()->cancelTask($this->getHandler()->getTaskId());
|
||||
$this->getHandler()->cancel();
|
||||
$this->plugin->onAllTestsCompleted();
|
||||
}
|
||||
}elseif($test->isFinished() or $test->isTimedOut()){
|
||||
|
@ -17,7 +17,7 @@ PLUGINS_DIR="$DATA_DIR/plugins"
|
||||
rm -rf "$DATA_DIR"
|
||||
rm PocketMine-MP.phar 2> /dev/null
|
||||
|
||||
cd tests/plugins/PocketMine-DevTools
|
||||
cd tests/plugins/DevTools
|
||||
php -dphar.readonly=0 ./src/DevTools/ConsoleScript.php --make ./ --relative ./ --out ../../../DevTools.phar
|
||||
cd ../../..
|
||||
|
||||
|
Reference in New Issue
Block a user