mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 11:16:57 +00:00
Compare commits
102 Commits
Author | SHA1 | Date | |
---|---|---|---|
af90e18b18 | |||
ab5b4d112b | |||
a30b1fb6d5 | |||
20b4723728 | |||
d1ced0ffc6 | |||
2164dbae67 | |||
6c92a2e88b | |||
97deadc59f | |||
0c3b136a8d | |||
79b7e08e60 | |||
2540dacdd7 | |||
f1078e3909 | |||
2f43b054de | |||
23b5d64535 | |||
9afa0e5483 | |||
4eaea54b0e | |||
6b51bf4a80 | |||
cba8d86c4f | |||
2e834c8f5c | |||
f9873e9108 | |||
074baf7e1c | |||
2e0dd574e0 | |||
e16d8e31af | |||
3c93a57397 | |||
e2e927b328 | |||
a8dab25201 | |||
3de2b7969e | |||
8f486ea65d | |||
6b971b1761 | |||
6f36fa504b | |||
8e73842a93 | |||
e71e18fc88 | |||
e1bacb5c6d | |||
44697e784a | |||
65529ff2ce | |||
c346c45d42 | |||
c433fad0a7 | |||
8fad5a6e30 | |||
7a6f279825 | |||
10b72c895d | |||
d520928888 | |||
27767e7ddb | |||
243c12de7c | |||
372545e47e | |||
8913b48700 | |||
6ee4a0e090 | |||
8bd8da4bc6 | |||
9ba4144a71 | |||
9da7c6af27 | |||
109312284c | |||
51934614bc | |||
9e89f65094 | |||
9562711b84 | |||
30b49e0d22 | |||
a975868fc3 | |||
b38b932845 | |||
43cb19ebca | |||
769cc91543 | |||
278f37d3e0 | |||
02a6ca84a9 | |||
b8703d5dff | |||
37c2d78731 | |||
b7663e5815 | |||
1d0ffa06f8 | |||
768cfe3953 | |||
2822465f33 | |||
5da48f429f | |||
dbd0d04549 | |||
0f92ec6d2a | |||
791b4d8ef3 | |||
0b7ff6f2e7 | |||
af092b01e1 | |||
d811217755 | |||
d7f86f0240 | |||
5fe1d2e396 | |||
ddbb5363ef | |||
d3704bfae4 | |||
07f034d2da | |||
331ae5498f | |||
eebd90ec42 | |||
8e47a40b4c | |||
0f9fdf6442 | |||
5364e4de68 | |||
1099e2044b | |||
80d48161d3 | |||
fbe8485696 | |||
a150f39b02 | |||
71d17c50d6 | |||
3a18bdd6a0 | |||
96857c65b6 | |||
9826abd83e | |||
48c8c2a8c3 | |||
c83b7d9b69 | |||
c66dc7b273 | |||
5bf7350ee5 | |||
636cc1c199 | |||
62b6405371 | |||
9ecf23d3ee | |||
187f36fe38 | |||
dc89b48354 | |||
e6d1c1dfbc | |||
5a8812b1dc |
@ -4,3 +4,7 @@ root = yes
|
||||
[*]
|
||||
indent_size = 4
|
||||
indent_style = tab
|
||||
|
||||
[*.yml]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
@ -27,7 +27,7 @@
|
||||
"pocketmine/raklib": "^0.12.0",
|
||||
"pocketmine/spl": "^0.3.0",
|
||||
"pocketmine/binaryutils": "^0.1.0",
|
||||
"pocketmine/nbt": "^0.2.1",
|
||||
"pocketmine/nbt": "^0.2.6",
|
||||
"pocketmine/math": "^0.2.0",
|
||||
"pocketmine/snooze": "^0.1.0",
|
||||
"daverandom/callback-validator": "dev-master",
|
||||
|
26
composer.lock
generated
26
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "d3fb809caf4d5a5c99054f47f28ff271",
|
||||
"content-hash": "2f5313e4ebd7b62c785cf683b27464b4",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -160,16 +160,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/nbt",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/NBT.git",
|
||||
"reference": "0b290fa0f5b44835ebeea8146c9ac960cac833f5"
|
||||
"reference": "92eaf84dd61f700d3ec02ebd01b606cb5b1590d4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/0b290fa0f5b44835ebeea8146c9ac960cac833f5",
|
||||
"reference": "0b290fa0f5b44835ebeea8146c9ac960cac833f5",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/92eaf84dd61f700d3ec02ebd01b606cb5b1590d4",
|
||||
"reference": "92eaf84dd61f700d3ec02ebd01b606cb5b1590d4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -194,23 +194,23 @@
|
||||
],
|
||||
"description": "PHP library for working with Named Binary Tags",
|
||||
"support": {
|
||||
"source": "https://github.com/pmmp/NBT/tree/0.2.5",
|
||||
"source": "https://github.com/pmmp/NBT/tree/0.2.6",
|
||||
"issues": "https://github.com/pmmp/NBT/issues"
|
||||
},
|
||||
"time": "2019-01-07T17:28:16+00:00"
|
||||
"time": "2019-02-07T16:28:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib",
|
||||
"version": "0.12.1",
|
||||
"version": "0.12.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/RakLib.git",
|
||||
"reference": "334b469f2d0f070f17902d7ac584bea7c6149dc6"
|
||||
"reference": "54a36d55eeba0a182e00439920ee2fcfa8c72bf3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/334b469f2d0f070f17902d7ac584bea7c6149dc6",
|
||||
"reference": "334b469f2d0f070f17902d7ac584bea7c6149dc6",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/54a36d55eeba0a182e00439920ee2fcfa8c72bf3",
|
||||
"reference": "54a36d55eeba0a182e00439920ee2fcfa8c72bf3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -235,10 +235,10 @@
|
||||
],
|
||||
"description": "A RakNet server implementation written in PHP",
|
||||
"support": {
|
||||
"source": "https://github.com/pmmp/RakLib/tree/0.12.1",
|
||||
"source": "https://github.com/pmmp/RakLib/tree/0.12",
|
||||
"issues": "https://github.com/pmmp/RakLib/issues"
|
||||
},
|
||||
"time": "2019-01-04T14:23:37+00:00"
|
||||
"time": "2019-01-21T14:17:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/snooze",
|
||||
|
19
doxygen.conf
19
doxygen.conf
@ -51,7 +51,7 @@ PROJECT_BRIEF =
|
||||
# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
|
||||
# to the output directory.
|
||||
|
||||
PROJECT_LOGO = "/home/jenkins/PocketMine-h-64.png"
|
||||
PROJECT_LOGO =
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
|
||||
# into which the generated documentation will be written. If a relative path is
|
||||
@ -240,7 +240,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
# qualified scopes will look different, etc.
|
||||
# The default value is: NO.
|
||||
|
||||
OPTIMIZE_OUTPUT_JAVA = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
|
||||
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
|
||||
# sources. Doxygen will then generate output that is tailored for Fortran.
|
||||
@ -737,7 +737,9 @@ WARN_LOGFILE =
|
||||
# spaces.
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = ./
|
||||
INPUT = ./src \
|
||||
./vendor/pocketmine \
|
||||
./README.md
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
@ -757,9 +759,7 @@ INPUT_ENCODING = UTF-8
|
||||
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
|
||||
# *.qsf, *.as and *.js.
|
||||
|
||||
FILE_PATTERNS = *.php \
|
||||
*.sh \
|
||||
*.md
|
||||
FILE_PATTERNS = *.php
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
@ -793,7 +793,10 @@ EXCLUDE_SYMLINKS = YES
|
||||
EXCLUDE_PATTERNS = */bin/* \
|
||||
*/players/* \
|
||||
*/worlds/* \
|
||||
*/plugins/*
|
||||
*/plugins/* \
|
||||
*/plugin_data/* \
|
||||
*/tests/* \
|
||||
*/stubs/*
|
||||
|
||||
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
|
||||
# (namespaces, classes, functions, etc.) that should be excluded from the
|
||||
@ -878,7 +881,7 @@ FILTER_SOURCE_PATTERNS =
|
||||
# (index.html). This can be useful if you have a project on for instance GitHub
|
||||
# and want to reuse the introduction page also for the doxygen output.
|
||||
|
||||
USE_MDFILE_AS_MAINPAGE = README.md
|
||||
USE_MDFILE_AS_MAINPAGE = ./README.md
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to source browsing
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine;
|
||||
use pocketmine\block\Bed;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\block\UnknownBlock;
|
||||
use pocketmine\command\Command;
|
||||
use pocketmine\command\CommandSender;
|
||||
use pocketmine\entity\Effect;
|
||||
@ -185,6 +186,7 @@ use function min;
|
||||
use function preg_match;
|
||||
use function round;
|
||||
use function spl_object_hash;
|
||||
use function sqrt;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
@ -475,8 +477,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
public function setFlying(bool $value){
|
||||
$this->flying = $value;
|
||||
$this->sendSettings();
|
||||
if($this->flying !== $value){
|
||||
$this->flying = $value;
|
||||
$this->resetFallDistance();
|
||||
$this->sendSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public function isFlying() : bool{
|
||||
@ -688,14 +693,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$this->perm->recalculatePermissions();
|
||||
|
||||
if($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)){
|
||||
$permManager->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this);
|
||||
}
|
||||
if($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)){
|
||||
$permManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);
|
||||
}
|
||||
|
||||
if($this->spawned){
|
||||
if($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)){
|
||||
$permManager->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this);
|
||||
}
|
||||
if($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)){
|
||||
$permManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);
|
||||
}
|
||||
|
||||
$this->sendCommandData();
|
||||
}
|
||||
}
|
||||
@ -715,7 +720,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
$data = new CommandData();
|
||||
$data->commandName = $command->getName();
|
||||
//TODO: commands containing uppercase letters in the name crash 1.9.0 client
|
||||
$data->commandName = strtolower($command->getName());
|
||||
$data->commandDescription = $this->server->getLanguage()->translateString($command->getDescription());
|
||||
$data->flags = 0;
|
||||
$data->permission = 0;
|
||||
@ -1409,19 +1415,17 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$this->allowFlight = $this->isCreative();
|
||||
if($this->isSpectator()){
|
||||
$this->flying = true;
|
||||
$this->setFlying(true);
|
||||
$this->keepMovement = true;
|
||||
$this->despawnFromAll();
|
||||
}else{
|
||||
$this->keepMovement = $this->allowMovementCheats;
|
||||
if($this->isSurvival()){
|
||||
$this->flying = false;
|
||||
$this->setFlying(false);
|
||||
}
|
||||
$this->spawnToAll();
|
||||
}
|
||||
|
||||
$this->resetFallDistance();
|
||||
|
||||
$this->namedtag->setInt("playerGameType", $this->gamemode);
|
||||
if(!$client){ //Gamemode changed by server, do not send for client changes
|
||||
$this->sendGamemode();
|
||||
@ -1647,7 +1651,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}else{
|
||||
$this->broadcastMovement();
|
||||
|
||||
$distance = $from->distance($to);
|
||||
$distance = sqrt((($from->x - $to->x) ** 2) + (($from->z - $to->z) ** 2));
|
||||
//TODO: check swimming (adds 0.015 exhaustion in MCPE)
|
||||
if($this->isSprinting()){
|
||||
$this->exhaust(0.1 * $distance, PlayerExhaustEvent::CAUSE_SPRINTING);
|
||||
@ -1678,6 +1682,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$this->newPosition = null;
|
||||
}
|
||||
|
||||
public function fall(float $fallDistance) : void{
|
||||
if(!$this->flying){
|
||||
parent::fall($fallDistance);
|
||||
}
|
||||
}
|
||||
|
||||
public function jump() : void{
|
||||
(new PlayerJumpEvent($this))->call();
|
||||
parent::jump();
|
||||
@ -2714,6 +2724,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
public function handleBlockPickRequest(BlockPickRequestPacket $packet) : bool{
|
||||
$block = $this->level->getBlockAt($packet->blockX, $packet->blockY, $packet->blockZ);
|
||||
if($block instanceof UnknownBlock){
|
||||
return true;
|
||||
}
|
||||
|
||||
$item = $block->getPickedItem();
|
||||
if($packet->addUserData){
|
||||
@ -2938,8 +2951,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
$this->sendSettings();
|
||||
}else{
|
||||
}else{ //don't use setFlying() here, to avoid feedback loops
|
||||
$this->flying = $ev->isFlying();
|
||||
$this->resetFallDistance();
|
||||
}
|
||||
|
||||
$handled = true;
|
||||
@ -3613,7 +3627,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
if($this->inventory !== null){
|
||||
$this->inventory->setHeldItemIndex(0, false); //This is already handled when sending contents, don't send it twice
|
||||
$this->inventory->setHeldItemIndex(0);
|
||||
$this->inventory->clearAll();
|
||||
}
|
||||
if($this->armorInventory !== null){
|
||||
@ -3621,6 +3635,10 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: allow this number to be manipulated during PlayerDeathEvent
|
||||
$this->level->dropExperience($this, $this->getXpDropAmount());
|
||||
$this->setXpAndProgress(0, 0);
|
||||
|
||||
if($ev->getDeathMessage() != ""){
|
||||
$this->server->broadcast($ev->getDeathMessage(), Server::BROADCAST_CHANNEL_USERS);
|
||||
}
|
||||
@ -3890,8 +3908,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
throw new \InvalidArgumentException("Cannot remove fixed window $id (" . get_class($inventory) . ") from " . $this->getName());
|
||||
}
|
||||
|
||||
$inventory->close($this);
|
||||
if($id !== null){
|
||||
$inventory->close($this);
|
||||
unset($this->windows[$hash], $this->windowIndex[$id], $this->permanentWindows[$id]);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ namespace pocketmine {
|
||||
use pocketmine\wizard\SetupWizard;
|
||||
|
||||
const NAME = "PocketMine-MP";
|
||||
const BASE_VERSION = "3.5.7";
|
||||
const BASE_VERSION = "3.6.4";
|
||||
const IS_DEVELOPMENT_BUILD = false;
|
||||
const BUILD_NUMBER = 0;
|
||||
|
||||
@ -177,7 +177,6 @@ namespace pocketmine {
|
||||
ini_set("default_charset", "utf-8");
|
||||
|
||||
ini_set("memory_limit", '-1');
|
||||
define('pocketmine\START_TIME', microtime(true));
|
||||
|
||||
define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'src' . DIRECTORY_SEPARATOR . 'pocketmine' . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR);
|
||||
|
||||
@ -245,6 +244,8 @@ namespace pocketmine {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: move this to a Server field
|
||||
define('pocketmine\START_TIME', microtime(true));
|
||||
ThreadManager::init();
|
||||
new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
|
||||
|
||||
|
@ -124,7 +124,6 @@ use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function floor;
|
||||
use function function_exists;
|
||||
use function gc_collect_cycles;
|
||||
use function get_class;
|
||||
use function getmypid;
|
||||
use function getopt;
|
||||
@ -2148,9 +2147,6 @@ class Server{
|
||||
$this->network->unregisterInterface($interface);
|
||||
}
|
||||
}
|
||||
|
||||
$this->getLogger()->debug("Collecting cycles");
|
||||
gc_collect_cycles();
|
||||
}catch(\Throwable $e){
|
||||
$this->logger->logException($e);
|
||||
$this->logger->emergency("Crashed while crashing, killing process");
|
||||
|
@ -28,7 +28,7 @@ namespace pocketmine;
|
||||
*/
|
||||
abstract class Thread extends \Thread{
|
||||
|
||||
/** @var \ClassLoader */
|
||||
/** @var \ClassLoader|null */
|
||||
protected $classLoader;
|
||||
/** @var string|null */
|
||||
protected $composerAutoloaderPath;
|
||||
|
@ -28,7 +28,7 @@ namespace pocketmine;
|
||||
*/
|
||||
abstract class Worker extends \Worker{
|
||||
|
||||
/** @var \ClassLoader */
|
||||
/** @var \ClassLoader|null */
|
||||
protected $classLoader;
|
||||
/** @var string|null */
|
||||
protected $composerAutoloaderPath;
|
||||
|
@ -39,6 +39,7 @@ use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use function array_merge;
|
||||
use function get_class;
|
||||
use const PHP_INT_MAX;
|
||||
|
||||
class Block extends Position implements BlockIds, Metadatable{
|
||||
@ -268,6 +269,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
* @param Item $item
|
||||
*
|
||||
* @return float
|
||||
* @throws \InvalidArgumentException if the item efficiency is not a positive number
|
||||
*/
|
||||
public function getBreakTime(Item $item) : float{
|
||||
$base = $this->getHardness();
|
||||
@ -279,7 +281,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
|
||||
$efficiency = $item->getMiningEfficiency($this);
|
||||
if($efficiency <= 0){
|
||||
throw new \RuntimeException("Item efficiency is invalid");
|
||||
throw new \InvalidArgumentException(get_class($item) . " has invalid mining efficiency: expected >= 0, got $efficiency");
|
||||
}
|
||||
|
||||
$base /= $efficiency;
|
||||
|
@ -171,7 +171,7 @@ class BlockFactory{
|
||||
self::registerBlock(new Cake());
|
||||
//TODO: REPEATER_BLOCK
|
||||
//TODO: POWERED_REPEATER
|
||||
//TODO: INVISIBLEBEDROCK
|
||||
self::registerBlock(new InvisibleBedrock());
|
||||
self::registerBlock(new Trapdoor());
|
||||
//TODO: MONSTER_EGG
|
||||
self::registerBlock(new StoneBricks());
|
||||
@ -319,13 +319,13 @@ class BlockFactory{
|
||||
self::registerBlock(new Stonecutter());
|
||||
self::registerBlock(new GlowingObsidian());
|
||||
self::registerBlock(new NetherReactor());
|
||||
//TODO: INFO_UPDATE
|
||||
//TODO: INFO_UPDATE2
|
||||
self::registerBlock(new InfoUpdate(Block::INFO_UPDATE, 0, "update!"));
|
||||
self::registerBlock(new InfoUpdate(Block::INFO_UPDATE2, 0, "ate!upd"));
|
||||
//TODO: MOVINGBLOCK
|
||||
//TODO: OBSERVER
|
||||
//TODO: STRUCTURE_BLOCK
|
||||
|
||||
//TODO: RESERVED6
|
||||
self::registerBlock(new Reserved6(Block::RESERVED6, 0, "reserved6"));
|
||||
|
||||
for($id = 0, $size = self::$fullList->getSize() >> 4; $id < $size; ++$id){
|
||||
if(self::$fullList[$id << 4] === null){
|
||||
@ -430,8 +430,13 @@ class BlockFactory{
|
||||
public static function registerStaticRuntimeIdMappings() : void{
|
||||
/** @var mixed[] $runtimeIdMap */
|
||||
$runtimeIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true);
|
||||
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "legacy_id_map.json"), true);
|
||||
foreach($runtimeIdMap as $k => $obj){
|
||||
self::registerMapping($k, $obj["id"], $obj["data"]);
|
||||
//this has to use the json offset to make sure the mapping is consistent with what we send over network, even though we aren't using all the entries
|
||||
if(!isset($legacyIdMap[$obj["name"]])){
|
||||
continue;
|
||||
}
|
||||
self::registerMapping($k, $legacyIdMap[$obj["name"]], $obj["data"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,9 +96,12 @@ class Cactus extends Transparent{
|
||||
if($b->getId() === self::AIR){
|
||||
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||
if($ev->isCancelled()){
|
||||
break;
|
||||
}
|
||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->meta = 0;
|
||||
|
@ -30,6 +30,18 @@ use pocketmine\math\Vector3;
|
||||
class CobblestoneWall extends Transparent{
|
||||
public const NONE_MOSSY_WALL = 0;
|
||||
public const MOSSY_WALL = 1;
|
||||
public const GRANITE_WALL = 2;
|
||||
public const DIORITE_WALL = 3;
|
||||
public const ANDESITE_WALL = 4;
|
||||
public const SANDSTONE_WALL = 5;
|
||||
public const BRICK_WALL = 6;
|
||||
public const STONE_BRICK_WALL = 7;
|
||||
public const MOSSY_STONE_BRICK_WALL = 8;
|
||||
public const NETHER_BRICK_WALL = 9;
|
||||
public const END_STONE_BRICK_WALL = 10;
|
||||
public const PRISMARINE_WALL = 11;
|
||||
public const RED_SANDSTONE_WALL = 12;
|
||||
public const RED_NETHER_BRICK_WALL = 13;
|
||||
|
||||
protected $id = self::COBBLESTONE_WALL;
|
||||
|
||||
@ -50,11 +62,23 @@ class CobblestoneWall extends Transparent{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
if($this->meta === 0x01){
|
||||
return "Mossy Cobblestone Wall";
|
||||
}
|
||||
|
||||
return "Cobblestone Wall";
|
||||
static $names = [
|
||||
self::NONE_MOSSY_WALL => "Cobblestone",
|
||||
self::MOSSY_WALL => "Mossy Cobblestone",
|
||||
self::GRANITE_WALL => "Granite",
|
||||
self::DIORITE_WALL => "Diorite",
|
||||
self::ANDESITE_WALL => "Andesite",
|
||||
self::SANDSTONE_WALL => "Sandstone",
|
||||
self::BRICK_WALL => "Brick",
|
||||
self::STONE_BRICK_WALL => "Stone Brick",
|
||||
self::MOSSY_STONE_BRICK_WALL => "Mossy Stone Brick",
|
||||
self::NETHER_BRICK_WALL => "Nether Brick",
|
||||
self::END_STONE_BRICK_WALL => "End Stone Brick",
|
||||
self::PRISMARINE_WALL => "Prismarine",
|
||||
self::RED_SANDSTONE_WALL => "Red Sandstone",
|
||||
self::RED_NETHER_BRICK_WALL => "Red Nether Brick"
|
||||
];
|
||||
return ($names[$this->getVariant()] ?? "Unknown") . " Wall";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
@ -43,7 +43,7 @@ abstract class Crops extends Flowable{
|
||||
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
if($this->meta < 7 and $item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
$block = clone $this;
|
||||
$block->meta += mt_rand(2, 5);
|
||||
if($block->meta > 7){
|
||||
|
31
src/pocketmine/block/InfoUpdate.php
Normal file
31
src/pocketmine/block/InfoUpdate.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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;
|
||||
|
||||
class InfoUpdate extends Solid{
|
||||
|
||||
public function getHardness() : float{
|
||||
return 1;
|
||||
}
|
||||
}
|
51
src/pocketmine/block/InvisibleBedrock.php
Normal file
51
src/pocketmine/block/InvisibleBedrock.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?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\item\Item;
|
||||
|
||||
class InvisibleBedrock extends Transparent{
|
||||
|
||||
protected $id = self::INVISIBLE_BEDROCK;
|
||||
|
||||
public function __construct(){
|
||||
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Invisible Bedrock";
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function getBlastResistance() : float{
|
||||
return 18000000;
|
||||
}
|
||||
|
||||
public function isBreakable(Item $item) : bool{
|
||||
return false;
|
||||
}
|
||||
}
|
@ -65,7 +65,7 @@ class ItemFrame extends Flowable{
|
||||
2 => Vector3::SIDE_NORTH,
|
||||
3 => Vector3::SIDE_SOUTH
|
||||
];
|
||||
if(!$this->getSide($sides[$this->meta])->isSolid()){
|
||||
if(isset($sides[$this->meta]) and !$this->getSide($sides[$this->meta])->isSolid()){
|
||||
$this->level->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
@ -112,4 +112,8 @@ class ItemFrame extends Flowable{
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 0.25;
|
||||
}
|
||||
}
|
||||
|
@ -58,8 +58,10 @@ class Ladder extends Transparent{
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$entity->resetFallDistance();
|
||||
$entity->onGround = true;
|
||||
if($entity->asVector3()->floor()->distanceSquared($this) < 1){ //entity coordinates must be inside block
|
||||
$entity->resetFallDistance();
|
||||
$entity->onGround = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class PackedIce extends Solid{
|
||||
|
||||
protected $id = self::PACKED_ICE;
|
||||
@ -46,4 +48,8 @@ class PackedIce extends Solid{
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
31
src/pocketmine/block/Reserved6.php
Normal file
31
src/pocketmine/block/Reserved6.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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;
|
||||
|
||||
class Reserved6 extends Solid{
|
||||
|
||||
public function getHardness() : float{
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -89,7 +89,7 @@ abstract class Stair extends Transparent{
|
||||
2 => 1,
|
||||
3 => 3
|
||||
];
|
||||
$this->meta = $faces[$player->getDirection()] & 0x03;
|
||||
$this->meta = $player !== null ? $faces[$player->getDirection()] & 0x03 : 0;
|
||||
if(($clickVector->y > 0.5 and $face !== Vector3::SIDE_UP) or $face === Vector3::SIDE_DOWN){
|
||||
$this->meta |= 0x04; //Upside-down stairs
|
||||
}
|
||||
|
@ -26,6 +26,12 @@ namespace pocketmine\block;
|
||||
class StoneSlab2 extends StoneSlab{
|
||||
public const TYPE_RED_SANDSTONE = 0;
|
||||
public const TYPE_PURPUR = 1;
|
||||
public const TYPE_PRISMARINE = 2;
|
||||
public const TYPE_DARK_PRISMARINE = 3;
|
||||
public const TYPE_PRISMARINE_BRICKS = 4;
|
||||
public const TYPE_MOSSY_COBBLESTONE = 5;
|
||||
public const TYPE_SMOOTH_SANDSTONE = 6;
|
||||
public const TYPE_RED_NETHER_BRICK = 7;
|
||||
|
||||
protected $id = self::STONE_SLAB2;
|
||||
|
||||
@ -36,7 +42,13 @@ class StoneSlab2 extends StoneSlab{
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
self::TYPE_RED_SANDSTONE => "Red Sandstone",
|
||||
self::TYPE_PURPUR => "Purpur"
|
||||
self::TYPE_PURPUR => "Purpur",
|
||||
self::TYPE_PRISMARINE => "Prismarine",
|
||||
self::TYPE_DARK_PRISMARINE => "Dark Prismarine",
|
||||
self::TYPE_PRISMARINE_BRICKS => "Prismarine Bricks",
|
||||
self::TYPE_MOSSY_COBBLESTONE => "Mossy Cobblestone",
|
||||
self::TYPE_SMOOTH_SANDSTONE => "Smooth Sandstone",
|
||||
self::TYPE_RED_NETHER_BRICK => "Red Nether Brick"
|
||||
];
|
||||
|
||||
return (($this->meta & 0x08) > 0 ? "Upper " : "") . ($names[$this->getVariant()] ?? "") . " Slab";
|
||||
|
@ -50,9 +50,11 @@ class Sugarcane extends Flowable{
|
||||
if($b->getId() === self::AIR){
|
||||
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||
if($ev->isCancelled()){
|
||||
break;
|
||||
}
|
||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\projectile\Arrow;
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\enchantment\Enchantment;
|
||||
use pocketmine\item\FlintSteel;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -51,8 +53,10 @@ class TNT extends Solid{
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($item instanceof FlintSteel){
|
||||
$item->applyDamage(1);
|
||||
if($item instanceof FlintSteel or $item->hasEnchantment(Enchantment::FIRE_ASPECT)){
|
||||
if($item instanceof Durable){
|
||||
$item->applyDamage(1);
|
||||
}
|
||||
$this->ignite();
|
||||
return true;
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ class TallGrass extends Flowable{
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === self::GRASS){
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN)->getId();
|
||||
if($down === self::GRASS or $down === self::DIRT){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
|
||||
return true;
|
||||
|
@ -26,6 +26,7 @@ declare(strict_types=1);
|
||||
*/
|
||||
namespace pocketmine\command;
|
||||
|
||||
use pocketmine\command\utils\CommandException;
|
||||
use pocketmine\lang\TextContainer;
|
||||
use pocketmine\lang\TranslationContainer;
|
||||
use pocketmine\permission\PermissionManager;
|
||||
@ -92,6 +93,7 @@ abstract class Command{
|
||||
* @param string[] $args
|
||||
*
|
||||
* @return mixed
|
||||
* @throws CommandException
|
||||
*/
|
||||
abstract public function execute(CommandSender $sender, string $commandLabel, array $args);
|
||||
|
||||
|
@ -66,13 +66,13 @@ use pocketmine\command\defaults\VersionCommand;
|
||||
use pocketmine\command\defaults\WhitelistCommand;
|
||||
use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\Server;
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function min;
|
||||
use function str_getcsv;
|
||||
use function preg_match_all;
|
||||
use function stripslashes;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
@ -247,7 +247,16 @@ class SimpleCommandMap implements CommandMap{
|
||||
}
|
||||
|
||||
public function dispatch(CommandSender $sender, string $commandLine) : bool{
|
||||
$args = array_map("\stripslashes", str_getcsv($commandLine, " "));
|
||||
$args = [];
|
||||
preg_match_all('/"((?:\\\\.|[^\\\\"])*)"|(\S+)/u', $commandLine, $matches);
|
||||
foreach($matches[0] as $k => $_){
|
||||
for($i = 1; $i <= 2; ++$i){
|
||||
if($matches[$i][$k] !== ""){
|
||||
$args[$k] = stripslashes($matches[$i][$k]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$sentCommandLabel = "";
|
||||
$target = $this->matchCommand($sentCommandLabel, $args);
|
||||
|
||||
|
@ -53,6 +53,9 @@ class DeopCommand extends VanillaCommand{
|
||||
}
|
||||
|
||||
$name = array_shift($args);
|
||||
if(!Player::isValidUserName($name)){
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $sender->getServer()->getOfflinePlayer($name);
|
||||
$player->setOp(false);
|
||||
|
@ -83,7 +83,7 @@ class EffectCommand extends VanillaCommand{
|
||||
$amplification = 0;
|
||||
|
||||
if(count($args) >= 3){
|
||||
if(($d = $this->getBoundedInt($sender, $args[2], 0, INT32_MAX)) === null){
|
||||
if(($d = $this->getBoundedInt($sender, $args[2], 0, (int) (INT32_MAX / 20))) === null){
|
||||
return false;
|
||||
}
|
||||
$duration = $d * 20; //ticks
|
||||
|
@ -53,6 +53,9 @@ class OpCommand extends VanillaCommand{
|
||||
}
|
||||
|
||||
$name = array_shift($args);
|
||||
if(!Player::isValidUserName($name)){
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $sender->getServer()->getOfflinePlayer($name);
|
||||
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.op.success", [$player->getName()]));
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\command\Command;
|
||||
use pocketmine\command\CommandSender;
|
||||
use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\lang\TranslationContainer;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function count;
|
||||
use function implode;
|
||||
@ -94,6 +95,9 @@ class WhitelistCommand extends VanillaCommand{
|
||||
if($this->badPerm($sender, strtolower($args[0]))){
|
||||
return false;
|
||||
}
|
||||
if(!Player::isValidUserName($args[1])){
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
switch(strtolower($args[0])){
|
||||
case "add":
|
||||
$sender->getServer()->getOfflinePlayer($args[1])->setWhitelisted(true);
|
||||
|
@ -200,6 +200,11 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
public const DATA_FLAGS2 = 91; //long (extended data flags)
|
||||
/* 92 (float) related to panda lying down
|
||||
* 93 (float) related to panda lying down */
|
||||
public const DATA_AREA_EFFECT_CLOUD_DURATION = 94; //int
|
||||
public const DATA_AREA_EFFECT_CLOUD_SPAWN_TIME = 95; //int
|
||||
public const DATA_AREA_EFFECT_CLOUD_RADIUS_PER_TICK = 96; //float, usually negative
|
||||
public const DATA_AREA_EFFECT_CLOUD_RADIUS_CHANGE_ON_PICKUP = 97; //float
|
||||
public const DATA_AREA_EFFECT_CLOUD_PICKUP_COUNT = 98; //int
|
||||
|
||||
|
||||
public const DATA_FLAG_ONFIRE = 0;
|
||||
@ -1164,6 +1169,9 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
}
|
||||
|
||||
protected function updateMovement(bool $teleport = false) : void{
|
||||
//TODO: hack for client-side AI interference: prevent client sided movement when motion is 0
|
||||
$this->setImmobile($this->motion->x == 0 and $this->motion->y == 0 and $this->motion->z == 0);
|
||||
|
||||
$diffPosition = ($this->x - $this->lastX) ** 2 + ($this->y - $this->lastY) ** 2 + ($this->z - $this->lastZ) ** 2;
|
||||
$diffRotation = ($this->yaw - $this->lastYaw) ** 2 + ($this->pitch - $this->lastPitch) ** 2;
|
||||
|
||||
|
@ -301,7 +301,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
$food = $this->getFood();
|
||||
if($food > 0){
|
||||
$food--;
|
||||
$this->setFood($food);
|
||||
$this->setFood(max($food, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -578,7 +578,9 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
}
|
||||
|
||||
public function getXpDropAmount() : int{
|
||||
return (int) min(100, $this->getCurrentTotalXp());
|
||||
//this causes some XP to be lost on death when above level 1 (by design), dropping at most enough points for
|
||||
//about 7.5 levels of XP.
|
||||
return (int) min(100, 7 * $this->getXpLevel());
|
||||
}
|
||||
|
||||
public function getInventory(){
|
||||
|
@ -152,7 +152,7 @@ abstract class Living extends Entity implements Damageable{
|
||||
}
|
||||
|
||||
public function setMaxHealth(int $amount) : void{
|
||||
$this->attributeMap->getAttribute(Attribute::HEALTH)->setMaxValue($amount);
|
||||
$this->attributeMap->getAttribute(Attribute::HEALTH)->setMaxValue($amount)->setDefaultValue($amount);
|
||||
}
|
||||
|
||||
public function getAbsorption() : float{
|
||||
@ -644,6 +644,10 @@ abstract class Living extends Entity implements Damageable{
|
||||
foreach($ev->getDrops() as $item){
|
||||
$this->getLevel()->dropItem($this, $item);
|
||||
}
|
||||
|
||||
//TODO: check death conditions (must have been damaged by player < 5 seconds from death)
|
||||
//TODO: allow this number to be manipulated during EntityDeathEvent
|
||||
$this->level->dropExperience($this, $this->getXpDropAmount());
|
||||
}
|
||||
|
||||
protected function onDeathUpdate(int $tickDiff) : bool{
|
||||
@ -651,9 +655,6 @@ abstract class Living extends Entity implements Damageable{
|
||||
$this->deadTicks += $tickDiff;
|
||||
if($this->deadTicks >= $this->maxDeadTicks){
|
||||
$this->endDeathAnimation();
|
||||
|
||||
//TODO: check death conditions (must have been damaged by player < 5 seconds from death)
|
||||
$this->level->dropExperience($this, $this->getXpDropAmount());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\entity\Human;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
use pocketmine\Player;
|
||||
use function sqrt;
|
||||
|
||||
class ExperienceOrb extends Entity{
|
||||
public const NETWORK_ID = self::XP_ORB;
|
||||
@ -190,15 +191,15 @@ class ExperienceOrb extends Entity{
|
||||
$this->setTargetPlayer($currentTarget);
|
||||
|
||||
if($currentTarget !== null){
|
||||
$vector = $currentTarget->subtract($this)->add(0, $currentTarget->getEyeHeight() / 2, 0)->divide(self::MAX_TARGET_DISTANCE);
|
||||
$vector = $currentTarget->add(0, $currentTarget->getEyeHeight() / 2, 0)->subtract($this)->divide(self::MAX_TARGET_DISTANCE);
|
||||
|
||||
$distance = $vector->length();
|
||||
$oneMinusDistance = (1 - $distance) ** 2;
|
||||
$distance = $vector->lengthSquared();
|
||||
if($distance < 1){
|
||||
$diff = $vector->normalize()->multiply(0.2 * (1 - sqrt($distance)) ** 2);
|
||||
|
||||
if($oneMinusDistance > 0){
|
||||
$this->motion->x += $vector->x / $distance * $oneMinusDistance * 0.2;
|
||||
$this->motion->y += $vector->y / $distance * $oneMinusDistance * 0.2;
|
||||
$this->motion->z += $vector->z / $distance * $oneMinusDistance * 0.2;
|
||||
$this->motion->x += $diff->x;
|
||||
$this->motion->y += $diff->y;
|
||||
$this->motion->z += $diff->z;
|
||||
}
|
||||
|
||||
if($currentTarget->canPickupXp() and $this->boundingBox->intersectsWith($currentTarget->getBoundingBox())){
|
||||
|
@ -123,7 +123,7 @@ class Arrow extends Projectile{
|
||||
|
||||
$hasUpdate = parent::entityBaseTick($tickDiff);
|
||||
|
||||
if($this->isCollided){
|
||||
if($this->blockHit !== null){
|
||||
$this->collideTicks += $tickDiff;
|
||||
if($this->collideTicks > 1200){
|
||||
$this->flagForDespawn();
|
||||
|
@ -85,7 +85,7 @@ class SplashPotion extends Throwable{
|
||||
if(!$this->willLinger()){
|
||||
foreach($this->level->getNearbyEntities($this->boundingBox->expandedCopy(4.125, 2.125, 4.125), $this) as $entity){
|
||||
if($entity instanceof Living and $entity->isAlive()){
|
||||
$distanceSquared = $entity->distanceSquared($this);
|
||||
$distanceSquared = $entity->add(0, $entity->getEyeHeight(), 0)->distanceSquared($this);
|
||||
if($distanceSquared > 16){ //4 blocks
|
||||
continue;
|
||||
}
|
||||
|
@ -253,11 +253,9 @@ abstract class BaseInventory implements Inventory{
|
||||
|
||||
public function canAddItem(Item $item) : bool{
|
||||
$item = clone $item;
|
||||
$checkDamage = !$item->hasAnyDamageValue();
|
||||
$checkTags = $item->hasCompoundTag();
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
|
||||
$slot = $this->getItem($i);
|
||||
if($item->equals($slot, $checkDamage, $checkTags)){
|
||||
if($item->equals($slot)){
|
||||
if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){
|
||||
$item->setCount($item->getCount() - $diff);
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ class Item implements ItemIds, \JsonSerializable{
|
||||
/**
|
||||
* Sets the Item's NBT
|
||||
*
|
||||
* @param CompoundTag|string $tags
|
||||
* @param CompoundTag|string|null $tags
|
||||
*
|
||||
* @return Item
|
||||
*/
|
||||
@ -224,7 +224,7 @@ class Item implements ItemIds, \JsonSerializable{
|
||||
if($tags instanceof CompoundTag){
|
||||
$this->setNamedTag($tags);
|
||||
}else{
|
||||
$this->tags = (string) $tags;
|
||||
$this->tags = $tags === null ? "" : (string) $tags;
|
||||
$this->cachedNBT = null;
|
||||
}
|
||||
|
||||
@ -232,6 +232,9 @@ class Item implements ItemIds, \JsonSerializable{
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method returns NBT serialized in a network-dependent format. Prefer use of getNamedTag() instead.
|
||||
* @see Item::getNamedTag()
|
||||
*
|
||||
* Returns the serialized NBT of the Item
|
||||
* @return string
|
||||
*/
|
||||
|
@ -300,16 +300,16 @@ class ItemFactory{
|
||||
/**
|
||||
* Returns an instance of the Item with the specified id, meta, count and NBT.
|
||||
*
|
||||
* @param int $id
|
||||
* @param int $meta
|
||||
* @param int $count
|
||||
* @param CompoundTag|string $tags
|
||||
* @param int $id
|
||||
* @param int $meta
|
||||
* @param int $count
|
||||
* @param CompoundTag|string|null $tags
|
||||
*
|
||||
* @return Item
|
||||
* @throws \TypeError
|
||||
*/
|
||||
public static function get(int $id, int $meta = 0, int $count = 1, $tags = "") : Item{
|
||||
if(!is_string($tags) and !($tags instanceof CompoundTag)){
|
||||
public static function get(int $id, int $meta = 0, int $count = 1, $tags = null) : Item{
|
||||
if(!is_string($tags) and !($tags instanceof CompoundTag) and $tags !== null){
|
||||
throw new \TypeError("`tags` argument must be a string or CompoundTag instance, " . (is_object($tags) ? "instance of " . get_class($tags) : gettype($tags)) . " given");
|
||||
}
|
||||
|
||||
@ -318,7 +318,7 @@ class ItemFactory{
|
||||
$listed = self::$list[self::getListOffset($id)];
|
||||
if($listed !== null){
|
||||
$item = clone $listed;
|
||||
}elseif($id < 256){ //intentionally includes negatives, for extended block IDs
|
||||
}elseif($id >= 0 and $id < 256){ //intentionally excludes negatives because extended blocks aren't supported yet
|
||||
/* Blocks must have a damage value 0-15, but items can have damage value -1 to indicate that they are
|
||||
* crafting ingredients with any-damage. */
|
||||
$item = new ItemBlock($id, $meta);
|
||||
|
Submodule src/pocketmine/lang/locale updated: 1d525a7c1c...5dad5db214
@ -219,11 +219,10 @@ class Explosion{
|
||||
|
||||
$t = $this->level->getTileAt($block->x, $block->y, $block->z);
|
||||
if($t instanceof Tile){
|
||||
if($t instanceof Chest){
|
||||
$t->unpair();
|
||||
}
|
||||
if($yieldDrops and $t instanceof Container){
|
||||
if($t instanceof Chest){
|
||||
$t->unpair();
|
||||
}
|
||||
|
||||
$t->getInventory()->dropContents($this->level, $t->add(0.5, 0.5, 0.5));
|
||||
}
|
||||
|
||||
|
@ -293,6 +293,19 @@ class Level implements ChunkManager, Metadatable{
|
||||
return (($x & 0xFFFFFFF) << 36) | (($y & Level::Y_MASK) << 28) | ($z & 0xFFFFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a small index relative to chunk base from the given coordinates.
|
||||
*
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
* @param int $z
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function chunkBlockHash(int $x, int $y, int $z) : int{
|
||||
return ($y << 8) | (($z & 0xf) << 4) | ($x & 0xf);
|
||||
}
|
||||
|
||||
public static function getBlockXYZ(int $hash, ?int &$x, ?int &$y, ?int &$z) : void{
|
||||
$x = $hash >> 36;
|
||||
$y = ($hash >> 28) & Level::Y_MASK; //it's always positive
|
||||
@ -369,6 +382,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.level.preparing", [$this->displayName]));
|
||||
$this->generator = GeneratorManager::getGenerator($this->provider->getGenerator());
|
||||
//TODO: validate generator options
|
||||
|
||||
$this->folderName = $name;
|
||||
|
||||
@ -554,7 +568,8 @@ class Level implements ChunkManager, Metadatable{
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal DO NOT use this from plugins, it's for internal use only. Use Server->unloadLevel() instead.
|
||||
* @internal
|
||||
* @see Server::unloadLevel()
|
||||
*
|
||||
* Unloads the current level from memory safely
|
||||
*
|
||||
@ -602,7 +617,10 @@ class Level implements ChunkManager, Metadatable{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the players being used in a specific chunk
|
||||
* @deprecated WARNING: This function has a misleading name. Contrary to what the name might imply, this function
|
||||
* DOES NOT return players who are IN a chunk, rather, it returns players who can SEE the chunk.
|
||||
*
|
||||
* Returns a list of players who have the target chunk within their view distance.
|
||||
*
|
||||
* @param int $chunkX
|
||||
* @param int $chunkZ
|
||||
@ -681,25 +699,25 @@ class Level implements ChunkManager, Metadatable{
|
||||
}
|
||||
|
||||
public function registerChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ, bool $autoLoad = true){
|
||||
$hash = $loader->getLoaderId();
|
||||
$loaderId = $loader->getLoaderId();
|
||||
|
||||
if(!isset($this->chunkLoaders[$index = Level::chunkHash($chunkX, $chunkZ)])){
|
||||
$this->chunkLoaders[$index] = [];
|
||||
$this->playerLoaders[$index] = [];
|
||||
}elseif(isset($this->chunkLoaders[$index][$hash])){
|
||||
if(!isset($this->chunkLoaders[$chunkHash = Level::chunkHash($chunkX, $chunkZ)])){
|
||||
$this->chunkLoaders[$chunkHash] = [];
|
||||
$this->playerLoaders[$chunkHash] = [];
|
||||
}elseif(isset($this->chunkLoaders[$chunkHash][$loaderId])){
|
||||
return;
|
||||
}
|
||||
|
||||
$this->chunkLoaders[$index][$hash] = $loader;
|
||||
$this->chunkLoaders[$chunkHash][$loaderId] = $loader;
|
||||
if($loader instanceof Player){
|
||||
$this->playerLoaders[$index][$hash] = $loader;
|
||||
$this->playerLoaders[$chunkHash][$loaderId] = $loader;
|
||||
}
|
||||
|
||||
if(!isset($this->loaders[$hash])){
|
||||
$this->loaderCounter[$hash] = 1;
|
||||
$this->loaders[$hash] = $loader;
|
||||
if(!isset($this->loaders[$loaderId])){
|
||||
$this->loaderCounter[$loaderId] = 1;
|
||||
$this->loaders[$loaderId] = $loader;
|
||||
}else{
|
||||
++$this->loaderCounter[$hash];
|
||||
++$this->loaderCounter[$loaderId];
|
||||
}
|
||||
|
||||
$this->cancelUnloadChunkRequest($chunkX, $chunkZ);
|
||||
@ -710,27 +728,26 @@ class Level implements ChunkManager, Metadatable{
|
||||
}
|
||||
|
||||
public function unregisterChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ){
|
||||
$index = Level::chunkHash($chunkX, $chunkZ);
|
||||
$hash = $loader->getLoaderId();
|
||||
if(isset($this->chunkLoaders[$index][$hash])){
|
||||
unset($this->chunkLoaders[$index][$hash]);
|
||||
unset($this->playerLoaders[$index][$hash]);
|
||||
if(count($this->chunkLoaders[$index]) === 0){
|
||||
unset($this->chunkLoaders[$index]);
|
||||
unset($this->playerLoaders[$index]);
|
||||
$chunkHash = Level::chunkHash($chunkX, $chunkZ);
|
||||
$loaderId = $loader->getLoaderId();
|
||||
if(isset($this->chunkLoaders[$chunkHash][$loaderId])){
|
||||
unset($this->chunkLoaders[$chunkHash][$loaderId]);
|
||||
unset($this->playerLoaders[$chunkHash][$loaderId]);
|
||||
if(count($this->chunkLoaders[$chunkHash]) === 0){
|
||||
unset($this->chunkLoaders[$chunkHash]);
|
||||
unset($this->playerLoaders[$chunkHash]);
|
||||
$this->unloadChunkRequest($chunkX, $chunkZ, true);
|
||||
}
|
||||
|
||||
if(--$this->loaderCounter[$hash] === 0){
|
||||
unset($this->loaderCounter[$hash]);
|
||||
unset($this->loaders[$hash]);
|
||||
if(--$this->loaderCounter[$loaderId] === 0){
|
||||
unset($this->loaderCounter[$loaderId]);
|
||||
unset($this->loaders[$loaderId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Do not use this, it's only for internal use.
|
||||
* Changes to this function won't be recorded on the version.
|
||||
* @internal
|
||||
*/
|
||||
public function checkTime(){
|
||||
if($this->stopTime){
|
||||
@ -741,8 +758,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Do not use this, it's only for internal use.
|
||||
* Changes to this function won't be recorded on the version.
|
||||
* @internal
|
||||
*
|
||||
* @param Player ...$targets If empty, will send to all players in the level.
|
||||
*/
|
||||
@ -754,8 +770,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Do not use this, it's only for internal use.
|
||||
* Changes to this function won't be recorded on the version.
|
||||
* @internal
|
||||
*
|
||||
* @param int $currentTick
|
||||
*
|
||||
@ -1076,11 +1091,12 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
foreach($chunk->getSubChunks() as $Y => $subChunk){
|
||||
if(!($subChunk instanceof EmptySubChunk)){
|
||||
$k = mt_rand(0, 0xfffffffff); //36 bits
|
||||
for($i = 0; $i < 3; ++$i){
|
||||
$k = mt_rand(0, 0xfff);
|
||||
$x = $k & 0x0f;
|
||||
$y = ($k >> 4) & 0x0f;
|
||||
$z = ($k >> 8) & 0x0f;
|
||||
$k >>= 12;
|
||||
|
||||
$blockId = $subChunk->getBlockId($x, $y, $z);
|
||||
if($this->randomTickBlocks[$blockId] !== null){
|
||||
@ -1423,14 +1439,14 @@ class Level implements ChunkManager, Metadatable{
|
||||
*/
|
||||
public function getBlockAt(int $x, int $y, int $z, bool $cached = true, bool $addToCache = true) : Block{
|
||||
$fullState = 0;
|
||||
$blockHash = null;
|
||||
$relativeBlockHash = null;
|
||||
$chunkHash = Level::chunkHash($x >> 4, $z >> 4);
|
||||
|
||||
if($this->isInWorld($x, $y, $z)){
|
||||
$blockHash = Level::blockHash($x, $y, $z);
|
||||
$relativeBlockHash = Level::chunkBlockHash($x, $y, $z);
|
||||
|
||||
if($cached and isset($this->blockCache[$chunkHash][$blockHash])){
|
||||
return $this->blockCache[$chunkHash][$blockHash];
|
||||
if($cached and isset($this->blockCache[$chunkHash][$relativeBlockHash])){
|
||||
return $this->blockCache[$chunkHash][$relativeBlockHash];
|
||||
}
|
||||
|
||||
$chunk = $this->chunks[$chunkHash] ?? null;
|
||||
@ -1448,8 +1464,8 @@ class Level implements ChunkManager, Metadatable{
|
||||
$block->z = $z;
|
||||
$block->level = $this;
|
||||
|
||||
if($addToCache and $blockHash !== null){
|
||||
$this->blockCache[$chunkHash][$blockHash] = $block;
|
||||
if($addToCache and $relativeBlockHash !== null){
|
||||
$this->blockCache[$chunkHash][$relativeBlockHash] = $block;
|
||||
}
|
||||
|
||||
return $block;
|
||||
@ -1607,19 +1623,19 @@ class Level implements ChunkManager, Metadatable{
|
||||
$block->clearCaches();
|
||||
|
||||
$chunkHash = Level::chunkHash($pos->x >> 4, $pos->z >> 4);
|
||||
$blockHash = Level::blockHash($pos->x, $pos->y, $pos->z);
|
||||
$relativeBlockHash = Level::chunkBlockHash($pos->x, $pos->y, $pos->z);
|
||||
|
||||
unset($this->blockCache[$chunkHash][$blockHash]);
|
||||
unset($this->blockCache[$chunkHash][$relativeBlockHash]);
|
||||
|
||||
if($direct){
|
||||
$this->sendBlocks($this->getChunkPlayers($pos->x >> 4, $pos->z >> 4), [$block], UpdateBlockPacket::FLAG_ALL_PRIORITY);
|
||||
unset($this->chunkCache[$chunkHash], $this->changedBlocks[$chunkHash][$blockHash]);
|
||||
unset($this->chunkCache[$chunkHash], $this->changedBlocks[$chunkHash][$relativeBlockHash]);
|
||||
}else{
|
||||
if(!isset($this->changedBlocks[$chunkHash])){
|
||||
$this->changedBlocks[$chunkHash] = [];
|
||||
}
|
||||
|
||||
$this->changedBlocks[$chunkHash][$blockHash] = $block;
|
||||
$this->changedBlocks[$chunkHash][$relativeBlockHash] = $block;
|
||||
}
|
||||
|
||||
foreach($this->getChunkLoaders($pos->x >> 4, $pos->z >> 4) as $loader){
|
||||
@ -2212,14 +2228,14 @@ class Level implements ChunkManager, Metadatable{
|
||||
return;
|
||||
}
|
||||
$chunkHash = Level::chunkHash($x >> 4, $z >> 4);
|
||||
$blockHash = Level::blockHash($x, $y, $z);
|
||||
unset($this->blockCache[$chunkHash][$blockHash]);
|
||||
$relativeBlockHash = Level::chunkBlockHash($x, $y, $z);
|
||||
unset($this->blockCache[$chunkHash][$relativeBlockHash]);
|
||||
$this->getChunk($x >> 4, $z >> 4, true)->setBlockId($x & 0x0f, $y, $z & 0x0f, $id & 0xff);
|
||||
|
||||
if(!isset($this->changedBlocks[$chunkHash])){
|
||||
$this->changedBlocks[$chunkHash] = [];
|
||||
}
|
||||
$this->changedBlocks[$chunkHash][$blockHash] = $v = new Vector3($x, $y, $z);
|
||||
$this->changedBlocks[$chunkHash][$relativeBlockHash] = $v = new Vector3($x, $y, $z);
|
||||
foreach($this->getChunkLoaders($x >> 4, $z >> 4) as $loader){
|
||||
$loader->onBlockChanged($v);
|
||||
}
|
||||
@ -2251,15 +2267,15 @@ class Level implements ChunkManager, Metadatable{
|
||||
return;
|
||||
}
|
||||
$chunkHash = Level::chunkHash($x >> 4, $z >> 4);
|
||||
$blockHash = Level::blockHash($x, $y, $z);
|
||||
unset($this->blockCache[$chunkHash][$blockHash]);
|
||||
$relativeBlockHash = Level::chunkBlockHash($x, $y, $z);
|
||||
unset($this->blockCache[$chunkHash][$relativeBlockHash]);
|
||||
|
||||
$this->getChunk($x >> 4, $z >> 4, true)->setBlockData($x & 0x0f, $y, $z & 0x0f, $data & 0x0f);
|
||||
|
||||
if(!isset($this->changedBlocks[$chunkHash])){
|
||||
$this->changedBlocks[$chunkHash] = [];
|
||||
}
|
||||
$this->changedBlocks[$chunkHash][$blockHash] = $v = new Vector3($x, $y, $z);
|
||||
$this->changedBlocks[$chunkHash][$relativeBlockHash] = $v = new Vector3($x, $y, $z);
|
||||
foreach($this->getChunkLoaders($x >> 4, $z >> 4) as $loader){
|
||||
$loader->onBlockChanged($v);
|
||||
}
|
||||
@ -2461,9 +2477,9 @@ class Level implements ChunkManager, Metadatable{
|
||||
* @param int $chunkX
|
||||
* @param int $chunkZ
|
||||
* @param Chunk|null $chunk
|
||||
* @param bool $unload
|
||||
* @param bool $deleteEntitiesAndTiles Whether to delete entities and tiles on the old chunk, or transfer them to the new one
|
||||
*/
|
||||
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null, bool $unload = true){
|
||||
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null, bool $deleteEntitiesAndTiles = true){
|
||||
if($chunk === null){
|
||||
return;
|
||||
}
|
||||
@ -2474,7 +2490,16 @@ class Level implements ChunkManager, Metadatable{
|
||||
$chunkHash = Level::chunkHash($chunkX, $chunkZ);
|
||||
$oldChunk = $this->getChunk($chunkX, $chunkZ, false);
|
||||
if($oldChunk !== null and $oldChunk !== $chunk){
|
||||
if($unload){
|
||||
if($deleteEntitiesAndTiles){
|
||||
foreach($oldChunk->getEntities() as $player){
|
||||
if(!($player instanceof Player)){
|
||||
continue;
|
||||
}
|
||||
$chunk->addEntity($player);
|
||||
$oldChunk->removeEntity($player);
|
||||
$player->chunk = $chunk;
|
||||
}
|
||||
//TODO: this causes chunkloaders to receive false "unloaded" notifications
|
||||
$this->unloadChunk($chunkX, $chunkZ, false, false);
|
||||
}else{
|
||||
foreach($oldChunk->getEntities() as $entity){
|
||||
@ -2814,6 +2839,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
$loader->onChunkLoaded($chunk);
|
||||
}
|
||||
}else{
|
||||
$this->server->getLogger()->debug("Newly loaded chunk $x $z has no loaders registered, will be unloaded at next available opportunity");
|
||||
$this->unloadChunkRequest($x, $z);
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,11 @@ use pocketmine\level\generator\populator\Ore;
|
||||
use pocketmine\level\generator\populator\Populator;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\utils\Random;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function preg_match;
|
||||
use function preg_match_all;
|
||||
use function str_replace;
|
||||
|
||||
class Flat extends Generator{
|
||||
/** @var Chunk */
|
||||
@ -62,6 +63,11 @@ class Flat extends Generator{
|
||||
return "flat";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @throws InvalidGeneratorOptionsException
|
||||
*/
|
||||
public function __construct(array $options = []){
|
||||
$this->options = $options;
|
||||
if(isset($this->options["preset"]) and $this->options["preset"] != ""){
|
||||
@ -89,13 +95,28 @@ class Flat extends Generator{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $layers
|
||||
*
|
||||
* @return int[][]
|
||||
* @throws InvalidGeneratorOptionsException
|
||||
*/
|
||||
public static function parseLayers(string $layers) : array{
|
||||
$result = [];
|
||||
preg_match_all('#^(([0-9]*x|)([0-9]{1,3})(|:[0-9]{0,2}))$#m', str_replace(",", "\n", $layers), $matches);
|
||||
$split = array_map('\trim', explode(',', $layers));
|
||||
$y = 0;
|
||||
foreach($matches[3] as $i => $b){
|
||||
$b = ItemFactory::fromString($b . $matches[4][$i]);
|
||||
$cnt = $matches[2][$i] === "" ? 1 : (int) $matches[2][$i];
|
||||
foreach($split as $line){
|
||||
preg_match('#^(?:(\d+)x)?(.+)$#', $line, $matches);
|
||||
if(count($matches) !== 3){
|
||||
throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\"");
|
||||
}
|
||||
|
||||
$cnt = $matches[1] !== "" ? (int) $matches[1] : 1;
|
||||
try{
|
||||
$b = ItemFactory::fromString($matches[2])->getBlock();
|
||||
}catch(\InvalidArgumentException $e){
|
||||
throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\": " . $e->getMessage(), 0, $e);
|
||||
}
|
||||
for($cY = $y, $y += $cnt; $cY < $y; ++$cY){
|
||||
$result[$cY] = [$b->getId(), $b->getDamage()];
|
||||
}
|
||||
@ -113,6 +134,7 @@ class Flat extends Generator{
|
||||
|
||||
$this->floorLevel = count($this->structure);
|
||||
|
||||
//TODO: more error checking
|
||||
preg_match_all('#(([0-9a-z_]{1,})\(?([0-9a-z_ =:]{0,})\)?),?#', $options, $matches);
|
||||
foreach($matches[2] as $i => $option){
|
||||
$params = true;
|
||||
|
@ -58,6 +58,11 @@ abstract class Generator{
|
||||
/** @var Random */
|
||||
protected $random;
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
*
|
||||
* @throws InvalidGeneratorOptionsException
|
||||
*/
|
||||
abstract public function __construct(array $settings = []);
|
||||
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
<?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\level\generator;
|
||||
|
||||
class InvalidGeneratorOptionsException extends \UnexpectedValueException{
|
||||
|
||||
}
|
@ -27,6 +27,7 @@ use pocketmine\block\Block;
|
||||
use pocketmine\level\biome\Biome;
|
||||
use pocketmine\level\ChunkManager;
|
||||
use pocketmine\level\generator\Generator;
|
||||
use pocketmine\level\generator\InvalidGeneratorOptionsException;
|
||||
use pocketmine\level\generator\noise\Simplex;
|
||||
use pocketmine\level\generator\populator\Populator;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -51,6 +52,11 @@ class Nether extends Generator{
|
||||
/** @var Simplex */
|
||||
private $noiseBase;
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @throws InvalidGeneratorOptionsException
|
||||
*/
|
||||
public function __construct(array $options = []){
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ use pocketmine\level\biome\Biome;
|
||||
use pocketmine\level\ChunkManager;
|
||||
use pocketmine\level\generator\biome\BiomeSelector;
|
||||
use pocketmine\level\generator\Generator;
|
||||
use pocketmine\level\generator\InvalidGeneratorOptionsException;
|
||||
use pocketmine\level\generator\noise\Simplex;
|
||||
use pocketmine\level\generator\object\OreType;
|
||||
use pocketmine\level\generator\populator\GroundCover;
|
||||
@ -57,6 +58,11 @@ class Normal extends Generator{
|
||||
private static $GAUSSIAN_KERNEL = null;
|
||||
private static $SMOOTH_SIZE = 2;
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @throws InvalidGeneratorOptionsException
|
||||
*/
|
||||
public function __construct(array $options = []){
|
||||
if(self::$GAUSSIAN_KERNEL === null){
|
||||
self::generateKernel();
|
||||
|
@ -30,6 +30,8 @@ use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
|
||||
use pocketmine\network\mcpe\protocol\types\EntityLink;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
@ -38,6 +40,8 @@ use function count;
|
||||
use function strlen;
|
||||
|
||||
class NetworkBinaryStream extends BinaryStream{
|
||||
/** @var NetworkLittleEndianNBTStream */
|
||||
private static $nbtSerializer = null;
|
||||
|
||||
public function getString() : string{
|
||||
return $this->get($this->getUnsignedVarInt());
|
||||
@ -79,10 +83,17 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
$cnt = $auxValue & 0xff;
|
||||
|
||||
$nbtLen = $this->getLShort();
|
||||
$nbt = "";
|
||||
|
||||
if($nbtLen > 0){
|
||||
$nbt = $this->get($nbtLen);
|
||||
/** @var CompoundTag|string $nbt */
|
||||
$nbt = "";
|
||||
if($nbtLen === 0xffff){
|
||||
$c = $this->getByte();
|
||||
if($c !== 1){
|
||||
throw new \UnexpectedValueException("Unexpected NBT count $c");
|
||||
}
|
||||
$nbt = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset);
|
||||
}elseif($nbtLen !== 0){
|
||||
throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen");
|
||||
}
|
||||
|
||||
//TODO
|
||||
@ -110,25 +121,14 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
$auxValue = (($item->getDamage() & 0x7fff) << 8) | $item->getCount();
|
||||
$this->putVarInt($auxValue);
|
||||
|
||||
$nbt = $item->getCompoundTag();
|
||||
$nbtLen = strlen($nbt);
|
||||
if($nbtLen > 32767){
|
||||
/*
|
||||
* TODO: Workaround bug in the protocol (overflow)
|
||||
* Encoded tags larger than 32KB overflow the length field, so we can't send these over network.
|
||||
* However, it's unreasonable to randomly throw this burden off onto users by crashing their servers, so the
|
||||
* next best solution is to just not send the NBT. This is also not an ideal solution (books and the like
|
||||
* with too-large tags won't work on the client side) but it's better than crashing the server or client due
|
||||
* to a protocol bug. Mojang have confirmed this will be resolved by a future MCPE release, so we'll just
|
||||
* work around this problem until then.
|
||||
*/
|
||||
$nbt = "";
|
||||
$nbtLen = 0;
|
||||
if($item->hasCompoundTag()){
|
||||
$this->putLShort(0xffff);
|
||||
$this->putByte(1); //TODO: some kind of count field? always 1 as of 1.9.0
|
||||
$this->put((new NetworkLittleEndianNBTStream())->write($item->getNamedTag()));
|
||||
}else{
|
||||
$this->putLShort(0);
|
||||
}
|
||||
|
||||
$this->putLShort($nbtLen);
|
||||
$this->put($nbt);
|
||||
|
||||
$this->putVarInt(0); //CanPlaceOn entry count (TODO)
|
||||
$this->putVarInt(0); //CanDestroy entry count (TODO)
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ namespace pocketmine\network\mcpe;
|
||||
|
||||
use pocketmine\network\mcpe\protocol\AddBehaviorTreePacket;
|
||||
use pocketmine\network\mcpe\protocol\AddEntityPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddHangingEntityPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddItemEntityPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddPaintingPacket;
|
||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||
@ -72,6 +71,7 @@ use pocketmine\network\mcpe\protocol\LabTablePacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacketV1;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacketV2;
|
||||
use pocketmine\network\mcpe\protocol\LoginPacket;
|
||||
use pocketmine\network\mcpe\protocol\MapInfoRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
|
||||
@ -210,10 +210,6 @@ abstract class NetworkSession{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleAddHangingEntity(AddHangingEntityPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleTakeItemEntity(TakeItemEntityPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
@ -622,7 +618,7 @@ abstract class NetworkSession{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleLevelSoundEvent(LevelSoundEventPacket $packet) : bool{
|
||||
public function handleLevelSoundEventPacketV2(LevelSoundEventPacketV2 $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -634,4 +630,8 @@ abstract class NetworkSession{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleLevelSoundEvent(LevelSoundEventPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
||||
use pocketmine\network\mcpe\protocol\ModalFormResponsePacket;
|
||||
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerActionPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerHotbarPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerInputPacket;
|
||||
@ -300,4 +301,8 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
|
||||
public function handleLevelSoundEvent(LevelSoundEventPacket $packet) : bool{
|
||||
return $this->player->handleLevelSoundEvent($packet);
|
||||
}
|
||||
|
||||
public function handleNetworkStackLatency(NetworkStackLatencyPacket $packet) : bool{
|
||||
return true; //TODO: implement this properly - this is here to silence debug spam from MCPE dev builds
|
||||
}
|
||||
}
|
||||
|
@ -28,19 +28,37 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class AddPaintingPacket extends AddHangingEntityPacket{
|
||||
class AddPaintingPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::ADD_PAINTING_PACKET;
|
||||
|
||||
/** @var string */
|
||||
public $title;
|
||||
/** @var int */
|
||||
public $entityRuntimeId;
|
||||
/** @var int */
|
||||
public $x;
|
||||
/** @var int|null */
|
||||
public $entityUniqueId = null;
|
||||
/** @var int */
|
||||
public $y;
|
||||
/** @var int */
|
||||
public $z;
|
||||
/** @var int */
|
||||
public $direction;
|
||||
|
||||
protected function decodePayload(){
|
||||
parent::decodePayload();
|
||||
$this->entityUniqueId = $this->getEntityUniqueId();
|
||||
$this->entityRuntimeId = $this->getEntityRuntimeId();
|
||||
$this->getBlockPosition($this->x, $this->y, $this->z);
|
||||
$this->direction = $this->getVarInt();
|
||||
$this->title = $this->getString();
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
parent::encodePayload();
|
||||
$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
|
||||
$this->putEntityRuntimeId($this->entityRuntimeId);
|
||||
$this->putBlockPosition($this->x, $this->y, $this->z);
|
||||
$this->putVarInt($this->direction);
|
||||
$this->putString($this->title);
|
||||
}
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -299,7 +299,7 @@ class LevelSoundEventPacket extends DataPacket{
|
||||
public $disableRelativeVolume = false;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->sound = $this->getByte();
|
||||
$this->sound = $this->getUnsignedVarInt();
|
||||
$this->position = $this->getVector3();
|
||||
$this->extraData = $this->getVarInt();
|
||||
$this->entityType = $this->getString();
|
||||
@ -308,7 +308,7 @@ class LevelSoundEventPacket extends DataPacket{
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->putByte($this->sound);
|
||||
$this->putUnsignedVarInt($this->sound);
|
||||
$this->putVector3($this->position);
|
||||
$this->putVarInt($this->extraData);
|
||||
$this->putString($this->entityType);
|
||||
|
@ -25,39 +25,47 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class AddHangingEntityPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::ADD_HANGING_ENTITY_PACKET;
|
||||
/**
|
||||
* Useless leftover from a 1.9 refactor, does nothing
|
||||
*/
|
||||
class LevelSoundEventPacketV2 extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::LEVEL_SOUND_EVENT_PACKET_V2;
|
||||
|
||||
/** @var int|null */
|
||||
public $entityUniqueId = null;
|
||||
/** @var int */
|
||||
public $entityRuntimeId;
|
||||
public $sound;
|
||||
/** @var Vector3 */
|
||||
public $position;
|
||||
/** @var int */
|
||||
public $x;
|
||||
/** @var int */
|
||||
public $y;
|
||||
/** @var int */
|
||||
public $z;
|
||||
/** @var int */
|
||||
public $direction;
|
||||
public $extraData = -1;
|
||||
/** @var string */
|
||||
public $entityType = ":"; //???
|
||||
/** @var bool */
|
||||
public $isBabyMob = false; //...
|
||||
/** @var bool */
|
||||
public $disableRelativeVolume = false;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->entityUniqueId = $this->getEntityUniqueId();
|
||||
$this->entityRuntimeId = $this->getEntityRuntimeId();
|
||||
$this->getBlockPosition($this->x, $this->y, $this->z);
|
||||
$this->direction = $this->getVarInt();
|
||||
$this->sound = $this->getByte();
|
||||
$this->position = $this->getVector3();
|
||||
$this->extraData = $this->getVarInt();
|
||||
$this->entityType = $this->getString();
|
||||
$this->isBabyMob = $this->getBool();
|
||||
$this->disableRelativeVolume = $this->getBool();
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
|
||||
$this->putEntityRuntimeId($this->entityRuntimeId);
|
||||
$this->putBlockPosition($this->x, $this->y, $this->z);
|
||||
$this->putVarInt($this->direction);
|
||||
$this->putByte($this->sound);
|
||||
$this->putVector3($this->position);
|
||||
$this->putVarInt($this->extraData);
|
||||
$this->putString($this->entityType);
|
||||
$this->putBool($this->isBabyMob);
|
||||
$this->putBool($this->disableRelativeVolume);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
return $session->handleAddHangingEntity($this);
|
||||
return $session->handleLevelSoundEventPacketV2($this);
|
||||
}
|
||||
}
|
@ -32,13 +32,17 @@ class NetworkStackLatencyPacket extends DataPacket{
|
||||
|
||||
/** @var int */
|
||||
public $timestamp;
|
||||
/** @var bool */
|
||||
public $needResponse;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->timestamp = $this->getLLong();
|
||||
$this->needResponse = $this->getBool();
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->putLLong($this->timestamp);
|
||||
$this->putBool($this->needResponse);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
|
@ -48,7 +48,6 @@ class PacketPool{
|
||||
static::registerPacket(new AddEntityPacket());
|
||||
static::registerPacket(new RemoveEntityPacket());
|
||||
static::registerPacket(new AddItemEntityPacket());
|
||||
static::registerPacket(new AddHangingEntityPacket());
|
||||
static::registerPacket(new TakeItemEntityPacket());
|
||||
static::registerPacket(new MoveEntityAbsolutePacket());
|
||||
static::registerPacket(new MovePlayerPacket());
|
||||
@ -151,9 +150,10 @@ class PacketPool{
|
||||
static::registerPacket(new ScriptCustomEventPacket());
|
||||
static::registerPacket(new SpawnParticleEffectPacket());
|
||||
static::registerPacket(new AvailableEntityIdentifiersPacket());
|
||||
static::registerPacket(new LevelSoundEventPacket());
|
||||
static::registerPacket(new LevelSoundEventPacketV2());
|
||||
static::registerPacket(new NetworkChunkPublisherUpdatePacket());
|
||||
static::registerPacket(new BiomeDefinitionListPacket());
|
||||
static::registerPacket(new LevelSoundEventPacket());
|
||||
|
||||
static::registerPacket(new BatchPacket());
|
||||
}
|
||||
|
@ -39,15 +39,15 @@ interface ProtocolInfo{
|
||||
/**
|
||||
* Actual Minecraft: PE protocol version
|
||||
*/
|
||||
public const CURRENT_PROTOCOL = 313;
|
||||
public const CURRENT_PROTOCOL = 332;
|
||||
/**
|
||||
* Current Minecraft PE version reported by the server. This is usually the earliest currently supported version.
|
||||
*/
|
||||
public const MINECRAFT_VERSION = 'v1.8.0';
|
||||
public const MINECRAFT_VERSION = 'v1.9.0';
|
||||
/**
|
||||
* Version number sent to clients in ping responses.
|
||||
*/
|
||||
public const MINECRAFT_VERSION_NETWORK = '1.8.0';
|
||||
public const MINECRAFT_VERSION_NETWORK = '1.9.0';
|
||||
|
||||
public const LOGIN_PACKET = 0x01;
|
||||
public const PLAY_STATUS_PACKET = 0x02;
|
||||
@ -64,7 +64,7 @@ interface ProtocolInfo{
|
||||
public const ADD_ENTITY_PACKET = 0x0d;
|
||||
public const REMOVE_ENTITY_PACKET = 0x0e;
|
||||
public const ADD_ITEM_ENTITY_PACKET = 0x0f;
|
||||
public const ADD_HANGING_ENTITY_PACKET = 0x10;
|
||||
|
||||
public const TAKE_ITEM_ENTITY_PACKET = 0x11;
|
||||
public const MOVE_ENTITY_ABSOLUTE_PACKET = 0x12;
|
||||
public const MOVE_PLAYER_PACKET = 0x13;
|
||||
@ -168,8 +168,9 @@ interface ProtocolInfo{
|
||||
public const SCRIPT_CUSTOM_EVENT_PACKET = 0x75;
|
||||
public const SPAWN_PARTICLE_EFFECT_PACKET = 0x76;
|
||||
public const AVAILABLE_ENTITY_IDENTIFIERS_PACKET = 0x77;
|
||||
public const LEVEL_SOUND_EVENT_PACKET = 0x78;
|
||||
public const LEVEL_SOUND_EVENT_PACKET_V2 = 0x78;
|
||||
public const NETWORK_CHUNK_PUBLISHER_UPDATE_PACKET = 0x79;
|
||||
public const BIOME_DEFINITION_LIST_PACKET = 0x7a;
|
||||
public const LEVEL_SOUND_EVENT_PACKET = 0x7b;
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ class ResourcePacksInfoPacket extends DataPacket{
|
||||
|
||||
/** @var bool */
|
||||
public $mustAccept = false; //if true, forces client to use selected resource packs
|
||||
/** @var bool */
|
||||
public $hasScripts = false; //if true, causes disconnect for any platform that doesn't support scripts yet
|
||||
/** @var ResourcePack[] */
|
||||
public $behaviorPackEntries = [];
|
||||
/** @var ResourcePack[] */
|
||||
@ -42,6 +44,7 @@ class ResourcePacksInfoPacket extends DataPacket{
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->mustAccept = $this->getBool();
|
||||
$this->hasScripts = $this->getBool();
|
||||
$behaviorPackCount = $this->getLShort();
|
||||
while($behaviorPackCount-- > 0){
|
||||
$this->getString();
|
||||
@ -50,6 +53,7 @@ class ResourcePacksInfoPacket extends DataPacket{
|
||||
$this->getString();
|
||||
$this->getString();
|
||||
$this->getString();
|
||||
$this->getBool();
|
||||
}
|
||||
|
||||
$resourcePackCount = $this->getLShort();
|
||||
@ -60,12 +64,13 @@ class ResourcePacksInfoPacket extends DataPacket{
|
||||
$this->getString();
|
||||
$this->getString();
|
||||
$this->getString();
|
||||
$this->getBool();
|
||||
}
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
|
||||
$this->putBool($this->mustAccept);
|
||||
$this->putBool($this->hasScripts);
|
||||
$this->putLShort(count($this->behaviorPackEntries));
|
||||
foreach($this->behaviorPackEntries as $entry){
|
||||
$this->putString($entry->getPackId());
|
||||
@ -74,6 +79,7 @@ class ResourcePacksInfoPacket extends DataPacket{
|
||||
$this->putString(""); //TODO: encryption key
|
||||
$this->putString(""); //TODO: subpack name
|
||||
$this->putString(""); //TODO: content identity
|
||||
$this->putBool(false); //TODO: has scripts (?)
|
||||
}
|
||||
$this->putLShort(count($this->resourcePackEntries));
|
||||
foreach($this->resourcePackEntries as $entry){
|
||||
@ -83,6 +89,7 @@ class ResourcePacksInfoPacket extends DataPacket{
|
||||
$this->putString(""); //TODO: encryption key
|
||||
$this->putString(""); //TODO: subpack name
|
||||
$this->putString(""); //TODO: content identity
|
||||
$this->putBool(false); //TODO: seems useless for resource packs
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,8 @@ class SpawnParticleEffectPacket extends DataPacket{
|
||||
|
||||
/** @var int */
|
||||
public $dimensionId = DimensionIds::OVERWORLD; //wtf mojang
|
||||
/** @var int */
|
||||
public $entityUniqueId = -1; //default none
|
||||
/** @var Vector3 */
|
||||
public $position;
|
||||
/** @var string */
|
||||
@ -41,12 +43,14 @@ class SpawnParticleEffectPacket extends DataPacket{
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->dimensionId = $this->getByte();
|
||||
$this->entityUniqueId = $this->getEntityUniqueId();
|
||||
$this->position = $this->getVector3();
|
||||
$this->particleName = $this->getString();
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->putByte($this->dimensionId);
|
||||
$this->putEntityUniqueId($this->entityUniqueId);
|
||||
$this->putVector3($this->position);
|
||||
$this->putString($this->particleName);
|
||||
}
|
||||
|
@ -84,35 +84,33 @@ class StartGamePacket extends DataPacket{
|
||||
/** @var float */
|
||||
public $lightningLevel;
|
||||
/** @var bool */
|
||||
public $hasConfirmedPlatformLockedContent = false;
|
||||
/** @var bool */
|
||||
public $isMultiplayerGame = true;
|
||||
/** @var bool */
|
||||
public $hasLANBroadcast = true;
|
||||
/** @var bool */
|
||||
public $hasXboxLiveBroadcast = false;
|
||||
/** @var int */
|
||||
public $xboxLiveBroadcastMode = 0; //TODO: find values
|
||||
/** @var int */
|
||||
public $platformBroadcastMode = 0;
|
||||
/** @var bool */
|
||||
public $commandsEnabled;
|
||||
/** @var bool */
|
||||
public $isTexturePacksRequired = true;
|
||||
/** @var array */
|
||||
public $gameRules = []; //TODO: implement this
|
||||
public $gameRules = [ //TODO: implement this
|
||||
"naturalregeneration" => [1, false] //Hack for client side regeneration
|
||||
];
|
||||
/** @var bool */
|
||||
public $hasBonusChestEnabled = false;
|
||||
/** @var bool */
|
||||
public $hasStartWithMapEnabled = false;
|
||||
/** @var bool */
|
||||
public $hasTrustPlayersEnabled = false;
|
||||
/** @var int */
|
||||
public $defaultPlayerPermission = PlayerPermissions::MEMBER; //TODO
|
||||
/** @var int */
|
||||
public $xboxLiveBroadcastMode = 0; //TODO: find values
|
||||
|
||||
/** @var int */
|
||||
public $serverChunkTickRadius = 4; //TODO (leave as default for now)
|
||||
/** @var bool */
|
||||
public $hasPlatformBroadcast = false;
|
||||
/** @var int */
|
||||
public $platformBroadcastMode = 0;
|
||||
/** @var bool */
|
||||
public $xboxLiveBroadcastIntent = false;
|
||||
|
||||
/** @var bool */
|
||||
public $hasLockedBehaviorPack = false;
|
||||
/** @var bool */
|
||||
@ -164,21 +162,18 @@ class StartGamePacket extends DataPacket{
|
||||
$this->hasEduFeaturesEnabled = $this->getBool();
|
||||
$this->rainLevel = $this->getLFloat();
|
||||
$this->lightningLevel = $this->getLFloat();
|
||||
$this->hasConfirmedPlatformLockedContent = $this->getBool();
|
||||
$this->isMultiplayerGame = $this->getBool();
|
||||
$this->hasLANBroadcast = $this->getBool();
|
||||
$this->hasXboxLiveBroadcast = $this->getBool();
|
||||
$this->xboxLiveBroadcastMode = $this->getVarInt();
|
||||
$this->platformBroadcastMode = $this->getVarInt();
|
||||
$this->commandsEnabled = $this->getBool();
|
||||
$this->isTexturePacksRequired = $this->getBool();
|
||||
$this->gameRules = $this->getGameRules();
|
||||
$this->hasBonusChestEnabled = $this->getBool();
|
||||
$this->hasStartWithMapEnabled = $this->getBool();
|
||||
$this->hasTrustPlayersEnabled = $this->getBool();
|
||||
$this->defaultPlayerPermission = $this->getVarInt();
|
||||
$this->xboxLiveBroadcastMode = $this->getVarInt();
|
||||
$this->serverChunkTickRadius = $this->getLInt();
|
||||
$this->hasPlatformBroadcast = $this->getBool();
|
||||
$this->platformBroadcastMode = $this->getVarInt();
|
||||
$this->xboxLiveBroadcastIntent = $this->getBool();
|
||||
$this->hasLockedBehaviorPack = $this->getBool();
|
||||
$this->hasLockedResourcePack = $this->getBool();
|
||||
$this->isFromLockedWorldTemplate = $this->getBool();
|
||||
@ -226,21 +221,18 @@ class StartGamePacket extends DataPacket{
|
||||
$this->putBool($this->hasEduFeaturesEnabled);
|
||||
$this->putLFloat($this->rainLevel);
|
||||
$this->putLFloat($this->lightningLevel);
|
||||
$this->putBool($this->hasConfirmedPlatformLockedContent);
|
||||
$this->putBool($this->isMultiplayerGame);
|
||||
$this->putBool($this->hasLANBroadcast);
|
||||
$this->putBool($this->hasXboxLiveBroadcast);
|
||||
$this->putVarInt($this->xboxLiveBroadcastMode);
|
||||
$this->putVarInt($this->platformBroadcastMode);
|
||||
$this->putBool($this->commandsEnabled);
|
||||
$this->putBool($this->isTexturePacksRequired);
|
||||
$this->putGameRules($this->gameRules);
|
||||
$this->putBool($this->hasBonusChestEnabled);
|
||||
$this->putBool($this->hasStartWithMapEnabled);
|
||||
$this->putBool($this->hasTrustPlayersEnabled);
|
||||
$this->putVarInt($this->defaultPlayerPermission);
|
||||
$this->putVarInt($this->xboxLiveBroadcastMode);
|
||||
$this->putLInt($this->serverChunkTickRadius);
|
||||
$this->putBool($this->hasPlatformBroadcast);
|
||||
$this->putVarInt($this->platformBroadcastMode);
|
||||
$this->putBool($this->xboxLiveBroadcastIntent);
|
||||
$this->putBool($this->hasLockedBehaviorPack);
|
||||
$this->putBool($this->hasLockedResourcePack);
|
||||
$this->putBool($this->isFromLockedWorldTemplate);
|
||||
|
@ -41,6 +41,7 @@ class TextPacket extends DataPacket{
|
||||
public const TYPE_SYSTEM = 6;
|
||||
public const TYPE_WHISPER = 7;
|
||||
public const TYPE_ANNOUNCEMENT = 8;
|
||||
public const TYPE_JSON = 9;
|
||||
|
||||
/** @var int */
|
||||
public $type;
|
||||
@ -69,6 +70,7 @@ class TextPacket extends DataPacket{
|
||||
case self::TYPE_RAW:
|
||||
case self::TYPE_TIP:
|
||||
case self::TYPE_SYSTEM:
|
||||
case self::TYPE_JSON:
|
||||
$this->message = $this->getString();
|
||||
break;
|
||||
|
||||
@ -99,6 +101,7 @@ class TextPacket extends DataPacket{
|
||||
case self::TYPE_RAW:
|
||||
case self::TYPE_TIP:
|
||||
case self::TYPE_SYSTEM:
|
||||
case self::TYPE_JSON:
|
||||
$this->putString($this->message);
|
||||
break;
|
||||
|
||||
|
@ -40,7 +40,18 @@ use function strlen;
|
||||
use function substr;
|
||||
|
||||
class QueryHandler{
|
||||
private $server, $lastToken, $token, $longData, $shortData, $timeout;
|
||||
/** @var Server */
|
||||
private $server;
|
||||
/** @var string */
|
||||
private $lastToken;
|
||||
/** @var string */
|
||||
private $token;
|
||||
/** @var string */
|
||||
private $longData;
|
||||
/** @var string */
|
||||
private $shortData;
|
||||
/** @var float */
|
||||
private $timeout;
|
||||
|
||||
public const HANDSHAKE = 9;
|
||||
public const STATISTICS = 0;
|
||||
|
@ -29,9 +29,7 @@ namespace pocketmine\network\upnp;
|
||||
use pocketmine\utils\Internet;
|
||||
use pocketmine\utils\Utils;
|
||||
use function class_exists;
|
||||
use function gethostbyname;
|
||||
use function is_object;
|
||||
use function trim;
|
||||
|
||||
abstract class UPnP{
|
||||
|
||||
@ -46,7 +44,7 @@ abstract class UPnP{
|
||||
throw new \RuntimeException("UPnP requires the com_dotnet extension");
|
||||
}
|
||||
|
||||
$myLocalIP = gethostbyname(trim(`hostname`));
|
||||
$myLocalIP = Internet::getInternalIP();
|
||||
|
||||
/** @noinspection PhpUndefinedClassInspection */
|
||||
$com = new \COM("HNetCfg.NATUPnP");
|
||||
|
@ -384,14 +384,14 @@ class PluginManager{
|
||||
*/
|
||||
public function isCompatibleApi(string ...$versions) : bool{
|
||||
$serverString = $this->server->getApiVersion();
|
||||
$serverApi = array_pad(explode("-", $serverString), 2, "");
|
||||
$serverApi = array_pad(explode("-", $serverString, 2), 2, "");
|
||||
$serverNumbers = array_map("\intval", explode(".", $serverApi[0]));
|
||||
|
||||
foreach($versions as $version){
|
||||
//Format: majorVersion.minorVersion.patch (3.0.0)
|
||||
// or: majorVersion.minorVersion.patch-devBuild (3.0.0-alpha1)
|
||||
if($version !== $serverString){
|
||||
$pluginApi = array_pad(explode("-", $version), 2, ""); //0 = version, 1 = suffix (optional)
|
||||
$pluginApi = array_pad(explode("-", $version, 2), 2, ""); //0 = version, 1 = suffix (optional)
|
||||
|
||||
if(strtoupper($pluginApi[1]) !== strtoupper($serverApi[1])){ //Different release phase (alpha vs. beta) or phase build (alpha.1 vs alpha.2)
|
||||
continue;
|
||||
|
251
src/pocketmine/resources/legacy_id_map.json
Normal file
251
src/pocketmine/resources/legacy_id_map.json
Normal file
@ -0,0 +1,251 @@
|
||||
{
|
||||
"minecraft:air": 0,
|
||||
"minecraft:stone": 1,
|
||||
"minecraft:grass": 2,
|
||||
"minecraft:dirt": 3,
|
||||
"minecraft:cobblestone": 4,
|
||||
"minecraft:planks": 5,
|
||||
"minecraft:sapling": 6,
|
||||
"minecraft:bedrock": 7,
|
||||
"minecraft:flowing_water": 8,
|
||||
"minecraft:water": 9,
|
||||
"minecraft:flowing_lava": 10,
|
||||
"minecraft:lava": 11,
|
||||
"minecraft:sand": 12,
|
||||
"minecraft:gravel": 13,
|
||||
"minecraft:gold_ore": 14,
|
||||
"minecraft:iron_ore": 15,
|
||||
"minecraft:coal_ore": 16,
|
||||
"minecraft:log": 17,
|
||||
"minecraft:leaves": 18,
|
||||
"minecraft:sponge": 19,
|
||||
"minecraft:glass": 20,
|
||||
"minecraft:lapis_ore": 21,
|
||||
"minecraft:lapis_block": 22,
|
||||
"minecraft:dispenser": 23,
|
||||
"minecraft:sandstone": 24,
|
||||
"minecraft:noteblock": 25,
|
||||
"minecraft:bed": 26,
|
||||
"minecraft:golden_rail": 27,
|
||||
"minecraft:detector_rail": 28,
|
||||
"minecraft:sticky_piston": 29,
|
||||
"minecraft:web": 30,
|
||||
"minecraft:tallgrass": 31,
|
||||
"minecraft:deadbush": 32,
|
||||
"minecraft:piston": 33,
|
||||
"minecraft:pistonArmCollision": 34,
|
||||
"minecraft:wool": 35,
|
||||
"minecraft:element_0": 36,
|
||||
"minecraft:yellow_flower": 37,
|
||||
"minecraft:red_flower": 38,
|
||||
"minecraft:brown_mushroom": 39,
|
||||
"minecraft:red_mushroom": 40,
|
||||
"minecraft:gold_block": 41,
|
||||
"minecraft:iron_block": 42,
|
||||
"minecraft:double_stone_slab": 43,
|
||||
"minecraft:stone_slab": 44,
|
||||
"minecraft:brick_block": 45,
|
||||
"minecraft:tnt": 46,
|
||||
"minecraft:bookshelf": 47,
|
||||
"minecraft:mossy_cobblestone": 48,
|
||||
"minecraft:obsidian": 49,
|
||||
"minecraft:torch": 50,
|
||||
"minecraft:fire": 51,
|
||||
"minecraft:mob_spawner": 52,
|
||||
"minecraft:oak_stairs": 53,
|
||||
"minecraft:chest": 54,
|
||||
"minecraft:redstone_wire": 55,
|
||||
"minecraft:diamond_ore": 56,
|
||||
"minecraft:diamond_block": 57,
|
||||
"minecraft:crafting_table": 58,
|
||||
"minecraft:wheat": 59,
|
||||
"minecraft:farmland": 60,
|
||||
"minecraft:furnace": 61,
|
||||
"minecraft:lit_furnace": 62,
|
||||
"minecraft:standing_sign": 63,
|
||||
"minecraft:wooden_door": 64,
|
||||
"minecraft:ladder": 65,
|
||||
"minecraft:rail": 66,
|
||||
"minecraft:stone_stairs": 67,
|
||||
"minecraft:wall_sign": 68,
|
||||
"minecraft:lever": 69,
|
||||
"minecraft:stone_pressure_plate": 70,
|
||||
"minecraft:iron_door": 71,
|
||||
"minecraft:wooden_pressure_plate": 72,
|
||||
"minecraft:redstone_ore": 73,
|
||||
"minecraft:lit_redstone_ore": 74,
|
||||
"minecraft:unlit_redstone_torch": 75,
|
||||
"minecraft:redstone_torch": 76,
|
||||
"minecraft:stone_button": 77,
|
||||
"minecraft:snow_layer": 78,
|
||||
"minecraft:ice": 79,
|
||||
"minecraft:snow": 80,
|
||||
"minecraft:cactus": 81,
|
||||
"minecraft:clay": 82,
|
||||
"minecraft:reeds": 83,
|
||||
"minecraft:jukebox": 84,
|
||||
"minecraft:fence": 85,
|
||||
"minecraft:pumpkin": 86,
|
||||
"minecraft:netherrack": 87,
|
||||
"minecraft:soul_sand": 88,
|
||||
"minecraft:glowstone": 89,
|
||||
"minecraft:portal": 90,
|
||||
"minecraft:lit_pumpkin": 91,
|
||||
"minecraft:cake": 92,
|
||||
"minecraft:unpowered_repeater": 93,
|
||||
"minecraft:powered_repeater": 94,
|
||||
"minecraft:invisibleBedrock": 95,
|
||||
"minecraft:trapdoor": 96,
|
||||
"minecraft:monster_egg": 97,
|
||||
"minecraft:stonebrick": 98,
|
||||
"minecraft:brown_mushroom_block": 99,
|
||||
"minecraft:red_mushroom_block": 100,
|
||||
"minecraft:iron_bars": 101,
|
||||
"minecraft:glass_pane": 102,
|
||||
"minecraft:melon_block": 103,
|
||||
"minecraft:pumpkin_stem": 104,
|
||||
"minecraft:melon_stem": 105,
|
||||
"minecraft:vine": 106,
|
||||
"minecraft:fence_gate": 107,
|
||||
"minecraft:brick_stairs": 108,
|
||||
"minecraft:stone_brick_stairs": 109,
|
||||
"minecraft:mycelium": 110,
|
||||
"minecraft:waterlily": 111,
|
||||
"minecraft:nether_brick": 112,
|
||||
"minecraft:nether_brick_fence": 113,
|
||||
"minecraft:nether_brick_stairs": 114,
|
||||
"minecraft:nether_wart": 115,
|
||||
"minecraft:enchanting_table": 116,
|
||||
"minecraft:brewing_stand": 117,
|
||||
"minecraft:cauldron": 118,
|
||||
"minecraft:end_portal": 119,
|
||||
"minecraft:end_portal_frame": 120,
|
||||
"minecraft:end_stone": 121,
|
||||
"minecraft:dragon_egg": 122,
|
||||
"minecraft:redstone_lamp": 123,
|
||||
"minecraft:lit_redstone_lamp": 124,
|
||||
"minecraft:dropper": 125,
|
||||
"minecraft:activator_rail": 126,
|
||||
"minecraft:cocoa": 127,
|
||||
"minecraft:sandstone_stairs": 128,
|
||||
"minecraft:emerald_ore": 129,
|
||||
"minecraft:ender_chest": 130,
|
||||
"minecraft:tripwire_hook": 131,
|
||||
"minecraft:tripWire": 132,
|
||||
"minecraft:emerald_block": 133,
|
||||
"minecraft:spruce_stairs": 134,
|
||||
"minecraft:birch_stairs": 135,
|
||||
"minecraft:jungle_stairs": 136,
|
||||
"minecraft:command_block": 137,
|
||||
"minecraft:beacon": 138,
|
||||
"minecraft:cobblestone_wall": 139,
|
||||
"minecraft:flower_pot": 140,
|
||||
"minecraft:carrots": 141,
|
||||
"minecraft:potatoes": 142,
|
||||
"minecraft:wooden_button": 143,
|
||||
"minecraft:skull": 144,
|
||||
"minecraft:anvil": 145,
|
||||
"minecraft:trapped_chest": 146,
|
||||
"minecraft:light_weighted_pressure_plate": 147,
|
||||
"minecraft:heavy_weighted_pressure_plate": 148,
|
||||
"minecraft:unpowered_comparator": 149,
|
||||
"minecraft:powered_comparator": 150,
|
||||
"minecraft:daylight_detector": 151,
|
||||
"minecraft:redstone_block": 152,
|
||||
"minecraft:quartz_ore": 153,
|
||||
"minecraft:hopper": 154,
|
||||
"minecraft:quartz_block": 155,
|
||||
"minecraft:quartz_stairs": 156,
|
||||
"minecraft:double_wooden_slab": 157,
|
||||
"minecraft:wooden_slab": 158,
|
||||
"minecraft:stained_hardened_clay": 159,
|
||||
"minecraft:stained_glass_pane": 160,
|
||||
"minecraft:leaves2": 161,
|
||||
"minecraft:log2": 162,
|
||||
"minecraft:acacia_stairs": 163,
|
||||
"minecraft:dark_oak_stairs": 164,
|
||||
"minecraft:slime": 165,
|
||||
"minecraft:iron_trapdoor": 167,
|
||||
"minecraft:prismarine": 168,
|
||||
"minecraft:seaLantern": 169,
|
||||
"minecraft:hay_block": 170,
|
||||
"minecraft:carpet": 171,
|
||||
"minecraft:hardened_clay": 172,
|
||||
"minecraft:coal_block": 173,
|
||||
"minecraft:packed_ice": 174,
|
||||
"minecraft:double_plant": 175,
|
||||
"minecraft:standing_banner": 176,
|
||||
"minecraft:wall_banner": 177,
|
||||
"minecraft:daylight_detector_inverted": 178,
|
||||
"minecraft:red_sandstone": 179,
|
||||
"minecraft:red_sandstone_stairs": 180,
|
||||
"minecraft:double_stone_slab2": 181,
|
||||
"minecraft:stone_slab2": 182,
|
||||
"minecraft:spruce_fence_gate": 183,
|
||||
"minecraft:birch_fence_gate": 184,
|
||||
"minecraft:jungle_fence_gate": 185,
|
||||
"minecraft:dark_oak_fence_gate": 186,
|
||||
"minecraft:acacia_fence_gate": 187,
|
||||
"minecraft:repeating_command_block": 188,
|
||||
"minecraft:chain_command_block": 189,
|
||||
"minecraft:hard_glass_pane": 190,
|
||||
"minecraft:hard_stained_glass_pane": 191,
|
||||
"minecraft:chemical_heat": 192,
|
||||
"minecraft:spruce_door": 193,
|
||||
"minecraft:birch_door": 194,
|
||||
"minecraft:jungle_door": 195,
|
||||
"minecraft:acacia_door": 196,
|
||||
"minecraft:dark_oak_door": 197,
|
||||
"minecraft:grass_path": 198,
|
||||
"minecraft:frame": 199,
|
||||
"minecraft:chorus_flower": 200,
|
||||
"minecraft:purpur_block": 201,
|
||||
"minecraft:colored_torch_rg": 202,
|
||||
"minecraft:purpur_stairs": 203,
|
||||
"minecraft:colored_torch_bp": 204,
|
||||
"minecraft:undyed_shulker_box": 205,
|
||||
"minecraft:end_bricks": 206,
|
||||
"minecraft:frosted_ice": 207,
|
||||
"minecraft:end_rod": 208,
|
||||
"minecraft:end_gateway": 209,
|
||||
"minecraft:magma": 213,
|
||||
"minecraft:nether_wart_block": 214,
|
||||
"minecraft:red_nether_brick": 215,
|
||||
"minecraft:bone_block": 216,
|
||||
"minecraft:shulker_box": 218,
|
||||
"minecraft:purple_glazed_terracotta": 219,
|
||||
"minecraft:white_glazed_terracotta": 220,
|
||||
"minecraft:orange_glazed_terracotta": 221,
|
||||
"minecraft:magenta_glazed_terracotta": 222,
|
||||
"minecraft:light_blue_glazed_terracotta": 223,
|
||||
"minecraft:yellow_glazed_terracotta": 224,
|
||||
"minecraft:lime_glazed_terracotta": 225,
|
||||
"minecraft:pink_glazed_terracotta": 226,
|
||||
"minecraft:gray_glazed_terracotta": 227,
|
||||
"minecraft:silver_glazed_terracotta": 228,
|
||||
"minecraft:cyan_glazed_terracotta": 229,
|
||||
"minecraft:blue_glazed_terracotta": 231,
|
||||
"minecraft:brown_glazed_terracotta": 232,
|
||||
"minecraft:green_glazed_terracotta": 233,
|
||||
"minecraft:red_glazed_terracotta": 234,
|
||||
"minecraft:black_glazed_terracotta": 235,
|
||||
"minecraft:concrete": 236,
|
||||
"minecraft:concretePowder": 237,
|
||||
"minecraft:chemistry_table": 238,
|
||||
"minecraft:underwater_torch": 239,
|
||||
"minecraft:chorus_plant": 240,
|
||||
"minecraft:stained_glass": 241,
|
||||
"minecraft:podzol": 243,
|
||||
"minecraft:beetroot": 244,
|
||||
"minecraft:stonecutter": 245,
|
||||
"minecraft:glowingobsidian": 246,
|
||||
"minecraft:netherreactor": 247,
|
||||
"minecraft:info_update": 248,
|
||||
"minecraft:info_update2": 249,
|
||||
"minecraft:movingBlock": 250,
|
||||
"minecraft:observer": 251,
|
||||
"minecraft:structure_block": 252,
|
||||
"minecraft:hard_glass": 253,
|
||||
"minecraft:hard_stained_glass": 254,
|
||||
"minecraft:reserved6": 255
|
||||
}
|
@ -4,192 +4,192 @@
|
||||
# New settings/defaults won't appear automatically in this file when upgrading.
|
||||
|
||||
settings:
|
||||
#Whether to send all strings translated to server locale or let the device handle them
|
||||
force-language: false
|
||||
shutdown-message: "Server closed"
|
||||
#Allow listing plugins via Query
|
||||
query-plugins: true
|
||||
#Show a console message when a plugin uses deprecated API methods
|
||||
deprecated-verbose: true
|
||||
#Enable plugin and core profiling by default
|
||||
enable-profiling: false
|
||||
#Will only add results when tick measurement is below or equal to given value (default 20)
|
||||
profile-report-trigger: 20
|
||||
#Number of AsyncTask workers.
|
||||
#Used for plugin asynchronous tasks, world generation, compression and web communication.
|
||||
#Set this approximately to your number of cores.
|
||||
#If set to auto, it'll try to detect the number of cores (or use 2)
|
||||
async-workers: auto
|
||||
#Whether to allow running development builds. Dev builds might crash, break your plugins, corrupt your world and more.
|
||||
#It is recommended to avoid using development builds where possible.
|
||||
enable-dev-builds: false
|
||||
#Whether to send all strings translated to server locale or let the device handle them
|
||||
force-language: false
|
||||
shutdown-message: "Server closed"
|
||||
#Allow listing plugins via Query
|
||||
query-plugins: true
|
||||
#Show a console message when a plugin uses deprecated API methods
|
||||
deprecated-verbose: true
|
||||
#Enable plugin and core profiling by default
|
||||
enable-profiling: false
|
||||
#Will only add results when tick measurement is below or equal to given value (default 20)
|
||||
profile-report-trigger: 20
|
||||
#Number of AsyncTask workers.
|
||||
#Used for plugin asynchronous tasks, world generation, compression and web communication.
|
||||
#Set this approximately to your number of cores.
|
||||
#If set to auto, it'll try to detect the number of cores (or use 2)
|
||||
async-workers: auto
|
||||
#Whether to allow running development builds. Dev builds might crash, break your plugins, corrupt your world and more.
|
||||
#It is recommended to avoid using development builds where possible.
|
||||
enable-dev-builds: false
|
||||
|
||||
memory:
|
||||
#Global soft memory limit in megabytes. Set to 0 to disable
|
||||
#This will trigger low-memory-triggers and fire an event to free memory when the usage goes over this
|
||||
global-limit: 0
|
||||
#Global soft memory limit in megabytes. Set to 0 to disable
|
||||
#This will trigger low-memory-triggers and fire an event to free memory when the usage goes over this
|
||||
global-limit: 0
|
||||
|
||||
#Main thread soft memory limit in megabytes. Set to 0 to disable
|
||||
#This will trigger low-memory-triggers and fire an event to free memory when the usage goes over this
|
||||
main-limit: 0
|
||||
#Main thread soft memory limit in megabytes. Set to 0 to disable
|
||||
#This will trigger low-memory-triggers and fire an event to free memory when the usage goes over this
|
||||
main-limit: 0
|
||||
|
||||
#Main thread hard memory limit in megabytes. Set to 0 to disable
|
||||
#This will stop the server when the limit is surpassed
|
||||
main-hard-limit: 1024
|
||||
#Main thread hard memory limit in megabytes. Set to 0 to disable
|
||||
#This will stop the server when the limit is surpassed
|
||||
main-hard-limit: 1024
|
||||
|
||||
#AsyncWorker threads' hard memory limit in megabytes. Set to 0 to disable
|
||||
#This will crash the task currently executing on the worker if the task exceeds the limit
|
||||
#NOTE: THIS LIMIT APPLIES PER WORKER, NOT TO THE WHOLE PROCESS.
|
||||
async-worker-hard-limit: 256
|
||||
#AsyncWorker threads' hard memory limit in megabytes. Set to 0 to disable
|
||||
#This will crash the task currently executing on the worker if the task exceeds the limit
|
||||
#NOTE: THIS LIMIT APPLIES PER WORKER, NOT TO THE WHOLE PROCESS.
|
||||
async-worker-hard-limit: 256
|
||||
|
||||
#Period in ticks to check memory (default 1 second)
|
||||
check-rate: 20
|
||||
#Period in ticks to check memory (default 1 second)
|
||||
check-rate: 20
|
||||
|
||||
#Continue firing low-memory-triggers and event while on low memory
|
||||
continuous-trigger: true
|
||||
#Continue firing low-memory-triggers and event while on low memory
|
||||
continuous-trigger: true
|
||||
|
||||
#Only if memory.continuous-trigger is enabled. Specifies the rate in memory.check-rate steps (default 30 seconds)
|
||||
continuous-trigger-rate: 30
|
||||
#Only if memory.continuous-trigger is enabled. Specifies the rate in memory.check-rate steps (default 30 seconds)
|
||||
continuous-trigger-rate: 30
|
||||
|
||||
garbage-collection:
|
||||
#Period in ticks to fire the garbage collector manually (default 30 minutes), set to 0 to disable
|
||||
#This only affects the main thread. Other threads should fire their own collections
|
||||
period: 36000
|
||||
garbage-collection:
|
||||
#Period in ticks to fire the garbage collector manually (default 30 minutes), set to 0 to disable
|
||||
#This only affects the main thread. Other threads should fire their own collections
|
||||
period: 36000
|
||||
|
||||
#Fire asynchronous tasks to collect garbage from workers
|
||||
collect-async-worker: true
|
||||
#Fire asynchronous tasks to collect garbage from workers
|
||||
collect-async-worker: true
|
||||
|
||||
#Trigger on low memory
|
||||
low-memory-trigger: true
|
||||
#Trigger on low memory
|
||||
low-memory-trigger: true
|
||||
|
||||
#Settings controlling memory dump handling.
|
||||
memory-dump:
|
||||
#Dump memory from async workers as well as the main thread. If you have issues with segfaults when dumping memory, disable this setting.
|
||||
dump-async-worker: true
|
||||
#Settings controlling memory dump handling.
|
||||
memory-dump:
|
||||
#Dump memory from async workers as well as the main thread. If you have issues with segfaults when dumping memory, disable this setting.
|
||||
dump-async-worker: true
|
||||
|
||||
max-chunks:
|
||||
#Cap maximum render distance per player when low memory is triggered. Set to 0 to disable cap.
|
||||
chunk-radius: 4
|
||||
max-chunks:
|
||||
#Cap maximum render distance per player when low memory is triggered. Set to 0 to disable cap.
|
||||
chunk-radius: 4
|
||||
|
||||
#Do chunk garbage collection on trigger
|
||||
trigger-chunk-collect: true
|
||||
#Do chunk garbage collection on trigger
|
||||
trigger-chunk-collect: true
|
||||
|
||||
world-caches:
|
||||
#Disallow adding to world chunk-packet caches when memory is low
|
||||
disable-chunk-cache: true
|
||||
#Clear world caches when memory is low
|
||||
low-memory-trigger: true
|
||||
world-caches:
|
||||
#Disallow adding to world chunk-packet caches when memory is low
|
||||
disable-chunk-cache: true
|
||||
#Clear world caches when memory is low
|
||||
low-memory-trigger: true
|
||||
|
||||
|
||||
network:
|
||||
#Threshold for batching packets, in bytes. Only these packets will be compressed
|
||||
#Set to 0 to compress everything, -1 to disable.
|
||||
batch-threshold: 256
|
||||
#Compression level used when sending batched packets. Higher = more CPU, less bandwidth usage
|
||||
compression-level: 7
|
||||
#Use AsyncTasks for compression. Adds half/one tick delay, less CPU load on main thread
|
||||
async-compression: false
|
||||
#Experimental, only for Windows. Tries to use UPnP to automatically port forward
|
||||
upnp-forwarding: false
|
||||
#Maximum size in bytes of packets sent over the network (default 1492 bytes). Packets larger than this will be
|
||||
#fragmented or split into smaller parts. Clients can request MTU sizes up to but not more than this number.
|
||||
max-mtu-size: 1492
|
||||
#Threshold for batching packets, in bytes. Only these packets will be compressed
|
||||
#Set to 0 to compress everything, -1 to disable.
|
||||
batch-threshold: 256
|
||||
#Compression level used when sending batched packets. Higher = more CPU, less bandwidth usage
|
||||
compression-level: 7
|
||||
#Use AsyncTasks for compression. Adds half/one tick delay, less CPU load on main thread
|
||||
async-compression: false
|
||||
#Experimental, only for Windows. Tries to use UPnP to automatically port forward
|
||||
upnp-forwarding: false
|
||||
#Maximum size in bytes of packets sent over the network (default 1492 bytes). Packets larger than this will be
|
||||
#fragmented or split into smaller parts. Clients can request MTU sizes up to but not more than this number.
|
||||
max-mtu-size: 1492
|
||||
|
||||
debug:
|
||||
#If > 1, it will show debug messages in the console
|
||||
level: 1
|
||||
#If > 1, it will show debug messages in the console
|
||||
level: 1
|
||||
|
||||
player:
|
||||
#Choose whether to enable player data saving.
|
||||
save-player-data: true
|
||||
anti-cheat:
|
||||
#If false, will try to prevent speed and noclip cheats. May cause movement issues.
|
||||
allow-movement-cheats: true
|
||||
#Choose whether to enable player data saving.
|
||||
save-player-data: true
|
||||
anti-cheat:
|
||||
#If false, will try to prevent speed and noclip cheats. May cause movement issues.
|
||||
allow-movement-cheats: true
|
||||
|
||||
level-settings:
|
||||
#The default format that levels will use when created
|
||||
default-format: pmanvil
|
||||
#Automatically change levels tick rate to maintain 20 ticks per second
|
||||
auto-tick-rate: true
|
||||
auto-tick-rate-limit: 20
|
||||
#Sets the base tick rate (1 = 20 ticks per second, 2 = 10 ticks per second, etc.)
|
||||
base-tick-rate: 1
|
||||
#Tick all players each tick even when other settings disallow this.
|
||||
always-tick-players: false
|
||||
#The default format that levels will use when created
|
||||
default-format: pmanvil
|
||||
#Automatically change levels tick rate to maintain 20 ticks per second
|
||||
auto-tick-rate: true
|
||||
auto-tick-rate-limit: 20
|
||||
#Sets the base tick rate (1 = 20 ticks per second, 2 = 10 ticks per second, etc.)
|
||||
base-tick-rate: 1
|
||||
#Tick all players each tick even when other settings disallow this.
|
||||
always-tick-players: false
|
||||
|
||||
chunk-sending:
|
||||
#To change server normal render distance, change view-distance in server.properties.
|
||||
#Amount of chunks sent to players per tick
|
||||
per-tick: 4
|
||||
#Radius of chunks that need to be sent before spawning the player
|
||||
spawn-radius: 4
|
||||
#To change server normal render distance, change view-distance in server.properties.
|
||||
#Amount of chunks sent to players per tick
|
||||
per-tick: 4
|
||||
#Radius of chunks that need to be sent before spawning the player
|
||||
spawn-radius: 4
|
||||
|
||||
chunk-ticking:
|
||||
#Max amount of chunks processed each tick
|
||||
per-tick: 40
|
||||
#Radius of chunks around a player to tick
|
||||
tick-radius: 3
|
||||
light-updates: false
|
||||
clear-tick-list: true
|
||||
#IDs of blocks not to perform random ticking on.
|
||||
disable-block-ticking:
|
||||
#- 2 # grass
|
||||
#Max amount of chunks processed each tick
|
||||
per-tick: 40
|
||||
#Radius of chunks around a player to tick
|
||||
tick-radius: 3
|
||||
light-updates: false
|
||||
clear-tick-list: true
|
||||
#IDs of blocks not to perform random ticking on.
|
||||
disable-block-ticking:
|
||||
#- 2 # grass
|
||||
|
||||
chunk-generation:
|
||||
#Max. amount of chunks in the waiting queue to be populated
|
||||
population-queue-size: 8
|
||||
#Max. amount of chunks in the waiting queue to be populated
|
||||
population-queue-size: 8
|
||||
|
||||
ticks-per:
|
||||
autosave: 6000
|
||||
autosave: 6000
|
||||
|
||||
auto-report:
|
||||
#Send crash reports for processing
|
||||
enabled: true
|
||||
send-code: true
|
||||
send-settings: true
|
||||
send-phpinfo: false
|
||||
use-https: true
|
||||
host: crash.pmmp.io
|
||||
#Send crash reports for processing
|
||||
enabled: true
|
||||
send-code: true
|
||||
send-settings: true
|
||||
send-phpinfo: false
|
||||
use-https: true
|
||||
host: crash.pmmp.io
|
||||
|
||||
anonymous-statistics:
|
||||
#Sends anonymous statistics for data aggregation, plugin usage tracking
|
||||
enabled: false #TODO: re-enable this when we have a new stats host
|
||||
host: stats.pocketmine.net
|
||||
#Sends anonymous statistics for data aggregation, plugin usage tracking
|
||||
enabled: false #TODO: re-enable this when we have a new stats host
|
||||
host: stats.pocketmine.net
|
||||
|
||||
auto-updater:
|
||||
enabled: true
|
||||
on-update:
|
||||
warn-console: true
|
||||
warn-ops: true
|
||||
#Can be development, alpha, beta or stable.
|
||||
preferred-channel: stable
|
||||
#If using a development version, it will suggest changing the channel
|
||||
suggest-channels: true
|
||||
host: update.pmmp.io
|
||||
enabled: true
|
||||
on-update:
|
||||
warn-console: true
|
||||
warn-ops: true
|
||||
#Can be development, alpha, beta or stable.
|
||||
preferred-channel: stable
|
||||
#If using a development version, it will suggest changing the channel
|
||||
suggest-channels: true
|
||||
host: update.pmmp.io
|
||||
|
||||
timings:
|
||||
#Choose the host to use for viewing your timings results.
|
||||
host: timings.pmmp.io
|
||||
#Choose the host to use for viewing your timings results.
|
||||
host: timings.pmmp.io
|
||||
|
||||
console:
|
||||
#Choose whether to enable server stats reporting on the console title.
|
||||
#NOTE: The title ticker will be disabled regardless if console colours are not enabled.
|
||||
title-tick: true
|
||||
#Choose whether to enable server stats reporting on the console title.
|
||||
#NOTE: The title ticker will be disabled regardless if console colours are not enabled.
|
||||
title-tick: true
|
||||
|
||||
aliases:
|
||||
#Examples:
|
||||
#showtheversion: version
|
||||
#savestop: [save-all, stop]
|
||||
#Examples:
|
||||
#showtheversion: version
|
||||
#savestop: [save-all, stop]
|
||||
|
||||
worlds:
|
||||
#These settings will override the generator set in server.properties and allows loading multiple levels
|
||||
#Example:
|
||||
#world:
|
||||
# seed: 404
|
||||
# generator: FLAT:2;7,59x1,3x3,2;1;decoration(treecount=80 grasscount=45)
|
||||
#These settings will override the generator set in server.properties and allows loading multiple levels
|
||||
#Example:
|
||||
#world:
|
||||
# seed: 404
|
||||
# generator: FLAT:2;7,59x1,3x3,2;1;decoration(treecount=80 grasscount=45)
|
||||
|
||||
plugins:
|
||||
#Setting this to true will cause the legacy structure to be used where plugin data is placed inside the --plugins dir.
|
||||
#False will place plugin data under plugin_data under --data.
|
||||
#This option exists for backwards compatibility with existing installations.
|
||||
legacy-data-dir: false
|
||||
#Setting this to true will cause the legacy structure to be used where plugin data is placed inside the --plugins dir.
|
||||
#False will place plugin data under plugin_data under --data.
|
||||
#This option exists for backwards compatibility with existing installations.
|
||||
legacy-data-dir: false
|
||||
|
@ -4,9 +4,9 @@
|
||||
#NOTE: This will do nothing if there are no resource packs in the stack below.
|
||||
force_resources: false
|
||||
resource_stack:
|
||||
#Resource packs here are applied from bottom to top. This means that resources in higher packs will override those in lower packs.
|
||||
#Entries here must indicate the filename of the resource pack.
|
||||
#Example
|
||||
# - natural.zip
|
||||
# - vanilla.zip
|
||||
#If you want to force clients to use vanilla resources, you must place a vanilla resource pack in your resources folder and add it to the stack here.
|
||||
#Resource packs here are applied from bottom to top. This means that resources in higher packs will override those in lower packs.
|
||||
#Entries here must indicate the filename of the resource pack.
|
||||
#Example
|
||||
# - natural.zip
|
||||
# - vanilla.zip
|
||||
#If you want to force clients to use vanilla resources, you must place a vanilla resource pack in your resources folder and add it to the stack here.
|
||||
|
File diff suppressed because one or more lines are too long
Submodule src/pocketmine/resources/vanilla updated: 0c00c4f3b9...90c5fcd4ab
@ -64,7 +64,7 @@ class TaskScheduler{
|
||||
/**
|
||||
* @param Task $task
|
||||
*
|
||||
* @return null|TaskHandler
|
||||
* @return TaskHandler
|
||||
*/
|
||||
public function scheduleTask(Task $task){
|
||||
return $this->addTask($task, -1, -1);
|
||||
@ -74,7 +74,7 @@ class TaskScheduler{
|
||||
* @param Task $task
|
||||
* @param int $delay
|
||||
*
|
||||
* @return null|TaskHandler
|
||||
* @return TaskHandler
|
||||
*/
|
||||
public function scheduleDelayedTask(Task $task, int $delay){
|
||||
return $this->addTask($task, $delay, -1);
|
||||
@ -84,7 +84,7 @@ class TaskScheduler{
|
||||
* @param Task $task
|
||||
* @param int $period
|
||||
*
|
||||
* @return null|TaskHandler
|
||||
* @return TaskHandler
|
||||
*/
|
||||
public function scheduleRepeatingTask(Task $task, int $period){
|
||||
return $this->addTask($task, -1, $period);
|
||||
@ -95,7 +95,7 @@ class TaskScheduler{
|
||||
* @param int $delay
|
||||
* @param int $period
|
||||
*
|
||||
* @return null|TaskHandler
|
||||
* @return TaskHandler
|
||||
*/
|
||||
public function scheduleDelayedRepeatingTask(Task $task, int $delay, int $period){
|
||||
return $this->addTask($task, $delay, $period);
|
||||
@ -139,7 +139,7 @@ class TaskScheduler{
|
||||
* @param int $delay
|
||||
* @param int $period
|
||||
*
|
||||
* @return null|TaskHandler
|
||||
* @return TaskHandler
|
||||
*
|
||||
* @throws \InvalidStateException
|
||||
*/
|
||||
|
@ -33,6 +33,8 @@ use function array_pad;
|
||||
use function array_slice;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function mb_check_encoding;
|
||||
use function mb_scrub;
|
||||
use function sprintf;
|
||||
|
||||
class Sign extends Spawnable{
|
||||
@ -57,6 +59,9 @@ class Sign extends Spawnable{
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->text = array_map(function(string $line) : string{
|
||||
return mb_scrub($line, 'UTF-8');
|
||||
}, $this->text);
|
||||
}
|
||||
|
||||
protected function writeSaveData(CompoundTag $nbt) : void{
|
||||
@ -79,16 +84,16 @@ class Sign extends Spawnable{
|
||||
*/
|
||||
public function setText(?string $line1 = "", ?string $line2 = "", ?string $line3 = "", ?string $line4 = "") : void{
|
||||
if($line1 !== null){
|
||||
$this->text[0] = $line1;
|
||||
$this->setLine(0, $line1, false);
|
||||
}
|
||||
if($line2 !== null){
|
||||
$this->text[1] = $line2;
|
||||
$this->setLine(1, $line2, false);
|
||||
}
|
||||
if($line3 !== null){
|
||||
$this->text[2] = $line3;
|
||||
$this->setLine(2, $line3, false);
|
||||
}
|
||||
if($line4 !== null){
|
||||
$this->text[3] = $line4;
|
||||
$this->setLine(3, $line4, false);
|
||||
}
|
||||
|
||||
$this->onChanged();
|
||||
@ -103,6 +108,9 @@ class Sign extends Spawnable{
|
||||
if($index < 0 or $index > 3){
|
||||
throw new \InvalidArgumentException("Index must be in the range 0-3!");
|
||||
}
|
||||
if(!mb_check_encoding($line, 'UTF-8')){
|
||||
throw new \InvalidArgumentException("Text must be valid UTF-8");
|
||||
}
|
||||
|
||||
$this->text[$index] = $line;
|
||||
if($update){
|
||||
|
@ -30,7 +30,13 @@ use function count;
|
||||
class Color{
|
||||
|
||||
/** @var int */
|
||||
protected $a, $r, $g, $b;
|
||||
protected $a;
|
||||
/** @var int */
|
||||
protected $r;
|
||||
/** @var int */
|
||||
protected $g;
|
||||
/** @var int */
|
||||
protected $b;
|
||||
|
||||
public function __construct(int $r, int $g, int $b, int $a = 0xff){
|
||||
$this->r = $r & 0xff;
|
||||
|
@ -32,10 +32,17 @@ use function curl_init;
|
||||
use function curl_setopt_array;
|
||||
use function explode;
|
||||
use function preg_match;
|
||||
use function socket_close;
|
||||
use function socket_connect;
|
||||
use function socket_create;
|
||||
use function socket_getsockname;
|
||||
use function socket_last_error;
|
||||
use function socket_strerror;
|
||||
use function strip_tags;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
use function trim;
|
||||
use const AF_INET;
|
||||
use const CURLINFO_HEADER_SIZE;
|
||||
use const CURLINFO_HTTP_CODE;
|
||||
use const CURLOPT_AUTOREFERER;
|
||||
@ -51,6 +58,8 @@ use const CURLOPT_RETURNTRANSFER;
|
||||
use const CURLOPT_SSL_VERIFYHOST;
|
||||
use const CURLOPT_SSL_VERIFYPEER;
|
||||
use const CURLOPT_TIMEOUT_MS;
|
||||
use const SOCK_DGRAM;
|
||||
use const SOL_UDP;
|
||||
|
||||
class Internet{
|
||||
public static $ip = false;
|
||||
@ -98,6 +107,28 @@ class Internet{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the machine's internal network IP address. If the machine is not behind a router, this may be the same
|
||||
* as the external IP.
|
||||
*
|
||||
* @return string
|
||||
* @throws InternetException
|
||||
*/
|
||||
public static function getInternalIP() : string{
|
||||
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
||||
try{
|
||||
if(!@socket_connect($sock, "8.8.8.8", 65534)){
|
||||
throw new InternetException("Failed to get internal IP: " . trim(socket_strerror(socket_last_error($sock))));
|
||||
}
|
||||
if(!@socket_getsockname($sock, $name)){
|
||||
throw new InternetException("Failed to get internal IP: " . trim(socket_strerror(socket_last_error($sock))));
|
||||
}
|
||||
return $name;
|
||||
}finally{
|
||||
socket_close($sock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GETs an URL using cURL
|
||||
* NOTE: This is a blocking operation and can take a significant amount of time. It is inadvisable to use this method on the main thread.
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\utils;
|
||||
|
||||
use function is_array;
|
||||
use function json_encode;
|
||||
use function mb_scrub;
|
||||
use function preg_quote;
|
||||
use function preg_replace;
|
||||
use function preg_split;
|
||||
@ -77,18 +78,19 @@ abstract class TextFormat{
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the string from Minecraft codes and ANSI Escape Codes
|
||||
* Cleans the string from Minecraft codes, ANSI Escape Codes and invalid UTF-8 characters
|
||||
*
|
||||
* @param string $string
|
||||
* @param bool $removeFormat
|
||||
*
|
||||
* @return string
|
||||
* @return string valid clean UTF-8
|
||||
*/
|
||||
public static function clean(string $string, bool $removeFormat = true) : string{
|
||||
$string = mb_scrub($string, 'UTF-8');
|
||||
if($removeFormat){
|
||||
return str_replace(TextFormat::ESCAPE, "", preg_replace(["/" . TextFormat::ESCAPE . "[0-9a-fk-or]/", "/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/"], "", $string));
|
||||
$string = str_replace(TextFormat::ESCAPE, "", preg_replace("/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "", $string));
|
||||
}
|
||||
return str_replace("\x1b", "", preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/", "", $string));
|
||||
return str_replace("\x1b", "", preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,6 +84,7 @@ use function strlen;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function strval;
|
||||
use function substr;
|
||||
use function sys_get_temp_dir;
|
||||
use function trim;
|
||||
use function xdebug_get_function_stack;
|
||||
@ -127,7 +128,7 @@ class Utils{
|
||||
*/
|
||||
public static function getNiceClosureName(\Closure $closure) : string{
|
||||
$func = new \ReflectionFunction($closure);
|
||||
if($func->getName() !== "{closure}"){
|
||||
if(substr($func->getName(), -strlen('{closure}')) !== '{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
|
||||
|
||||
|
@ -30,9 +30,9 @@ namespace pocketmine\wizard;
|
||||
use pocketmine\lang\BaseLang;
|
||||
use pocketmine\utils\Config;
|
||||
use pocketmine\utils\Internet;
|
||||
use pocketmine\utils\InternetException;
|
||||
use function base64_encode;
|
||||
use function fgets;
|
||||
use function gethostbyname;
|
||||
use function random_bytes;
|
||||
use function sleep;
|
||||
use function strtolower;
|
||||
@ -76,10 +76,6 @@ class SetupWizard{
|
||||
}
|
||||
}while($lang === null);
|
||||
|
||||
$config = new Config(\pocketmine\DATA . "server.properties", Config::PROPERTIES);
|
||||
$config->set("language", $lang);
|
||||
$config->save();
|
||||
|
||||
$this->lang = new BaseLang($lang);
|
||||
|
||||
$this->message($this->lang->get("language_has_been_selected"));
|
||||
@ -88,6 +84,11 @@ class SetupWizard{
|
||||
return false;
|
||||
}
|
||||
|
||||
//this has to happen here to prevent user avoiding agreeing to license
|
||||
$config = new Config(\pocketmine\DATA . "server.properties", Config::PROPERTIES);
|
||||
$config->set("language", $lang);
|
||||
$config->save();
|
||||
|
||||
if(strtolower($this->getInput($this->lang->get("skip_installer"), "n", "y/N")) === "y"){
|
||||
return true;
|
||||
}
|
||||
@ -223,7 +224,11 @@ LICENSE;
|
||||
if($externalIP === false){
|
||||
$externalIP = "unknown (server offline)";
|
||||
}
|
||||
$internalIP = gethostbyname(trim(`hostname`));
|
||||
try{
|
||||
$internalIP = Internet::getInternalIP();
|
||||
}catch(InternetException $e){
|
||||
$internalIP = "unknown (" . $e->getMessage() . ")";
|
||||
}
|
||||
|
||||
$this->error($this->lang->translateString("ip_warning", ["EXTERNAL_IP" => $externalIP, "INTERNAL_IP" => $internalIP]));
|
||||
$this->error($this->lang->get("ip_confirm"));
|
||||
|
59
tests/phpunit/inventory/BaseInventoryTest.php
Normal file
59
tests/phpunit/inventory/BaseInventoryTest.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\inventory;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
|
||||
class BaseInventoryTest extends TestCase{
|
||||
|
||||
public static function setUpBeforeClass(){
|
||||
ItemFactory::init();
|
||||
}
|
||||
|
||||
public function testAddItemDifferentUserData() : void{
|
||||
$inv = new class extends BaseInventory{
|
||||
public function getDefaultSize() : int{
|
||||
return 1;
|
||||
}
|
||||
public function getName() : string{
|
||||
return "";
|
||||
}
|
||||
};
|
||||
$item1 = ItemFactory::get(Item::ARROW, 0, 1);
|
||||
$item2 = ItemFactory::get(Item::ARROW, 0, 1)->setCustomName("TEST");
|
||||
|
||||
$inv->addItem(clone $item1);
|
||||
self::assertFalse($inv->canAddItem($item2), "Item WITHOUT userdata should not stack with item WITH userdata");
|
||||
self::assertNotEmpty($inv->addItem($item2));
|
||||
|
||||
$inv->clearAll();
|
||||
self::assertEmpty($inv->getContents());
|
||||
|
||||
$inv->addItem(clone $item2);
|
||||
self::assertFalse($inv->canAddItem($item1), "Item WITH userdata should not stack with item WITHOUT userdata");
|
||||
self::assertNotEmpty($inv->addItem($item1));
|
||||
}
|
||||
}
|
@ -24,9 +24,20 @@ declare(strict_types=1);
|
||||
namespace pocketmine\utils;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function define;
|
||||
use function defined;
|
||||
|
||||
class UtilsTest extends TestCase{
|
||||
|
||||
public function setUp(){
|
||||
if(!defined('pocketmine\PATH')){
|
||||
define('pocketmine\PATH', 'dummy');
|
||||
}
|
||||
if(!defined('pocketmine\PLUGIN_PATH')){
|
||||
define('pocketmine\PLUGIN_PATH', 'dummy');
|
||||
}
|
||||
}
|
||||
|
||||
public function parseDocCommentNewlineProvider() : array{
|
||||
return [
|
||||
["\t/**\r\n\t * @param PlayerJoinEvent \$event\r\n\t * @priority HIGHEST\r\n\t * @notHandler\r\n\t */"],
|
||||
@ -47,4 +58,9 @@ class UtilsTest extends TestCase{
|
||||
self::assertArrayHasKey("priority", $tags);
|
||||
self::assertEquals("HIGHEST", $tags["priority"]);
|
||||
}
|
||||
|
||||
public function testNamespacedNiceClosureName() : void{
|
||||
//be careful with this test. The closure has to be declared on the same line as the assertion.
|
||||
self::assertSame('closure@' . Utils::cleanPath(__FILE__) . '#L' . __LINE__, Utils::getNiceClosureName(function(){}));
|
||||
}
|
||||
}
|
||||
|
Submodule tests/plugins/PocketMine-DevTools updated: 3f14ab5bb7...c0f0f9383d
Submodule tests/preprocessor updated: b87380457e...cab4e6ceb1
Reference in New Issue
Block a user