mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-11 03:58:06 +00:00
Compare commits
286 Commits
5.0.0-ALPH
...
5.0.0-ALPH
Author | SHA1 | Date | |
---|---|---|---|
023010370b | |||
de3ba00684 | |||
b47035fbab | |||
072a9202ef | |||
f0925ff9dc | |||
d9324b9951 | |||
1d9336ed67 | |||
d37142af4b | |||
7c068101b7 | |||
217f9aea02 | |||
2f5e08067d | |||
a8556dff02 | |||
664089861a | |||
7314151c47 | |||
7abfc46567 | |||
3a13f5cf5f | |||
edb8f19a0c | |||
6c0254c1eb | |||
0bb9fb09cc | |||
ab21fcdd67 | |||
d9b8251f7b | |||
ad6a423d12 | |||
b03df4f1e6 | |||
0a2a6e2b3a | |||
0eb751c1c9 | |||
b59b1e491e | |||
95e8c68fde | |||
7e16f9be8f | |||
768650cee0 | |||
c2c529e2da | |||
c55e23a2c6 | |||
5c2ed210fc | |||
289e86e899 | |||
7d59bafd83 | |||
950eddf405 | |||
1bbe053848 | |||
69967a0e55 | |||
0132ff47cb | |||
2ed48c8469 | |||
d786ed5ebf | |||
8909aa6a18 | |||
a9f06fc5f4 | |||
a14346e98c | |||
b76265cd37 | |||
dff3f45d22 | |||
1e17d86421 | |||
ba18a81e88 | |||
6dd006e730 | |||
b57fcb52d4 | |||
2c20b20ad2 | |||
329c2a6c0f | |||
39218017ca | |||
a4494a2133 | |||
fc487b17be | |||
ecd8f151f1 | |||
c671d8a80b | |||
ca1f1bf09f | |||
91ac47ecba | |||
f4a1d69075 | |||
cbeae906e1 | |||
b25e8e26f0 | |||
a79be994de | |||
e26c8b9e9f | |||
4e9c3e101d | |||
d295e1be54 | |||
2f3fcef97c | |||
4df1f7f502 | |||
d74719704e | |||
c5056e0a43 | |||
a47aa50477 | |||
5021096bdd | |||
9c391a6809 | |||
f7930a3a0b | |||
bb7df60a4d | |||
992cb06da6 | |||
bb3f87f862 | |||
d2eddf9d33 | |||
81ca0c8fbf | |||
fc77b14760 | |||
52b6f1a492 | |||
0233e74f4f | |||
dd355c58d8 | |||
267032cff9 | |||
545d18eea7 | |||
9b4b960eb2 | |||
d4b8c47a65 | |||
4a3d9f8f83 | |||
1c96e7936c | |||
c5ca0857ee | |||
6cecd690b2 | |||
91e38d1f97 | |||
653178c1fd | |||
eb06535ed1 | |||
f9bcc8e862 | |||
c2918709a3 | |||
ece49f011c | |||
f43ca405d4 | |||
d146175d27 | |||
3baa5ab712 | |||
e647e8c933 | |||
c02bead12b | |||
e9ca25c1cb | |||
a513cca582 | |||
9a47c1d401 | |||
433f5451d7 | |||
85231215e7 | |||
64e505defb | |||
33d1755eae | |||
fc63c54116 | |||
db07976aab | |||
0e4b79ea77 | |||
588c9b114b | |||
b095f606c1 | |||
b312e93176 | |||
42db3abf5e | |||
172ce659b8 | |||
61933624d2 | |||
0d31b25fba | |||
90beaeaeb4 | |||
466f7e98ed | |||
59be901efe | |||
2da9b76452 | |||
c79806eaf0 | |||
7ac6bd79a9 | |||
6b8b7311f0 | |||
f173b91ca1 | |||
9796dfd4d9 | |||
c1ba735c9e | |||
8fd4918429 | |||
c89df7eb1c | |||
0d169b4e80 | |||
b1c0eae1f6 | |||
80832ff763 | |||
f7d0d16eb3 | |||
6375139d0b | |||
a8edb92565 | |||
133884da72 | |||
b4c7d33388 | |||
d37841c214 | |||
2a81a421f3 | |||
567bd8abb5 | |||
3d038b28ff | |||
0c9b6a6797 | |||
639f089c55 | |||
9010b2743c | |||
4c91c4aaf1 | |||
f8cc015c51 | |||
17125ce0e3 | |||
3987ee6cb2 | |||
51a684c0ea | |||
43e69041fc | |||
5d2b0acfc8 | |||
7d1d62042c | |||
2a33c9ed3b | |||
b03733442b | |||
9c9929ff39 | |||
566a8a261f | |||
a9e5f92958 | |||
17dde140a5 | |||
b3473960b4 | |||
044d35956e | |||
da4315df05 | |||
83bfe790fa | |||
ee7d4728d8 | |||
923dcec4e7 | |||
1e5597f0d5 | |||
aebcfc516f | |||
97ef209c5f | |||
16f90f4120 | |||
ec59dc1c80 | |||
973b8130db | |||
99faeb8d05 | |||
1305fd5fb2 | |||
7a137f932f | |||
63e8b1cf3a | |||
65bce762ff | |||
529700bb8b | |||
f38b15cf83 | |||
0efd928db6 | |||
9809909072 | |||
de3af9e660 | |||
a30c649607 | |||
d7ebabd771 | |||
be1087c071 | |||
b27c47335c | |||
58eec637c1 | |||
4f86ea9933 | |||
6e2685cbbb | |||
b2017c8462 | |||
bf44edd179 | |||
44e288554a | |||
ffa88aff67 | |||
aa374083d8 | |||
1785cbb6b5 | |||
3d75094874 | |||
8c0d3943d8 | |||
d02c6668b2 | |||
880d01daea | |||
50b70708fb | |||
ba4d038972 | |||
437fa615b8 | |||
0ee6cdb058 | |||
97d6a79b25 | |||
8b5e4c1c16 | |||
c5d716dc9d | |||
4d79aced07 | |||
95d0a3bf41 | |||
cf707e15c2 | |||
1308cda5c2 | |||
214a5ddc15 | |||
9f7dfe3355 | |||
9b55d18393 | |||
84f9136b95 | |||
31465525e3 | |||
74613b9b09 | |||
1cefe24414 | |||
4357c110c8 | |||
8bf85d4a18 | |||
b5e6dec0c6 | |||
a3306914cc | |||
3b32ea1b0b | |||
7ec32f981e | |||
b0c87e9d06 | |||
99996b62d6 | |||
fed2a6d917 | |||
8e600b4a78 | |||
1d4b6dc66e | |||
1cb6d9f5af | |||
18c2e90574 | |||
142ccc7e87 | |||
174c9a48f5 | |||
0a9b52618d | |||
7ae6425d05 | |||
b5cfab497d | |||
ca3b5c38b7 | |||
bc8def3be1 | |||
774e23137e | |||
3984d220bb | |||
43bc3c7b25 | |||
eb62dc3294 | |||
28d8526d8d | |||
0b497654f2 | |||
279056fe2f | |||
cd233b123b | |||
64dd5e3bf6 | |||
4e5cc57560 | |||
d476a4c1aa | |||
95263795a8 | |||
2db86d151f | |||
8f20b9da91 | |||
b0c6e8d8e0 | |||
f0358b09b7 | |||
80a432d9ff | |||
ec9f9a469f | |||
d450264e1c | |||
5e92f55d35 | |||
58c1bfe5d2 | |||
d03caafc2b | |||
641d35a30f | |||
642630a4d2 | |||
b6982a84ef | |||
d634b3de18 | |||
d79e6354a0 | |||
ff63983de4 | |||
588215044e | |||
5c1e9a35a9 | |||
aad9f5fb45 | |||
a8dca190c6 | |||
fdb07cdbcd | |||
3b6ff3c42b | |||
e5f5fe80f9 | |||
36ab34df29 | |||
23ae0c7cac | |||
1bc5e225ab | |||
dda8ff18b1 | |||
6562335120 | |||
0c463a8721 | |||
a66f966b08 | |||
cca22046ab | |||
858d3dce8e | |||
d19f0bf7be | |||
ff2391e74a | |||
39e10da88d | |||
34839da757 | |||
b3b8516661 | |||
9650b7f03a |
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@ -6,6 +6,12 @@ updates:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
#only allow patch updates for locale-data - this has to be updated manually due to codegen
|
||||
- dependency-name: pocketmine/locale-data
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- "version-update:semver-minor"
|
||||
|
||||
- package-ecosystem: gitsubmodule
|
||||
directory: "/"
|
||||
|
8
.github/workflows/build-docker-image.yml
vendored
8
.github/workflows/build-docker-image.yml
vendored
@ -46,7 +46,7 @@ jobs:
|
||||
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v3.2.0
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.2.0
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -72,7 +72,7 @@ jobs:
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.2.0
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -85,7 +85,7 @@ jobs:
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.2.0
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.22.0
|
||||
uses: shivammathur/setup-php@2.23.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
|
7
.github/workflows/draft-release.yml
vendored
7
.github/workflows/draft-release.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.22.0
|
||||
uses: shivammathur/setup-php@2.23.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
@ -55,6 +55,7 @@ jobs:
|
||||
echo ::set-output name=MCPE_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;')
|
||||
echo ::set-output name=PM_VERSION_SHORT::$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);')
|
||||
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);')
|
||||
echo ::set-output name=CHANGELOG_SUFFIX::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;')
|
||||
|
||||
- name: Generate build info
|
||||
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} ${{ github.run_id }} > build_info.json
|
||||
@ -69,7 +70,7 @@ jobs:
|
||||
${{ github.workspace }}/build_info.json
|
||||
|
||||
- name: Create draft release
|
||||
uses: ncipollo/release-action@v1.11.1
|
||||
uses: ncipollo/release-action@v1.12.0
|
||||
with:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||
commit: ${{ github.sha }}
|
||||
@ -80,4 +81,4 @@ jobs:
|
||||
body: |
|
||||
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
|
||||
|
||||
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
|
||||
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}${{ steps.get-pm-version.outputs.CHANGELOG_SUFFIX }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
|
||||
|
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -198,10 +198,12 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.22.0
|
||||
uses: shivammathur/setup-php@2.23.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
tools: php-cs-fixer:3.11
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Run PHP-CS-Fixer
|
||||
run: php-cs-fixer fix --dry-run --diff --ansi
|
||||
|
2
.github/workflows/support.yml
vendored
2
.github/workflows/support.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
||||
support:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/support-requests@v2
|
||||
- uses: dessant/support-requests@v3
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
support-label: "Support request"
|
||||
|
5
.idea/codeStyles/Project.xml
generated
5
.idea/codeStyles/Project.xml
generated
@ -62,6 +62,11 @@
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Shell Script">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="neon">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
|
@ -66,6 +66,9 @@ BODY,
|
||||
],
|
||||
'indentation_type' => true,
|
||||
'logical_operators' => true,
|
||||
'native_constant_invocation' => [
|
||||
'scope' => 'namespaced'
|
||||
],
|
||||
'native_function_invocation' => [
|
||||
'scope' => 'namespaced',
|
||||
'include' => ['@all'],
|
||||
@ -92,6 +95,12 @@ BODY,
|
||||
],
|
||||
'sort_algorithm' => 'alpha'
|
||||
],
|
||||
'phpdoc_align' => [
|
||||
'align' => 'vertical',
|
||||
'tags' => [
|
||||
'param',
|
||||
]
|
||||
],
|
||||
'phpdoc_line_span' => [
|
||||
'property' => 'single',
|
||||
'method' => null,
|
||||
|
@ -48,6 +48,8 @@ use function sort;
|
||||
use function strrpos;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
use const SORT_STRING;
|
||||
use const STDERR;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
|
@ -36,6 +36,8 @@ use function file_get_contents;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function strtoupper;
|
||||
use const SORT_STRING;
|
||||
use const STDERR;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
|
@ -36,9 +36,10 @@ use function ksort;
|
||||
use function mb_strtoupper;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function str_ends_with;
|
||||
use function str_replace;
|
||||
use function substr;
|
||||
use const SORT_STRING;
|
||||
use const STDERR;
|
||||
|
||||
if(count($argv) !== 2){
|
||||
fwrite(STDERR, "Provide a path to process\n");
|
||||
@ -120,7 +121,7 @@ require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
if(is_dir($argv[1])){
|
||||
/** @var string $file */
|
||||
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $file){
|
||||
if(substr($file, -4) !== ".php"){
|
||||
if(!str_ends_with($file, ".php")){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\block\utils\LeverFacing;
|
||||
use pocketmine\block\utils\MushroomBlockType;
|
||||
use pocketmine\block\utils\SkullType;
|
||||
use pocketmine\block\utils\SlabType;
|
||||
use pocketmine\item\MedicineType;
|
||||
use pocketmine\item\PotionType;
|
||||
use pocketmine\item\SuspiciousStewType;
|
||||
use function array_key_first;
|
||||
@ -48,6 +49,7 @@ use function lcfirst;
|
||||
use function log;
|
||||
use function ob_get_clean;
|
||||
use function ob_start;
|
||||
use const SORT_STRING;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
@ -165,6 +167,7 @@ $enumsUsed = [
|
||||
DyeColor::getAll(),
|
||||
FroglightType::getAll(),
|
||||
LeverFacing::getAll(),
|
||||
MedicineType::getAll(),
|
||||
MushroomBlockType::getAll(),
|
||||
SkullType::getAll(),
|
||||
SlabType::getAll(),
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\make_release;
|
||||
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
use pocketmine\VersionInfo;
|
||||
@ -30,7 +31,6 @@ use function array_keys;
|
||||
use function array_map;
|
||||
use function dirname;
|
||||
use function fgets;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function fwrite;
|
||||
use function getopt;
|
||||
@ -50,7 +50,7 @@ use const STR_PAD_LEFT;
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev, string $channel) : void{
|
||||
$versionInfo = Utils::assumeNotFalse(file_get_contents($versionInfoPath), $versionInfoPath . " should always exist");
|
||||
$versionInfo = Filesystem::fileGetContents($versionInfoPath);
|
||||
$versionInfo = preg_replace(
|
||||
$pattern = '/^([\t ]*public )?const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m',
|
||||
'$1const BASE_VERSION = "' . $newVersion . '";',
|
||||
|
Submodule build/php updated: 14ed8eaadd...6b605ed7c4
@ -40,12 +40,13 @@ use function rtrim;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function unlink;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_EOL;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* @param string[] $strings
|
||||
* @param string[] $strings
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
|
@ -36,3 +36,18 @@ Released 7th November 2022.
|
||||
- Added validation for the array given to `BaseInventory->setContents()` to ensure that it contains only `Item` instances.
|
||||
- Silenced `PlayerAuthInputPacket` spam when the session is in the "spawn response" state.
|
||||
- Updated to PHPStan 1.9.
|
||||
|
||||
# 4.10.2
|
||||
Released 25th November 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed crashes on macOS and Linux when using console colours without the `TERM` environment variable set.
|
||||
- Fixed crashdumps not being generated when error messages contained invalid UTF-8 characters.
|
||||
|
||||
## Documentation
|
||||
- Clarified documentation of caching behaviour for `Internet::getIP()`.
|
||||
- Added and improved documentation for many `Inventory` methods.
|
||||
- Rewritten documentation for `PlayerCreationEvent` with warnings and more detail.
|
||||
|
||||
## Internals
|
||||
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.
|
||||
|
106
changelogs/4.11.md
Normal file
106
changelogs/4.11.md
Normal file
@ -0,0 +1,106 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.40**
|
||||
|
||||
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.11.0
|
||||
Released 25th November 2022.
|
||||
|
||||
## General
|
||||
- Packet receive timings have now been split into two subcategories - Decode and Handle.
|
||||
- Console command entry can now be disabled via the `console.enable-input` setting in `pocketmine.yml`.
|
||||
- Best suited for headless servers (e.g. in a Docker container) where the console will never be used anyway.
|
||||
- Disabling the console reader slightly reduces memory usage, because console reading currently requires an additional subprocess.
|
||||
- Console command output now appears on the terminal only, and is not written to the log file.
|
||||
- The output from console commands now appears with a `Command output |` prefix, instead of as a log message.
|
||||
- User-defined `pocketmine.yml` custom commands now use a generic description which makes clear the command is config-defined.
|
||||
- Introduced validation for the `--data` and `--plugins` command line options.
|
||||
- Encrypted resource packs are now supported, by means of adding a `.key` file alongside the pack in the `resource_packs` folder.
|
||||
- e.g. `MyEncryptedPack.zip` -> `MyEncryptedPack.zip.key`
|
||||
- The file must contain the raw key bytes, and must not end with a newline.
|
||||
|
||||
## Configuration
|
||||
- The `chunk-ticking.per-tick` setting is now deprecated, and will be removed in a future release.
|
||||
- The functionality of this setting has been removed, since it caused more problems than it solved.
|
||||
- Setting it to zero will still disable chunk ticking (for now), but this should now be done by setting `chunk-ticking.tick-radius` to `0` instead.
|
||||
|
||||
## Gameplay
|
||||
- Fixed supporting blocks of dead bush to be in line with vanilla.
|
||||
- Sugarcane can now be grown using bonemeal on any part of the sugarcane. Previously, it only worked when used on the bottom block.
|
||||
- Fixed missing sounds when adding, rotating, or removing items in item frames.
|
||||
- Fixed modifier values for Instant Damage and Regeneration effects.
|
||||
- Implemented Darkness effect.
|
||||
- Improved chunk random ticking:
|
||||
- Removed the limit on chunks ticked per tick, and its associated config option is no longer respected.
|
||||
- This change significantly improves crop and plant growth with large numbers of players.
|
||||
- This limit was causing a linear decrease in chunk ticking speed with larger numbers of players, leading to worsened gameplay experience.
|
||||
- **Warning: This change will result in increased CPU usage if players are spread over a very large area.**
|
||||
- Every chunk within the configured tick radius of a player will be ticked. Previously, chunks were randomly selected from the radius.
|
||||
|
||||
## API
|
||||
### General
|
||||
- Plugins are now always disabled before their dependencies, to ensure that they are able to shutdown properly (e.g. a core plugin depending on a database plugin may want to save data to a DB during `onDisable()`).
|
||||
- [`webmozart/path-util`](https://packagist.org/packages/webmozart/path-util) has been deprecated, and will be dropped in favour of [`symfony/filesystem`](https://packagist.org/packages/symfony/filesystem) in PM5.
|
||||
- To prepare for this change, simply replace any usage of `Webmozart\PathUtil\Path` with `Symfony\Component\Filesystem\Path`, which is available as a dependency in this release.
|
||||
|
||||
### `pocketmine`
|
||||
- The following API methods are now deprecated:
|
||||
- `Server->getPlayerByPrefix()`
|
||||
|
||||
### `pocketmine\entity`
|
||||
- `EntitySpawnEvent` and `ItemSpawnEvent` are now fired on the first tick after the entity is added to the world. Previously, these events were called directly from the entity constructor, making it impossible to get properties like velocity which are often set after the entity is created.
|
||||
- The following API methods are now deprecated:
|
||||
- `Living->hasLineOfSight()`
|
||||
|
||||
### `pocketmine\event\block`
|
||||
- The following new classes have been added:
|
||||
- `BlockDeathEvent` - event called when coral or coral blocks die due to lack of water
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Armor->clearCustomColor() : $this`
|
||||
|
||||
### `pocketmine\inventory\transaction`
|
||||
- Introduced a `TransactionBuilder` class. This makes it less of a hassle to build an `InventoryTransaction` server-side, since the regular `Inventory` API methods can be used, rather than having to manually create `SlotChangeAction`s.
|
||||
|
||||
### `pocketmine\lang`
|
||||
- The following new API methods have been added:
|
||||
- `public Language->getAll() : array<string, string>`
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following new API methods have been added:
|
||||
- `public Player->sendToastNotification(string $title, string $body) : void` - makes a grey box appear at the top of the player's screen containing the specified message
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public static TextFormat::addBase(string $baseFormat, string $string) : string` - used for coloured log messages, changes the base formatting of a string by inserting the given formatting codes after every RESET code
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following new API methods have been added:
|
||||
- `public World->getChunkTickRadius() : int` - returns the world's simulation radius
|
||||
- `public World->setChunkTickRadius(int $radius) : void` - sets the world's simulation radius
|
||||
|
||||
### `pocketmine\world\sound`
|
||||
- The following new classes have been added:
|
||||
- `ItemFrameAddItemSound`
|
||||
- `ItemFrameRemoveItemSound`
|
||||
- `ItemFrameRotateItemSound`
|
||||
|
||||
## Internals
|
||||
- Improved performance of `ContainerTrait` dropping items on block destroy. ([link](https://github.com/pmmp/PocketMine-MP/commits/24e72ec109c1442b09558df89b6833cf2f2e0ec7))
|
||||
- Avoid repeated calls to `Position->getWorld()` (use local variables). ([link](https://github.com/pmmp/PocketMine-MP/commit/2940547026db40ce76deb46e992870de3ead79ad))
|
||||
- Revamped the way `InventoryManager` handles fake inventory slot mappings for stuff like crafting tables. ([link](https://github.com/pmmp/PocketMine-MP/commit/e90abecf38d9c57635fa0497514bba7e546a2469))
|
||||
- Inventories are now mapped on a per-slot basis. This means that more than one inventory can be mapped to the same window ID, which is necessary for correctly handling "UI" inventories like crafting tables.
|
||||
- `InventoryManager->getWindow(int $windowId) : ?Inventory` is replaced by `locateWindowAndSlot` (see below).
|
||||
- Added `InventoryManager->locateWindowAndSlot(int $windowId, int $netSlotId) : array{Inventory, int}` - accepts a window ID and absolute slot ID, and returns the associated inventory and the slot relative to the inventory's own start (for use with `getItem()` etc.).
|
||||
- Slot offset mapping for "UI" inventories is now handled in `InventoryManager->createComplexSlotMapping()` instead of in `TypeConverter`.
|
||||
- Console polling is now done on the main thread (no longer a performance concern). ([link](https://github.com/pmmp/PocketMine-MP/commit/b3f03d7ae645de67a54b7300c09b94eeca16298e))
|
||||
- Console reader subprocess should now automatically die if the server main process is killed, instead of persisting as a zombie. ([link](https://github.com/pmmp/PocketMine-MP/commit/2585160ca2c4df5758b8b980331307402ff9f0fb))
|
||||
- `ConsoleCommandSender` is no longer responsible for relaying broadcast messages to `MainLogger`. A new `BroadcastLoggerForwarder` has been added, which is subscribed to the appropriate server broadcast channels in order to relay messages. This ensures that chat messages and command audit messages are logged. ([link](https://github.com/pmmp/PocketMine-MP/commit/83e5b0adb6fa0dddec377182bb1c7945ac8f7820))
|
||||
- `DelegateInventory` now uses `WeakReference` to track its inventory listener. This allows the delegate to be reused. ([link](https://github.com/pmmp/PocketMine-MP/commit/3feaa18f6c10c3a99c0deca75f57ec2d74b92ab4))
|
||||
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.
|
106
changelogs/4.12.md
Normal file
106
changelogs/4.12.md
Normal file
@ -0,0 +1,106 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.50**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.12.0
|
||||
Released 30th November 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.50.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.12.1
|
||||
Released 4th December 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed items glitching when dragging a stack of items across the crafting grid (desync issues).
|
||||
|
||||
# 4.12.2
|
||||
Released 15th December 2022.
|
||||
|
||||
## Fixes
|
||||
- Folder used for plugins (optionally specified by `--plugins`) is no longer required to be writable.
|
||||
- Fixed broken writable check for server data folder (`is_writable()` broken on NFS and similar filesystems).
|
||||
- `Filesystem::createLockFile()` exceptions now include more information about why the lock file could not be created.
|
||||
- Fixed client-side item predictions not being rolled back when cancelling events such as `PlayerItemUseEvent`.
|
||||
|
||||
## Dependencies
|
||||
- Updated BedrockProtocol to [17.1.0](https://github.com/pmmp/BedrockProtocol/releases/tag/17.1.0+bedrock-1.19.50). This adds some missing `LevelSoundEvent` constants and fixes the values for `ContainerUIIds`.
|
||||
|
||||
# 4.12.3
|
||||
Released 28th December 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed unauthenticated connections taking up player count slots, preventing players from joining.
|
||||
- Fixed a possible crash in `World->tickChunk()` when plugins unload chunks during some events.
|
||||
- `/gamemode` will now report a failure to change game mode if the player is already in the requested game mode.
|
||||
|
||||
# 4.12.4
|
||||
Released 3rd January 2023.
|
||||
|
||||
## Fixes
|
||||
- Added workarounds for an active exploit being used to deny service to servers.
|
||||
|
||||
# 4.12.5
|
||||
Released 6th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Removed a workaround for an old client bug in custom form responses. The code contained a denial-of-service vulnerability.
|
||||
|
||||
# 4.12.6
|
||||
Released 7th January 2023.
|
||||
|
||||
## Changes
|
||||
- Added a new security measure to `NetworkSession` to detect and ban players who flood the server with packets.
|
||||
|
||||
# 4.12.7
|
||||
Released 8th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed players getting kicked when the server lags for too long.
|
||||
- Fixed players getting kicked when a debugging session is active and a breakpoint is hit.
|
||||
|
||||
# 4.12.8
|
||||
Released 9th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed players getting kicked during PvP.
|
||||
- Fixed players randomly getting kicked on Windows (improper rate limit handling wrt. 15ms timer resolution).
|
||||
|
||||
# 4.12.9
|
||||
Released 16th January 2023.
|
||||
|
||||
## Improvements
|
||||
### Timings
|
||||
- Added new timers:
|
||||
- `Server Mid-Tick Processing` - time spent processing Snooze interrupts between ticks (e.g. incoming network packets)
|
||||
- `Server Tick Update Cycle` - time spent processing regular per-tick updates (e.g. entity movement, world updates, etc.) (`Server->tick()`)
|
||||
- `Full Server Tick` timer now counts the total of `Server Mid-Tick Processing` and `Server Tick Update Cycle`, which generates more accurate performance metrics.
|
||||
- Previously, this timer only counted the time spent during regular per-tick updates, and the time recorded by `Server Mid-Tick Processing` was not included in the report at all.
|
||||
|
||||
## Fixes
|
||||
- Fixed blocks such as pressure plates being able to be placed without the correct supporting blocks if the clicked block was solid.
|
||||
- Pressure plates now self-destruct when the block below them is removed.
|
||||
- Fixed being unable to place blocks by clicking on the side of a bell (when the click doesn't result in ringing the bell).
|
||||
- Fixed various rotation-aware blocks (e.g. stairs) behaving incorrectly when placed by clicking on the side of a replaceable block (e.g. tall grass).
|
||||
- Fixed banners being able to be placed on top of blocks such as skulls.
|
||||
- Fixed server-side collision boxes of walls and glass (which should connect, but didn't). Note that wall connections still don't show client side - this just fixes the collision boxes.
|
||||
- Fixed `PlayerInteractEvent` with `LEFT_CLICK` sometimes firing before `BlockBreakEvent` when breaking blocks.
|
||||
|
||||
## Other changes
|
||||
- Increased packet batch budget for player sessions.
|
||||
|
||||
# 4.12.10
|
||||
Released 18th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed reported server load not including the time spent processing Snooze interrupts between ticks (e.g. incoming network packets).
|
||||
- Fixed `Connection Handler` entry in timings report not including time spent receiving packets.
|
||||
|
||||
## Note about server load & performance
|
||||
This version will report higher apparent server load than previous versions. The actual performance of the server is unchanged; the previous reported load was inaccurate.
|
||||
These bugs have been present for nearly 5 years (ever since the first introduction of Snooze in 3.0.0).
|
94
changelogs/4.13-beta.md
Normal file
94
changelogs/4.13-beta.md
Normal file
@ -0,0 +1,94 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.50**
|
||||
|
||||
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.13.0-BETA1
|
||||
Released 18th January 2023.
|
||||
|
||||
## Gameplay
|
||||
- Death message is now shown on the death screen when a player dies.
|
||||
- Armour damage is now only increased if the armour reduced the damage taken.
|
||||
- Implemented Swift Sneak enchantment.
|
||||
- Fixed incorrect collision box calculation of walls and glass/bars when connected. Note: Client-side, wall connections are still broken; this only fixes projectile flight server-side.
|
||||
|
||||
## Performance
|
||||
- Improved performance of chunk selection for chunk random ticking using a cache. This improves performance of chunk random ticking by 10-20%.
|
||||
|
||||
## Localization
|
||||
- Added localized description for the `/dumpmemory` command.
|
||||
|
||||
## Permissions
|
||||
- Added the following new core permissions:
|
||||
- `pocketmine.command.effect.other` - allows the player to use the `/effect` command on other players (default operator only)
|
||||
- `pocketmine.command.effect.self` - allows the player to use the `/effect` command on themselves (default operator only)
|
||||
- `pocketmine.command.enchant.other` - allows the player to use the `/enchant` command on other players (default operator only)
|
||||
- `pocketmine.command.enchant.self` - allows the player to use the `/enchant` command on themselves (default operator only)
|
||||
- `pocketmine.command.gamemode.other` - allows the player to use the `/gamemode` command on other players (default operator only)
|
||||
- `pocketmine.command.gamemode.self` - allows the player to use the `/gamemode` command on themselves (default operator only)
|
||||
- `pocketmine.command.give.other` - allows the player to use the `/give` command on other players (default operator only)
|
||||
- `pocketmine.command.give.self` - allows the player to use the `/give` command on themselves (default operator only)
|
||||
- `pocketmine.command.spawnpoint.other` - allows the player to use the `/spawnpoint` command on other players (default operator only)
|
||||
- `pocketmine.command.spawnpoint.self` - allows the player to use the `/spawnpoint` command on themselves (default operator only)
|
||||
- `pocketmine.command.teleport.other` - allows the player to use the `/teleport` command on other players (default operator only)
|
||||
- `pocketmine.command.teleport.self` - allows the player to use the `/teleport` command on themselves (default operator only)
|
||||
- `pocketmine.command.title.other` - allows the player to use the `/title` command on other players (default operator only)
|
||||
- `pocketmine.command.title.self` - allows the player to use the `/title` command on themselves (default operator only)
|
||||
|
||||
## Internals
|
||||
- Decoupled `Player->sendMessage()` and `Player->sendTranslation()`.
|
||||
- Refactored resource pack loading in `ResourcePackManager` to make it easier to understand.
|
||||
- Client-aware translation processing has been moved to `NetworkSession` due to being client-specific.
|
||||
- Replaced hardcoded strings with constants in various places.
|
||||
- `NetworkSession` destructive cleanup is now deferred to the next session tick. This fixes various `InventoryManager` crashes when kicking players during events.
|
||||
- Updated code using `strpos()` to use `str_starts_with()`, `str_ends_with()` and `str_contains()` where appropriate.
|
||||
- Added documentation for some internal methods.
|
||||
|
||||
## API
|
||||
### `pocketmine\command`
|
||||
- The following new API methods have been added:
|
||||
- `protected VanillaCommand->fetchPermittedPlayerTarget(...) : ?Player` - fetches a player target according to the given sender permissions, or null if not found or not permitted
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Living->getDisplayName() : string` - the name of the entity to be shown in death messages, commands etc.
|
||||
|
||||
### `pocketmine\event\world`
|
||||
- The following new classes have been added:
|
||||
- `WorldSoundEvent` - called when a sound is played in a world
|
||||
- `WorldParticleEvent` - called when a particle is spawned in a world
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Item->onInteractEntity(Player $player, Entity $entity, Vector3 $clickVector) : bool` - called when a player interacts with an entity with this item in hand
|
||||
|
||||
### `pocketmine\lang`
|
||||
- `Language->translate()` and `Language->translateString()` no longer parse nested translation in the "base text". This was never intended behaviour, and didn't work beyond the first level anyway.
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following new interfaces have been added:
|
||||
- `PlayerDataProvider` - implemented by classes which want to offer storage for player data
|
||||
- The following new classes have been added:
|
||||
- `DatFilePlayerDataProvider` - the default player data provider, which stores `.dat` files in the `players` folder
|
||||
- `PlayerDataLoadException` - thrown when an error occurs while loading player data
|
||||
- `PlayerDataSaveException` - thrown when an error occurs while saving player data
|
||||
- The following API methods have been deprecated:
|
||||
- `Player->sendTranslation()` - use `Player->sendMessage()` instead with a `Translatable` message
|
||||
|
||||
### `pocketmine\resourcepacks`
|
||||
- The following new API methods have been added:
|
||||
- `public ResourcePackManager->setResourceStack(list<ResourcePack> $resourceStack) : void` - sets the list of resource packs to be applied by players
|
||||
- `public ResourcePackManager->setPackEncryptionKey(string $id, ?string $key) : void` - sets the encryption key to be used for a resource pack
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public static Filesystem::fileGetContents(...) : string` - a wrapper around `file_get_contents()` which throws an exception on failure
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following new API methods have been added:
|
||||
- `public World->requestSafeSpawn(?Vector3 $spawn = null) : Promise<Position>` - an async version of `getSafeSpawn()` which generates all the needed chunks before returning
|
@ -646,4 +646,226 @@ Released 13th November 2022.
|
||||
- Copper blocks now play the correct scrape sound when using an axe on them.
|
||||
|
||||
## Internals
|
||||
- Moved command timings to `Timings`.
|
||||
- Moved command timings to `Timings`.
|
||||
|
||||
# 5.0.0-ALPHA6
|
||||
Released 19th December 2022.
|
||||
|
||||
**This release includes changes from the following releases, which may not be mentioned:**
|
||||
- [4.10.2](https://github.com/pmmp/PocketMine-MP/releases/tag/4.10.2)
|
||||
- [4.11.0](https://github.com/pmmp/PocketMine-MP/releases/tag/4.11.0)
|
||||
- [4.12.0](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.0)
|
||||
- [4.12.1](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.1)
|
||||
- [4.12.2](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.2)
|
||||
|
||||
## General
|
||||
- Fixed the Bedrock client asking to upgrade worlds exported from PocketMine-MP to Bedrock (missing level.dat fields).
|
||||
- Added support for 1.19.40 and newer Bedrock worlds.
|
||||
- Commands are now enabled by default in worlds exported from PocketMine-MP to Bedrock.
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Added the following new blocks:
|
||||
- Twisting Vines
|
||||
- Weeping Vines
|
||||
- Anvils are now damaged when they hit the ground after falling.
|
||||
- Added missing sounds for anvils hitting the ground after falling.
|
||||
- Fixed missing sounds when a projectile strikes an amethyst block.
|
||||
- Fixed some blocks being incorrectly able to be placed on top of a candle cake.
|
||||
|
||||
### Items
|
||||
- Added the following new items:
|
||||
- Music Disc (5)
|
||||
- Music Disc (Otherside)
|
||||
- Music Disc (Pigstep)
|
||||
- Implemented Swift Sneak enchantment.
|
||||
- Armour durability is now only reduced when the wearer receives a type of damage that the armour can protect against.
|
||||
|
||||
## API
|
||||
### General
|
||||
- Union and mixed native parameter, return and property types are now used where appropriate.
|
||||
|
||||
### `pocketmine\block`
|
||||
- The following new API methods have been added:
|
||||
- `public Furnace->getType() : utils\FurnaceType`
|
||||
- The following interfaces have new requirements:
|
||||
- `utils\Fallable` now requires `onHitGround()` to be implemented (although filled by default implementation in `FallableTrait`).
|
||||
- `utils\Fallable` now requires `getLandSound()` to be implemented (although filled by default implementation in `FallableTrait`).
|
||||
- The following new API constants have been added:
|
||||
- `public BlockTypeTags::FIRE` - used by fire and soul fire
|
||||
|
||||
### `pocketmine\crafting`
|
||||
- The `$type` parameter of `ShapelessRecipe->__construct()` is now mandatory.
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Living->getDisplayName() : string`
|
||||
- The following API methods have changed signatures:
|
||||
- `EntityFactory->register()` no longer accepts a `$legacyMcpeSaveId` parameter (now handled by internal conversions instead).
|
||||
|
||||
### `pocketmine\event`
|
||||
- The following classes have been renamed:
|
||||
- `entity\ExplosionPrimeEvent` -> `entity\EntityPreExplodeEvent`
|
||||
- The following new classes have been added:
|
||||
- `world\WorldParticleEvent` - called when a particle is spawned in a world
|
||||
- `world\WorldSoundEvent` - called when a sound is played in a world
|
||||
- The following API methods have changed signatures:
|
||||
- `entity\EntityPreExplodeEvent->__construct()` has the `$force` parameter renamed to `$radius`
|
||||
- `entity\EntityPreExplodeEvent->getForce() : float` -> `entity\EntityPreExplodeEvent->getRadius() : float`
|
||||
- `entity\EntityPreExplodeEvent->setForce(float $force) : void` -> `entity\EntityPreExplodeEvent->setRadius(float $radius) : void`
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Item->keepOnDeath() : bool` - returns whether this item will be retained when a player carrying it dies
|
||||
- `public Item->onInteractEntity(Player $player, Entity $entity, Vector3 $clickPos) : bool` - called when a player interacts with an entity with this item in their hand
|
||||
- `public Item->setKeepOnDeath(bool $keepOnDeath) : void` - sets whether this item will be retained when a player carrying it dies
|
||||
- `public StringToItemParser->lookupAliases(Item $item) : list<string>` - returns a list of all registered aliases for the given item
|
||||
- `public StringToItemParser->lookupBlockAliases(Block $block) : list<string>` - returns a list of all registered aliases for the given block
|
||||
|
||||
### `pocketmine\resourcepacks`
|
||||
- The following new API methods have been added:
|
||||
- `public ResourcePackManager->setPackEncryptionKey(string $id, ?string $key) : void` - sets the encryption key to be used for the resource pack identified by the given UUID
|
||||
- `public ResourcePackManager->setResourceStack(list<ResourcePack> $resourceStack) : void` - sets the resource stack to be used by the server
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following API methods have changed signatures:
|
||||
- `Explosion->__construct()` has the `$size` parameter renamed to `$radius`
|
||||
- The following public properties have been renamed:
|
||||
- `Explosion->size` -> `Explosion->radius`
|
||||
|
||||
## Internals
|
||||
- `EntityLegacyIds` has been removed. Legacy entity IDs found during world loading are now converted via `LegacyEntityIdToStringIdMap`.
|
||||
- All usages of NBT keys now use class constants instead of hardcoded strings (except for an occasional overlooked one).
|
||||
- All members of `BlockTypeTags` now have a `pocketmine:` prefix on the value. This does not affect constant usages.
|
||||
|
||||
# 5.0.0-ALPHA7
|
||||
Released 18th January 2023.
|
||||
|
||||
**This release includes changes from the following releases, which may not be mentioned:**
|
||||
- [4.12.3](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.3)
|
||||
- [4.12.4](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.4)
|
||||
- [4.12.5](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.5)
|
||||
- [4.12.6](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.6)
|
||||
- [4.12.7](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.7)
|
||||
- [4.12.8](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.8)
|
||||
- [4.12.9](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.9)
|
||||
- [4.12.10](https://github.com/pmmp/PocketMine-MP/releases/tag/4.12.10)
|
||||
- [4.13.0-BETA1](https://github.com/pmmp/PocketMine-MP/releases/tag/4.13.0-BETA1)
|
||||
|
||||
## Fixes
|
||||
- Fixed glowing item frame placement creating the wrong tile, causing invisible items.
|
||||
|
||||
## Localization
|
||||
- Localized disconnect messages are now used in the following cases:
|
||||
- Server full
|
||||
- Player not on the server whitelist
|
||||
- Player on the server ban list
|
||||
- Invalid skin
|
||||
- Invalid username
|
||||
- Kicked using `/kick`
|
||||
- Banned using `/ban`
|
||||
- Failure to find a safe spawn position
|
||||
- Session open, session close and session player name discovery messages are now localized.
|
||||
- All permissions now have localized descriptions. These are not currently used by PocketMine-MP, but may be useful for plugins.
|
||||
|
||||
## Gameplay
|
||||
### Worlds
|
||||
- Added support for 3D biomes. This isn't used by PocketMine-MP yet, but is necessary to be able to fully load 1.18 worlds.
|
||||
|
||||
### Blocks
|
||||
- Added the following new blocks:
|
||||
- Chain
|
||||
- Sculk
|
||||
|
||||
### Items
|
||||
- Added the following new items:
|
||||
- Eye Drops (from Education Edition)
|
||||
- Antidote (from Education Edition)
|
||||
- Elixir (from Education Edition)
|
||||
- Tonic (from Education Edition)
|
||||
|
||||
## API
|
||||
### Overview
|
||||
- Biome-related APIs have changed to accommodate 3D biomes.
|
||||
- Disconnect-related APIs have changed to accommodate localized disconnect messages.
|
||||
- New, more powerful chat formatting API introduced to `PlayerChatEvent`.
|
||||
- Glowing item frames moved to a separate block type instead of being a property of regular item frames (due to technical limitations).
|
||||
|
||||
### `pocketmine\block`
|
||||
- The following API methods have been removed:
|
||||
- `ItemFrame->isGlowing() : bool`
|
||||
- `ItemFrame->setGlowing(bool $glowing) : void`
|
||||
- The following new API methods have been added:
|
||||
- `public static VanillaBlocks::GLOWING_ITEM_FRAME() : ItemFrame`
|
||||
- The following constants have been added:
|
||||
- `BlockTypeIds::GLOWING_ITEM_FRAME`
|
||||
- `BlockTypeIds::CHAIN`
|
||||
- `BlockTypeIds::SCULK`
|
||||
- The following new classes have been added:
|
||||
- `Chain`
|
||||
- `Sculk`
|
||||
|
||||
### `pocketmine\event\player`
|
||||
- The following API methods have changed signatures:
|
||||
- `PlayerDuplicateLoginEvent->getDisconnectMessage()` now returns `Translatable|string` instead of `string`
|
||||
- `PlayerDuplicateLoginEvent->setDisconnectMessage()` now accepts `Translatable|string` instead of `string`
|
||||
- `PlayerKickEvent->getReason()` now returns `Translatable|string` instead of `string`
|
||||
- `PlayerKickEvent->setReason()` now accepts `Translatable|string` instead of `string`
|
||||
- `PlayerLoginEvent->getKickMessage()` now returns `Translatable|string` instead of `string`
|
||||
- `PlayerLoginEvent->setKickMessage()` now accepts `Translatable|string` instead of `string`
|
||||
- `PlayerPreLoginEvent->getFinalKickMessage()` now returns `Translatable|string` instead of `string`
|
||||
- `PlayerPreLoginEvent->getKickMessage()` now returns `Translatable|string|null` instead of `string|null`
|
||||
- `PlayerPreLoginEvent->setKickReason()` now accepts `Translatable|string` for the `$message` parameter instead of `string`
|
||||
- `PlayerQuitEvent->getQuitReason()` now returns `Translatable|string` instead of `string`
|
||||
- The following API methods have been removed:
|
||||
- `PlayerChatEvent->getFormat()` (use `PlayerChatEvent->getChatFormatter()` instead)
|
||||
- `PlayerChatEvent->setFormat()` (use `PlayerChatEvent->setChatFormatter()` instead)
|
||||
- The following new API methods have been added:
|
||||
- `public PlayerChatEvent->setChatFormatter(\pocketmine\player\chat\ChatFormatter $formatter) : void` - sets the chat formatter to be used for this event
|
||||
- `public PlayerChatEvent->getChatFormatter() : \pocketmine\player\chat\ChatFormatter` - returns the chat formatter to be used for this event
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new classes have been added:
|
||||
- `Medicine`
|
||||
- `MedicineType`
|
||||
- The following new class constants have been added:
|
||||
- `ItemTypeIds::MEDICINE`
|
||||
|
||||
### `pocketmine\network\query`
|
||||
- The following API methods have changed signatures:
|
||||
- `QueryInfo->getPlayerList()` now returns `list<string>` instead of `list<Player>`
|
||||
- `QueryInfo->setPlayerList()` now accepts `list<string>` instead of `list<Player>`
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following API methods have changed signatures:
|
||||
- `Player->kick()` now accepts `Translatable|string` for `$reason` instead of `string` (to allow localized kick messages)
|
||||
- `Player->disconnect()` now accepts `Translatable|string` for `$reason` instead of `string` (to allow localized disconnect messages)
|
||||
- `Player->sendJukeboxPopup()` now accepts `Translatable|string` instead of `string, string[]`
|
||||
|
||||
#### `pocketmine\player\chat`
|
||||
- The following new classes have been added:
|
||||
- `ChatFormatter` - interface implemented by chat formatters
|
||||
- `StandardChatFormatter` - formats chat messages in the vanilla Minecraft style
|
||||
- `LegacyRawChatFormatter` - implements the same behaviour previously used by `PlayerChatEvent->setFormat()`
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following API methods have changed signatures:
|
||||
- `World->getBiome()` now accepts `int $x, int $y, int $z` instead of `int $x, int $z`
|
||||
- `World->getBiomeId()` now accepts `int $x, int $y, int $z` instead of `int $x, int $z`
|
||||
- `World->setBiomeId()` now accepts `int $x, int $y, int $z` instead of `int $x, int $z`
|
||||
|
||||
#### `pocketmine\world\format`
|
||||
- The following new API methods have been added:
|
||||
- `public SubChunk->getBiomeArray() : PalettedBlockArray`
|
||||
- The following API methods have changed signatures:
|
||||
- `Chunk->getBiomeId()` now accepts `int $x, int $y, int $z` instead of `int $x, int $z`
|
||||
- `Chunk->setBiomeId()` now accepts `int $x, int $y, int $z` instead of `int $x, int $z`
|
||||
- `Chunk->__construct()` no longer accepts `BiomeArray` as a parameter (contained in each subchunk instead)
|
||||
- `SubChunk->__construct()` now accepts `int $emptyBlockId, list<PalettedBlockArray> $blocks, PalettedBlockArray $biomes, ?LightArray $blockLight, ?LightArray $skyLight` instead of `int, list<PalettedBlockArray>, ?LightArray, ?LightArray`
|
||||
- The following classes have been removed
|
||||
- `BiomeArray`
|
||||
|
||||
## Internals
|
||||
- Built-in commands now declare their names inside the class constructor, rather than accepting them as parameters. This improves code consistency.
|
||||
- `NetworkSession` disconnect APIs now accept `Translatable|string` instead of `string` to allow localized disconnect messages.
|
||||
- All external usages of `KnownTranslationKeys` are now removed. All localized messages are now sent using `Translatable` objects (usually from `KnownTranslationFactory`).
|
||||
|
@ -37,13 +37,13 @@
|
||||
"pocketmine/bedrock-block-upgrade-schema": "dev-master@dev",
|
||||
"pocketmine/bedrock-data": "dev-modern-world-support@dev",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "dev-master",
|
||||
"pocketmine/bedrock-protocol": "~14.0.0+bedrock-1.19.40",
|
||||
"pocketmine/bedrock-protocol": "~18.0.0+bedrock-1.19.50",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/classloader": "^0.2.0",
|
||||
"pocketmine/color": "^0.2.0",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
"pocketmine/errorhandler": "^0.6.0",
|
||||
"pocketmine/locale-data": "~2.9.0",
|
||||
"pocketmine/locale-data": "~2.18.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/log-pthreads": "^0.4.0",
|
||||
"pocketmine/math": "^0.4.0",
|
||||
@ -55,7 +55,7 @@
|
||||
"symfony/filesystem": "^5.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.9.1",
|
||||
"phpstan/phpstan": "1.9.12",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
|
306
composer.lock
generated
306
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": "6bcf382aecdbb6f170fd825727b4d621",
|
||||
"content-hash": "d6cafa9f9e236ad8d55c2eebdb51416a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -123,24 +123,24 @@
|
||||
},
|
||||
{
|
||||
"name": "fgrosse/phpasn1",
|
||||
"version": "v2.4.0",
|
||||
"version": "v2.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fgrosse/PHPASN1.git",
|
||||
"reference": "eef488991d53e58e60c9554b09b1201ca5ba9296"
|
||||
"reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/eef488991d53e58e60c9554b09b1201ca5ba9296",
|
||||
"reference": "eef488991d53e58e60c9554b09b1201ca5ba9296",
|
||||
"url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/42060ed45344789fb9f21f9f1864fc47b9e3507b",
|
||||
"reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0"
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "~2.0",
|
||||
"phpunit/phpunit": "^6.3 || ^7.0 || ^8.0"
|
||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "BCmath is the fallback extension for big integer calculations",
|
||||
@ -192,22 +192,23 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/fgrosse/PHPASN1/issues",
|
||||
"source": "https://github.com/fgrosse/PHPASN1/tree/v2.4.0"
|
||||
"source": "https://github.com/fgrosse/PHPASN1/tree/v2.5.0"
|
||||
},
|
||||
"time": "2021-12-11T12:41:06+00:00"
|
||||
"abandoned": true,
|
||||
"time": "2022-12-19T11:08:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
"version": "v4.0.0",
|
||||
"version": "v4.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cweiske/jsonmapper.git",
|
||||
"reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d"
|
||||
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
|
||||
"reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
|
||||
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -243,9 +244,9 @@
|
||||
"support": {
|
||||
"email": "cweiske@cweiske.de",
|
||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.0.0"
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0"
|
||||
},
|
||||
"time": "2020-12-01T19:48:11+00:00"
|
||||
"time": "2022-12-08T20:46:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-block-upgrade-schema",
|
||||
@ -280,12 +281,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "74fbcebae366b31f4a97bbf39ebb99be632f17a0"
|
||||
"reference": "d64617faab77300d828debcd1e3597b3403b63b7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/74fbcebae366b31f4a97bbf39ebb99be632f17a0",
|
||||
"reference": "74fbcebae366b31f4a97bbf39ebb99be632f17a0",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/d64617faab77300d828debcd1e3597b3403b63b7",
|
||||
"reference": "d64617faab77300d828debcd1e3597b3403b63b7",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -298,7 +299,7 @@
|
||||
"issues": "https://github.com/pmmp/BedrockData/issues",
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/modern-world-support"
|
||||
},
|
||||
"time": "2022-10-31T19:07:33+00:00"
|
||||
"time": "2022-12-02T13:01:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-item-upgrade-schema",
|
||||
@ -329,16 +330,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "14.0.0+bedrock-1.19.40",
|
||||
"version": "18.0.0+bedrock-1.19.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "b455a742779fee94d25f931cc2cbf6b2c5d61c1f"
|
||||
"reference": "b558ec883bd967dd3339f513cba62d2fbcd63349"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/b455a742779fee94d25f931cc2cbf6b2c5d61c1f",
|
||||
"reference": "b455a742779fee94d25f931cc2cbf6b2c5d61c1f",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/b558ec883bd967dd3339f513cba62d2fbcd63349",
|
||||
"reference": "b558ec883bd967dd3339f513cba62d2fbcd63349",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -346,13 +347,13 @@
|
||||
"netresearch/jsonmapper": "^4.0",
|
||||
"php": "^8.0",
|
||||
"pocketmine/binaryutils": "^0.2.0",
|
||||
"pocketmine/color": "^0.2.0",
|
||||
"pocketmine/color": "^0.2.0 || ^0.3.0",
|
||||
"pocketmine/math": "^0.3.0 || ^0.4.0",
|
||||
"pocketmine/nbt": "^0.3.0",
|
||||
"ramsey/uuid": "^4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.8.8",
|
||||
"phpstan/phpstan": "1.9.4",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
@ -370,9 +371,9 @@
|
||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/bedrock-1.19.40"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/18.0.0+bedrock-1.19.50"
|
||||
},
|
||||
"time": "2022-10-25T21:51:46+00:00"
|
||||
"time": "2023-01-06T21:47:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -513,24 +514,24 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/color",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Color.git",
|
||||
"reference": "09be6ea6d76f2e33d6813c39d29c22c46c17e1d2"
|
||||
"reference": "8cb346d0a21ad3287cc8d7175e4b643416607249"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Color/zipball/09be6ea6d76f2e33d6813c39d29c22c46c17e1d2",
|
||||
"reference": "09be6ea6d76f2e33d6813c39d29c22c46c17e1d2",
|
||||
"url": "https://api.github.com/repos/pmmp/Color/zipball/8cb346d0a21ad3287cc8d7175e4b643416607249",
|
||||
"reference": "8cb346d0a21ad3287cc8d7175e4b643416607249",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "0.12.59",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.2"
|
||||
"phpstan/phpstan": "1.9.4",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -545,9 +546,9 @@
|
||||
"description": "Color handling library used by PocketMine-MP and related projects",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/Color/issues",
|
||||
"source": "https://github.com/pmmp/Color/tree/0.2.0"
|
||||
"source": "https://github.com/pmmp/Color/tree/0.3.0"
|
||||
},
|
||||
"time": "2020-12-11T01:24:32+00:00"
|
||||
"time": "2022-12-18T19:49:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/errorhandler",
|
||||
@ -590,16 +591,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/locale-data",
|
||||
"version": "2.9.2",
|
||||
"version": "2.18.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Language.git",
|
||||
"reference": "8813ffd2a4501521ca9433c534f3009f941de136"
|
||||
"reference": "0f50afc3d0fec29f769a62e93c71f8a0fb968f76"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/8813ffd2a4501521ca9433c534f3009f941de136",
|
||||
"reference": "8813ffd2a4501521ca9433c534f3009f941de136",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/0f50afc3d0fec29f769a62e93c71f8a0fb968f76",
|
||||
"reference": "0f50afc3d0fec29f769a62e93c71f8a0fb968f76",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -607,9 +608,9 @@
|
||||
"description": "Language resources used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/Language/issues",
|
||||
"source": "https://github.com/pmmp/Language/tree/2.9.2"
|
||||
"source": "https://github.com/pmmp/Language/tree/2.18.0"
|
||||
},
|
||||
"time": "2022-10-21T20:30:38+00:00"
|
||||
"time": "2023-01-14T17:52:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/log",
|
||||
@ -905,42 +906,53 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/collection",
|
||||
"version": "1.2.2",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/collection.git",
|
||||
"reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a"
|
||||
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a",
|
||||
"reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4",
|
||||
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ^8",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"symfony/polyfill-php81": "^1.23"
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/captainhook": "^5.3",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
|
||||
"ergebnis/composer-normalize": "^2.6",
|
||||
"fakerphp/faker": "^1.5",
|
||||
"hamcrest/hamcrest-php": "^2",
|
||||
"jangregor/phpstan-prophecy": "^0.8",
|
||||
"mockery/mockery": "^1.3",
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"ergebnis/composer-normalize": "^2.28.3",
|
||||
"fakerphp/faker": "^1.21",
|
||||
"hamcrest/hamcrest-php": "^2.0",
|
||||
"jangregor/phpstan-prophecy": "^1.0",
|
||||
"mockery/mockery": "^1.5",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||
"phpcsstandards/phpcsutils": "^1.0.0-rc1",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpstan/extension-installer": "^1",
|
||||
"phpstan/phpstan": "^0.12.32",
|
||||
"phpstan/phpstan-mockery": "^0.12.5",
|
||||
"phpstan/phpstan-phpunit": "^0.12.11",
|
||||
"phpunit/phpunit": "^8.5 || ^9",
|
||||
"psy/psysh": "^0.10.4",
|
||||
"slevomat/coding-standard": "^6.3",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"vimeo/psalm": "^4.4"
|
||||
"phpstan/extension-installer": "^1.2",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpstan/phpstan-mockery": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/plugin-mockery": "^1.1",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"ramsey/coding-standard": "^2.0.3",
|
||||
"ramsey/conventional-commits": "^1.3",
|
||||
"vimeo/psalm": "^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"captainhook": {
|
||||
"force-install": true
|
||||
},
|
||||
"ramsey/conventional-commits": {
|
||||
"configFile": "conventional-commits.json"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ramsey\\Collection\\": "src/"
|
||||
@ -968,7 +980,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/collection/issues",
|
||||
"source": "https://github.com/ramsey/collection/tree/1.2.2"
|
||||
"source": "https://github.com/ramsey/collection/tree/1.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -980,27 +992,27 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-10-10T03:01:02+00:00"
|
||||
"time": "2022-12-27T19:12:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "4.6.0",
|
||||
"version": "4.7.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "ad63bc700e7d021039e30ce464eba384c4a1d40f"
|
||||
"reference": "433b2014e3979047db08a17a205f410ba3869cf2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/ad63bc700e7d021039e30ce464eba384c4a1d40f",
|
||||
"reference": "ad63bc700e7d021039e30ce464eba384c4a1d40f",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/433b2014e3979047db08a17a205f410ba3869cf2",
|
||||
"reference": "433b2014e3979047db08a17a205f410ba3869cf2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.8.8 || ^0.9 || ^0.10",
|
||||
"ext-json": "*",
|
||||
"php": "^8.0",
|
||||
"ramsey/collection": "^1.0"
|
||||
"ramsey/collection": "^1.2 || ^2.0"
|
||||
},
|
||||
"replace": {
|
||||
"rhumsaa/uuid": "self.version"
|
||||
@ -1060,7 +1072,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/uuid/issues",
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.6.0"
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.7.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1072,7 +1084,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-05T23:03:38+00:00"
|
||||
"time": "2023-01-12T18:13:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
@ -1140,16 +1152,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.26.0",
|
||||
"version": "v1.27.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
|
||||
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1164,7 +1176,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.26-dev"
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@ -1202,7 +1214,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1218,20 +1230,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-24T11:49:31+00:00"
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.26.0",
|
||||
"version": "v1.27.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
|
||||
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1246,7 +1258,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.26-dev"
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@ -1285,7 +1297,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1301,20 +1313,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-24T11:49:31+00:00"
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.26.0",
|
||||
"version": "v1.27.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
|
||||
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1323,7 +1335,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.26-dev"
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@ -1368,7 +1380,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1384,20 +1396,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-10T07:21:04+00:00"
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.26.0",
|
||||
"version": "v1.27.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
"reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1"
|
||||
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1",
|
||||
"reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
|
||||
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1406,7 +1418,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.26-dev"
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@ -1447,7 +1459,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1463,36 +1475,36 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-24T11:49:31+00:00"
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.4.1",
|
||||
"version": "1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
|
||||
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9",
|
||||
"doctrine/coding-standard": "^9 || ^11",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpbench/phpbench": "^0.16 || ^1",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpstan/phpstan-phpunit": "^1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"vimeo/psalm": "^4.22"
|
||||
"vimeo/psalm": "^4.30 || ^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -1519,7 +1531,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/instantiator/issues",
|
||||
"source": "https://github.com/doctrine/instantiator/tree/1.4.1"
|
||||
"source": "https://github.com/doctrine/instantiator/tree/1.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1535,7 +1547,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-03T08:28:38+00:00"
|
||||
"time": "2022-12-30T00:15:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
@ -1598,16 +1610,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.15.1",
|
||||
"version": "v4.15.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900"
|
||||
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
|
||||
"reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
|
||||
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1648,9 +1660,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2"
|
||||
},
|
||||
"time": "2022-09-04T07:30:47+00:00"
|
||||
"time": "2022-11-12T15:38:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@ -1765,16 +1777,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.9.1",
|
||||
"version": "1.9.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "a59c8b5bfd4a236f27efc8b5ce72c313c2b54b5f"
|
||||
"reference": "44a338ff0d5572c13fd77dfd91addb96e48c29f8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/a59c8b5bfd4a236f27efc8b5ce72c313c2b54b5f",
|
||||
"reference": "a59c8b5bfd4a236f27efc8b5ce72c313c2b54b5f",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/44a338ff0d5572c13fd77dfd91addb96e48c29f8",
|
||||
"reference": "44a338ff0d5572c13fd77dfd91addb96e48c29f8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1804,7 +1816,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.9.1"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.9.12"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1820,25 +1832,25 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-04T13:35:59+00:00"
|
||||
"time": "2023-01-17T10:44:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "1.2.2",
|
||||
"version": "1.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "dea1f87344c6964c607d9076dee42d891f3923f0"
|
||||
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/dea1f87344c6964c607d9076dee42d891f3923f0",
|
||||
"reference": "dea1f87344c6964c607d9076dee42d891f3923f0",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/54a24bd23e9e80ee918cdc24f909d376c2e273f7",
|
||||
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpstan": "^1.8.11"
|
||||
"phpstan/phpstan": "^1.9.3"
|
||||
},
|
||||
"conflict": {
|
||||
"phpunit/phpunit": "<7.0"
|
||||
@ -1870,27 +1882,27 @@
|
||||
"description": "PHPUnit extensions and rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.2.2"
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.3"
|
||||
},
|
||||
"time": "2022-10-28T10:23:07+00:00"
|
||||
"time": "2022-12-21T15:25:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
"version": "1.4.4",
|
||||
"version": "1.4.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6"
|
||||
"reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6",
|
||||
"reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d",
|
||||
"reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpstan": "^1.8.6"
|
||||
"phpstan/phpstan": "^1.9.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
@ -1918,22 +1930,22 @@
|
||||
"description": "Extra strict and opinionated rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.4"
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.5"
|
||||
},
|
||||
"time": "2022-09-21T11:38:17+00:00"
|
||||
"time": "2023-01-11T14:16:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.18",
|
||||
"version": "9.2.23",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a"
|
||||
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/12fddc491826940cf9b7e88ad9664cf51f0f6d0a",
|
||||
"reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
|
||||
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1989,7 +2001,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.18"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.23"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1997,7 +2009,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-10-27T13:35:33+00:00"
|
||||
"time": "2022-12-28T12:41:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -2242,20 +2254,20 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.5.26",
|
||||
"version": "9.5.28",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2"
|
||||
"reference": "954ca3113a03bf780d22f07bf055d883ee04b65e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/851867efcbb6a1b992ec515c71cdcf20d895e9d2",
|
||||
"reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/954ca3113a03bf780d22f07bf055d883ee04b65e",
|
||||
"reference": "954ca3113a03bf780d22f07bf055d883ee04b65e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.3.1",
|
||||
"doctrine/instantiator": "^1.3.1 || ^2",
|
||||
"ext-dom": "*",
|
||||
"ext-json": "*",
|
||||
"ext-libxml": "*",
|
||||
@ -2324,7 +2336,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.26"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.28"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2340,7 +2352,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-10-28T06:00:21+00:00"
|
||||
"time": "2023-01-14T12:32:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
@ -69,6 +69,10 @@ use const JSON_UNESCAPED_SLASHES;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
class MemoryManager{
|
||||
private const DEFAULT_CHECK_RATE = Server::TARGET_TICKS_PER_SECOND;
|
||||
private const DEFAULT_CONTINUOUS_TRIGGER_RATE = Server::TARGET_TICKS_PER_SECOND * 2;
|
||||
private const DEEFAULT_TICKS_PER_GC = 30 * 60 * Server::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
private int $memoryLimit;
|
||||
private int $globalMemoryLimit;
|
||||
private int $checkRate;
|
||||
@ -113,20 +117,12 @@ class MemoryManager{
|
||||
if($m <= 0){
|
||||
$defaultMemory = 0;
|
||||
}else{
|
||||
switch(mb_strtoupper($matches[2])){
|
||||
case "K":
|
||||
$defaultMemory = intdiv($m, 1024);
|
||||
break;
|
||||
case "M":
|
||||
$defaultMemory = $m;
|
||||
break;
|
||||
case "G":
|
||||
$defaultMemory = $m * 1024;
|
||||
break;
|
||||
default:
|
||||
$defaultMemory = $m;
|
||||
break;
|
||||
}
|
||||
$defaultMemory = match(mb_strtoupper($matches[2])){
|
||||
"K" => intdiv($m, 1024),
|
||||
"M" => $m,
|
||||
"G" => $m * 1024,
|
||||
default => $m,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,11 +135,11 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
$this->globalMemoryLimit = $config->getPropertyInt("memory.global-limit", 0) * 1024 * 1024;
|
||||
$this->checkRate = $config->getPropertyInt("memory.check-rate", 20);
|
||||
$this->checkRate = $config->getPropertyInt("memory.check-rate", self::DEFAULT_CHECK_RATE);
|
||||
$this->continuousTrigger = $config->getPropertyBool("memory.continuous-trigger", true);
|
||||
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", 30);
|
||||
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
|
||||
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", 36000);
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", self::DEEFAULT_TICKS_PER_GC);
|
||||
$this->garbageCollectionTrigger = $config->getPropertyBool("memory.garbage-collection.low-memory-trigger", true);
|
||||
$this->garbageCollectionAsync = $config->getPropertyBool("memory.garbage-collection.collect-async-worker", true);
|
||||
|
||||
@ -285,10 +281,8 @@ class MemoryManager{
|
||||
|
||||
/**
|
||||
* Static memory dumper accessible from any thread.
|
||||
*
|
||||
* @param mixed $startingObject
|
||||
*/
|
||||
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
|
||||
public static function dumpMemory(mixed $startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
|
||||
$hardLimit = Utils::assumeNotFalse(ini_get('memory_limit'), "memory_limit INI directive should always exist");
|
||||
ini_set('memory_limit', '-1');
|
||||
gc_disable();
|
||||
@ -479,18 +473,15 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $from
|
||||
* @param object[] $objects reference parameter
|
||||
* @param object[] $objects reference parameter
|
||||
* @param int[] $refCounts reference parameter
|
||||
*
|
||||
* @phpstan-param array<string, object> $objects
|
||||
* @phpstan-param array<string, int> $refCounts
|
||||
* @phpstan-param-out array<string, object> $objects
|
||||
* @phpstan-param-out array<string, int> $refCounts
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function continueDump($from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
||||
private static function continueDump(mixed $from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : mixed{
|
||||
if($maxNesting <= 0){
|
||||
return "(error) NESTING LIMIT REACHED";
|
||||
}
|
||||
|
@ -39,11 +39,14 @@ namespace pocketmine {
|
||||
use function extension_loaded;
|
||||
use function function_exists;
|
||||
use function getcwd;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function phpversion;
|
||||
use function preg_match;
|
||||
use function preg_quote;
|
||||
use function realpath;
|
||||
use function version_compare;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
@ -273,25 +276,33 @@ JIT_WARNING
|
||||
$pluginPath = getopt_string("plugins") ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
||||
Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX);
|
||||
|
||||
if(!@mkdir($dataPath, 0777, true) && (!is_dir($dataPath) || !is_writable($dataPath))){
|
||||
if(!@mkdir($dataPath, 0777, true) && !is_dir($dataPath)){
|
||||
critical_error("Unable to create/access data directory at $dataPath. Check that the target location is accessible by the current user.");
|
||||
exit(1);
|
||||
}
|
||||
//this has to be done after we're sure the data path exists
|
||||
$dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
|
||||
if(!@mkdir($pluginPath, 0777, true) && (!is_dir($pluginPath) || !is_writable($pluginPath))){
|
||||
critical_error("Unable to create plugin directory at $pluginPath. Check that the target location is accessible by the current user.");
|
||||
exit(1);
|
||||
}
|
||||
$pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
|
||||
|
||||
$lockFilePath = Path::join($dataPath, 'server.lock');
|
||||
if(($pid = Filesystem::createLockFile($lockFilePath)) !== null){
|
||||
try{
|
||||
$pid = Filesystem::createLockFile($lockFilePath);
|
||||
}catch(\InvalidArgumentException $e){
|
||||
critical_error($e->getMessage());
|
||||
critical_error("Please ensure that there is enough space on the disk and that the current user has read/write permissions to the selected data directory $dataPath.");
|
||||
exit(1);
|
||||
}
|
||||
if($pid !== null){
|
||||
critical_error("Another " . VersionInfo::NAME . " instance (PID $pid) is already using this folder (" . realpath($dataPath) . ").");
|
||||
critical_error("Please stop the other server first before running a new one.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!@mkdir($pluginPath, 0777, true) && !is_dir($pluginPath)){
|
||||
critical_error("Unable to create plugin directory at $pluginPath. Check that the target location is accessible by the current user.");
|
||||
exit(1);
|
||||
}
|
||||
$pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
|
||||
|
||||
//Logger has a dependency on timezone
|
||||
Timezone::init();
|
||||
|
||||
|
212
src/Server.php
212
src/Server.php
@ -49,10 +49,7 @@ use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\lang\Language;
|
||||
use pocketmine\lang\LanguageNotFoundException;
|
||||
use pocketmine\lang\Translatable;
|
||||
use pocketmine\nbt\BigEndianNbtSerializer;
|
||||
use pocketmine\nbt\NbtDataException;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\TreeRoot;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchTask;
|
||||
use pocketmine\network\mcpe\compression\Compressor;
|
||||
@ -72,9 +69,13 @@ use pocketmine\network\query\QueryInfo;
|
||||
use pocketmine\network\upnp\UPnPNetworkInterface;
|
||||
use pocketmine\permission\BanList;
|
||||
use pocketmine\permission\DefaultPermissions;
|
||||
use pocketmine\player\DatFilePlayerDataProvider;
|
||||
use pocketmine\player\GameMode;
|
||||
use pocketmine\player\OfflinePlayer;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\player\PlayerDataLoadException;
|
||||
use pocketmine\player\PlayerDataProvider;
|
||||
use pocketmine\player\PlayerDataSaveException;
|
||||
use pocketmine\player\PlayerInfo;
|
||||
use pocketmine\plugin\PharPluginLoader;
|
||||
use pocketmine\plugin\Plugin;
|
||||
@ -105,17 +106,18 @@ use pocketmine\utils\SignalHandler;
|
||||
use pocketmine\utils\Terminal;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\format\io\WorldProviderManager;
|
||||
use pocketmine\world\format\io\WritableWorldProviderManagerEntry;
|
||||
use pocketmine\world\generator\Generator;
|
||||
use pocketmine\world\generator\GeneratorManager;
|
||||
use pocketmine\world\generator\InvalidGeneratorOptionsException;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\World;
|
||||
use pocketmine\world\WorldCreationOptions;
|
||||
use pocketmine\world\WorldManager;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function array_fill;
|
||||
use function array_sum;
|
||||
use function base64_encode;
|
||||
use function cli_set_process_title;
|
||||
@ -124,7 +126,6 @@ use function count;
|
||||
use function date;
|
||||
use function fclose;
|
||||
use function file_exists;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function fopen;
|
||||
@ -161,12 +162,9 @@ use function time;
|
||||
use function touch;
|
||||
use function trim;
|
||||
use function yaml_parse;
|
||||
use function zlib_decode;
|
||||
use function zlib_encode;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_EOL;
|
||||
use const PHP_INT_MAX;
|
||||
use const ZLIB_ENCODING_GZIP;
|
||||
|
||||
/**
|
||||
* The class that manages everything
|
||||
@ -184,9 +182,30 @@ class Server{
|
||||
public const DEFAULT_PORT_IPV6 = 19133;
|
||||
public const DEFAULT_MAX_VIEW_DISTANCE = 16;
|
||||
|
||||
/**
|
||||
* Worlds, network, commands and most other things are polled this many times per second on average.
|
||||
* Between ticks, the server will sleep to ensure that the average tick rate is maintained.
|
||||
* It may wake up between ticks if a Snooze notification source is triggered (e.g. to process network packets).
|
||||
*/
|
||||
public const TARGET_TICKS_PER_SECOND = 20;
|
||||
/**
|
||||
* The average time between ticks, in seconds.
|
||||
*/
|
||||
public const TARGET_SECONDS_PER_TICK = 1 / self::TARGET_TICKS_PER_SECOND;
|
||||
public const TARGET_NANOSECONDS_PER_TICK = 1_000_000_000 / self::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
/**
|
||||
* The TPS threshold below which the server will generate log warnings.
|
||||
*/
|
||||
private const TPS_OVERLOAD_WARNING_THRESHOLD = self::TARGET_TICKS_PER_SECOND * 0.6;
|
||||
|
||||
private const TICKS_PER_WORLD_CACHE_CLEAR = 5 * self::TARGET_TICKS_PER_SECOND;
|
||||
private const TICKS_PER_TPS_OVERLOAD_WARNING = 5 * self::TARGET_TICKS_PER_SECOND;
|
||||
private const TICKS_PER_STATS_REPORT = 300 * self::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
private static ?Server $instance = null;
|
||||
|
||||
private SleeperHandler $tickSleeper;
|
||||
private TimeTrackingSleeperHandler $tickSleeper;
|
||||
|
||||
private BanList $banByName;
|
||||
|
||||
@ -202,7 +221,7 @@ class Server{
|
||||
|
||||
private PluginManager $pluginManager;
|
||||
|
||||
private float $profilingTickRate = 20;
|
||||
private float $profilingTickRate = self::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
private UpdateChecker $updater;
|
||||
|
||||
@ -212,10 +231,10 @@ class Server{
|
||||
private int $tickCounter = 0;
|
||||
private float $nextTick = 0;
|
||||
/** @var float[] */
|
||||
private array $tickAverage = [20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20];
|
||||
private array $tickAverage;
|
||||
/** @var float[] */
|
||||
private array $useAverage = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
private float $currentTPS = 20;
|
||||
private array $useAverage;
|
||||
private float $currentTPS = self::TARGET_TICKS_PER_SECOND;
|
||||
private float $currentUse = 0;
|
||||
private float $startTime;
|
||||
|
||||
@ -251,6 +270,8 @@ class Server{
|
||||
private string $dataPath;
|
||||
private string $pluginPath;
|
||||
|
||||
private PlayerDataProvider $playerDataProvider;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @phpstan-var array<string, string>
|
||||
@ -470,10 +491,7 @@ class Server{
|
||||
return $this->configGroup->getPropertyBool("player.save-player-data", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return OfflinePlayer|Player
|
||||
*/
|
||||
public function getOfflinePlayer(string $name){
|
||||
public function getOfflinePlayer(string $name) : Player|OfflinePlayer|null{
|
||||
$name = strtolower($name);
|
||||
$result = $this->getPlayerExact($name);
|
||||
|
||||
@ -484,49 +502,22 @@ class Server{
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function getPlayerDataPath(string $username) : string{
|
||||
return Path::join($this->getDataPath(), 'players', strtolower($username) . '.dat');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the server has stored any saved data for this player.
|
||||
*/
|
||||
public function hasOfflinePlayerData(string $name) : bool{
|
||||
return file_exists($this->getPlayerDataPath($name));
|
||||
}
|
||||
|
||||
private function handleCorruptedPlayerData(string $name) : void{
|
||||
$path = $this->getPlayerDataPath($name);
|
||||
rename($path, $path . '.bak');
|
||||
$this->logger->error($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||
return $this->playerDataProvider->hasData($name);
|
||||
}
|
||||
|
||||
public function getOfflinePlayerData(string $name) : ?CompoundTag{
|
||||
return Timings::$syncPlayerDataLoad->time(function() use ($name) : ?CompoundTag{
|
||||
$name = strtolower($name);
|
||||
$path = $this->getPlayerDataPath($name);
|
||||
|
||||
if(file_exists($path)){
|
||||
$contents = @file_get_contents($path);
|
||||
if($contents === false){
|
||||
throw new \RuntimeException("Failed to read player data file \"$path\" (permission denied?)");
|
||||
}
|
||||
$decompressed = @zlib_decode($contents);
|
||||
if($decompressed === false){
|
||||
$this->logger->debug("Failed to decompress raw player data for \"$name\"");
|
||||
$this->handleCorruptedPlayerData($name);
|
||||
return null;
|
||||
}
|
||||
|
||||
try{
|
||||
return (new BigEndianNbtSerializer())->read($decompressed)->mustGetCompoundTag();
|
||||
}catch(NbtDataException $e){ //corrupt data
|
||||
$this->logger->debug("Failed to decode NBT data for \"$name\": " . $e->getMessage());
|
||||
$this->handleCorruptedPlayerData($name);
|
||||
return null;
|
||||
}
|
||||
try{
|
||||
return $this->playerDataProvider->loadData($name);
|
||||
}catch(PlayerDataLoadException $e){
|
||||
$this->logger->debug("Failed to load player data for $name: " . $e->getMessage());
|
||||
$this->logger->error($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@ -540,11 +531,9 @@ class Server{
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
Timings::$syncPlayerDataSave->time(function() use ($name, $ev) : void{
|
||||
$nbt = new BigEndianNbtSerializer();
|
||||
$contents = Utils::assumeNotFalse(zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP), "zlib_encode() failed unexpectedly");
|
||||
try{
|
||||
Filesystem::safeFilePutContents($this->getPlayerDataPath($name), $contents);
|
||||
}catch(\RuntimeException $e){
|
||||
$this->playerDataProvider->saveData($name, $ev->getSaveData());
|
||||
}catch(PlayerDataSaveException $e){
|
||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
@ -560,51 +549,46 @@ class Server{
|
||||
$ev->call();
|
||||
$class = $ev->getPlayerClass();
|
||||
|
||||
if($offlinePlayerData !== null && ($world = $this->worldManager->getWorldByName($offlinePlayerData->getString("Level", ""))) !== null){
|
||||
if($offlinePlayerData !== null && ($world = $this->worldManager->getWorldByName($offlinePlayerData->getString(Player::TAG_LEVEL, ""))) !== null){
|
||||
$playerPos = EntityDataHelper::parseLocation($offlinePlayerData, $world);
|
||||
$spawn = $playerPos->asVector3();
|
||||
}else{
|
||||
$world = $this->worldManager->getDefaultWorld();
|
||||
if($world === null){
|
||||
throw new AssumptionFailedError("Default world should always be loaded");
|
||||
}
|
||||
$playerPos = null;
|
||||
$spawn = $world->getSpawnLocation();
|
||||
}
|
||||
/** @phpstan-var PromiseResolver<Player> $playerPromiseResolver */
|
||||
$playerPromiseResolver = new PromiseResolver();
|
||||
$world->requestChunkPopulation($spawn->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawn->getFloorZ() >> Chunk::COORD_BIT_SIZE, null)->onCompletion(
|
||||
function() use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $world, $playerPos, $spawn, $offlinePlayerData) : void{
|
||||
if(!$session->isConnected()){
|
||||
$playerPromiseResolver->reject();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Stick with the original spawn at the time of generation request, even if it changed since then.
|
||||
* This is because we know for sure that that chunk will be generated, but the one at the new location
|
||||
* might not be, and it would be much more complex to go back and redo the whole thing.
|
||||
*
|
||||
* TODO: this relies on the assumption that getSafeSpawn() will only alter the Y coordinate of the
|
||||
* provided position. If this assumption is broken, we'll start seeing crashes in here.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @see Player::__construct()
|
||||
* @var Player $player
|
||||
*/
|
||||
$player = new $class($this, $session, $playerInfo, $authenticated, $playerPos ?? Location::fromObject($world->getSafeSpawn($spawn), $world), $offlinePlayerData);
|
||||
if(!$player->hasPlayedBefore()){
|
||||
$player->onGround = true; //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move
|
||||
}
|
||||
$playerPromiseResolver->resolve($player);
|
||||
},
|
||||
static function() use ($playerPromiseResolver, $session) : void{
|
||||
if($session->isConnected()){
|
||||
$session->disconnect("Spawn terrain generation failed");
|
||||
}
|
||||
$playerPromiseResolver->reject();
|
||||
$createPlayer = function(Location $location) use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $offlinePlayerData) : void{
|
||||
$player = new $class($this, $session, $playerInfo, $authenticated, $location, $offlinePlayerData);
|
||||
if(!$player->hasPlayedBefore()){
|
||||
$player->onGround = true; //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move
|
||||
}
|
||||
);
|
||||
$playerPromiseResolver->resolve($player);
|
||||
};
|
||||
|
||||
if($playerPos === null){ //new player or no valid position due to world not being loaded
|
||||
$world->requestSafeSpawn()->onCompletion(
|
||||
function(Position $spawn) use ($createPlayer, $playerPromiseResolver, $session, $world) : void{
|
||||
if(!$session->isConnected()){
|
||||
$playerPromiseResolver->reject();
|
||||
return;
|
||||
}
|
||||
$createPlayer(Location::fromObject($spawn, $world));
|
||||
},
|
||||
function() use ($playerPromiseResolver, $session) : void{
|
||||
if($session->isConnected()){
|
||||
$session->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_error_respawn());
|
||||
}
|
||||
$playerPromiseResolver->reject();
|
||||
}
|
||||
);
|
||||
}else{ //returning player with a valid position - safe spawn not required
|
||||
$createPlayer($playerPos);
|
||||
}
|
||||
|
||||
return $playerPromiseResolver->getPromise();
|
||||
}
|
||||
|
||||
@ -780,8 +764,11 @@ class Server{
|
||||
}
|
||||
self::$instance = $this;
|
||||
$this->startTime = microtime(true);
|
||||
$this->tickAverage = array_fill(0, self::TARGET_TICKS_PER_SECOND, self::TARGET_TICKS_PER_SECOND);
|
||||
$this->useAverage = array_fill(0, self::TARGET_TICKS_PER_SECOND, 0);
|
||||
|
||||
$this->tickSleeper = new SleeperHandler();
|
||||
Timings::init();
|
||||
$this->tickSleeper = new TimeTrackingSleeperHandler(Timings::$serverInterrupts);
|
||||
|
||||
$this->signalHandler = new SignalHandler(function() : void{
|
||||
$this->logger->info("Received signal interrupt, stopping the server");
|
||||
@ -806,7 +793,7 @@ class Server{
|
||||
$this->logger->info("Loading server configuration");
|
||||
$pocketmineYmlPath = Path::join($this->dataPath, "pocketmine.yml");
|
||||
if(!file_exists($pocketmineYmlPath)){
|
||||
$content = Utils::assumeNotFalse(file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "pocketmine.yml")), "Missing required resource file");
|
||||
$content = Filesystem::fileGetContents(Path::join(\pocketmine\RESOURCE_PATH, "pocketmine.yml"));
|
||||
if(VersionInfo::IS_DEVELOPMENT_BUILD){
|
||||
$content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content);
|
||||
}
|
||||
@ -961,9 +948,8 @@ class Server{
|
||||
)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
|
||||
Timings::init();
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool("settings.enable-profiling", false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", 20);
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", self::TARGET_TICKS_PER_SECOND);
|
||||
|
||||
DefaultPermissions::registerCorePermissions();
|
||||
|
||||
@ -979,7 +965,7 @@ class Server{
|
||||
copy(Path::join(\pocketmine\RESOURCE_PATH, 'plugin_list.yml'), $graylistFile);
|
||||
}
|
||||
try{
|
||||
$pluginGraylist = PluginGraylist::fromArray(yaml_parse(file_get_contents($graylistFile)));
|
||||
$pluginGraylist = PluginGraylist::fromArray(yaml_parse(Filesystem::fileGetContents($graylistFile)));
|
||||
}catch(\InvalidArgumentException $e){
|
||||
$this->logger->emergency("Failed to load $graylistFile: " . $e->getMessage());
|
||||
$this->forceShutdownExit();
|
||||
@ -1001,12 +987,14 @@ class Server{
|
||||
|
||||
$this->worldManager = new WorldManager($this, Path::join($this->dataPath, "worlds"), $providerManager);
|
||||
$this->worldManager->setAutoSave($this->configGroup->getConfigBool("auto-save", $this->worldManager->getAutoSave()));
|
||||
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt("ticks-per.autosave", 6000));
|
||||
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt("ticks-per.autosave", $this->worldManager->getAutoSaveInterval()));
|
||||
|
||||
$this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString("auto-updater.host", "update.pmmp.io"));
|
||||
|
||||
$this->queryInfo = new QueryInfo($this);
|
||||
|
||||
$this->playerDataProvider = new DatFilePlayerDataProvider(Path::join($this->dataPath, "players"));
|
||||
|
||||
register_shutdown_function([$this, "crashDump"]);
|
||||
|
||||
$loadErrorCount = 0;
|
||||
@ -1039,7 +1027,7 @@ class Server{
|
||||
}
|
||||
|
||||
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
|
||||
$this->sendUsageTicker = 6000;
|
||||
$this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
|
||||
$this->sendUsage(SendUsageTask::TYPE_OPEN);
|
||||
}
|
||||
|
||||
@ -1268,7 +1256,7 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CommandSender[]|null $recipients
|
||||
* @param CommandSender[]|null $recipients
|
||||
*/
|
||||
public function broadcastMessage(Translatable|string $message, ?array $recipients = null) : int{
|
||||
$recipients = $recipients ?? $this->getBroadcastChannelSubscribers(self::BROADCAST_CHANNEL_USERS);
|
||||
@ -1321,9 +1309,9 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
|
||||
* @param int $stay Duration in ticks to stay on screen for
|
||||
* @param int $fadeOut Duration in ticks for fade-out.
|
||||
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
|
||||
* @param int $stay Duration in ticks to stay on screen for
|
||||
* @param int $fadeOut Duration in ticks for fade-out.
|
||||
* @param Player[]|null $recipients
|
||||
*/
|
||||
public function broadcastTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1, ?array $recipients = null) : int{
|
||||
@ -1538,7 +1526,7 @@ class Server{
|
||||
* @param mixed[][]|null $trace
|
||||
* @phpstan-param list<array<string, mixed>>|null $trace
|
||||
*/
|
||||
public function exceptionHandler(\Throwable $e, $trace = null) : void{
|
||||
public function exceptionHandler(\Throwable $e, ?array $trace = null) : void{
|
||||
while(@ob_end_flush()){}
|
||||
global $lastError;
|
||||
|
||||
@ -1822,11 +1810,11 @@ class Server{
|
||||
$this->network->tick();
|
||||
Timings::$connection->stopTiming();
|
||||
|
||||
if(($this->tickCounter % 20) === 0){
|
||||
if(($this->tickCounter % self::TARGET_TICKS_PER_SECOND) === 0){
|
||||
if($this->doTitleTick){
|
||||
$this->titleTick();
|
||||
}
|
||||
$this->currentTPS = 20;
|
||||
$this->currentTPS = self::TARGET_TICKS_PER_SECOND;
|
||||
$this->currentUse = 0;
|
||||
|
||||
$queryRegenerateEvent = new QueryRegenerateEvent(new QueryInfo($this));
|
||||
@ -1838,18 +1826,18 @@ class Server{
|
||||
}
|
||||
|
||||
if($this->sendUsageTicker > 0 && --$this->sendUsageTicker === 0){
|
||||
$this->sendUsageTicker = 6000;
|
||||
$this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
|
||||
$this->sendUsage(SendUsageTask::TYPE_STATUS);
|
||||
}
|
||||
|
||||
if(($this->tickCounter % 100) === 0){
|
||||
if(($this->tickCounter % self::TICKS_PER_WORLD_CACHE_CLEAR) === 0){
|
||||
foreach($this->worldManager->getWorlds() as $world){
|
||||
$world->clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
if($this->getTicksPerSecondAverage() < 12){
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||
}
|
||||
if(($this->tickCounter % self::TICKS_PER_TPS_OVERLOAD_WARNING) === 0 && $this->getTicksPerSecondAverage() < self::TPS_OVERLOAD_WARNING_THRESHOLD){
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||
}
|
||||
|
||||
$this->getMemoryManager()->check();
|
||||
@ -1866,19 +1854,21 @@ class Server{
|
||||
Timings::$serverTick->stopTiming();
|
||||
|
||||
$now = microtime(true);
|
||||
$this->currentTPS = min(20, 1 / max(0.001, $now - $tickTime));
|
||||
$this->currentUse = min(1, ($now - $tickTime) / 0.05);
|
||||
$totalTickTimeSeconds = $now - $tickTime + ($this->tickSleeper->getNotificationProcessingTime() / 1_000_000_000);
|
||||
$this->currentTPS = min(self::TARGET_TICKS_PER_SECOND, 1 / max(0.001, $totalTickTimeSeconds));
|
||||
$this->currentUse = min(1, $totalTickTimeSeconds / self::TARGET_SECONDS_PER_TICK);
|
||||
|
||||
TimingsHandler::tick($this->currentTPS <= $this->profilingTickRate);
|
||||
|
||||
$idx = $this->tickCounter % 20;
|
||||
$idx = $this->tickCounter % self::TARGET_TICKS_PER_SECOND;
|
||||
$this->tickAverage[$idx] = $this->currentTPS;
|
||||
$this->useAverage[$idx] = $this->currentUse;
|
||||
$this->tickSleeper->resetNotificationProcessingTime();
|
||||
|
||||
if(($this->nextTick - $tickTime) < -1){
|
||||
$this->nextTick = $tickTime;
|
||||
}else{
|
||||
$this->nextTick += 0.05;
|
||||
$this->nextTick += self::TARGET_SECONDS_PER_TICK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,12 +43,7 @@ final class ServerConfigGroup{
|
||||
private Config $serverProperties
|
||||
){}
|
||||
|
||||
/**
|
||||
* @param mixed $defaultValue
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getProperty(string $variable, $defaultValue = null){
|
||||
public function getProperty(string $variable, mixed $defaultValue = null) : mixed{
|
||||
if(!array_key_exists($variable, $this->propertyCache)){
|
||||
$v = getopt("", ["$variable::"]);
|
||||
if(isset($v[$variable])){
|
||||
|
64
src/TimeTrackingSleeperHandler.php
Normal file
64
src/TimeTrackingSleeperHandler.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use function hrtime;
|
||||
|
||||
/**
|
||||
* Custom Snooze sleeper handler which captures notification processing time.
|
||||
* @internal
|
||||
*/
|
||||
final class TimeTrackingSleeperHandler extends SleeperHandler{
|
||||
|
||||
private int $notificationProcessingTimeNs = 0;
|
||||
|
||||
public function __construct(
|
||||
private TimingsHandler $timings
|
||||
){
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in nanoseconds spent processing notifications since the last reset.
|
||||
*/
|
||||
public function getNotificationProcessingTime() : int{ return $this->notificationProcessingTimeNs; }
|
||||
|
||||
/**
|
||||
* Resets the notification processing time tracker to zero.
|
||||
*/
|
||||
public function resetNotificationProcessingTime() : void{ $this->notificationProcessingTimeNs = 0; }
|
||||
|
||||
public function processNotifications() : void{
|
||||
$startTime = hrtime(true);
|
||||
$this->timings->startTiming();
|
||||
try{
|
||||
parent::processNotifications();
|
||||
}finally{
|
||||
$this->notificationProcessingTimeNs += hrtime(true) - $startTime;
|
||||
$this->timings->stopTiming();
|
||||
}
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.0.0-ALPHA5";
|
||||
public const BASE_VERSION = "5.0.0-ALPHA7";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "alpha";
|
||||
|
||||
|
@ -30,12 +30,17 @@ use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataReader;
|
||||
use pocketmine\data\runtime\RuntimeDataWriter;
|
||||
use pocketmine\entity\object\FallingBlock;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\AnvilFallSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
use function lcg_value;
|
||||
use function round;
|
||||
|
||||
class Anvil extends Transparent implements Fallable{
|
||||
use FallableTrait;
|
||||
@ -95,4 +100,19 @@ class Anvil extends Transparent implements Fallable{
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onHitGround(FallingBlock $blockEntity) : bool{
|
||||
if(lcg_value() < 0.05 + (round($blockEntity->getFallDistance()) - 1) * 0.05){
|
||||
if($this->damage !== self::VERY_DAMAGED){
|
||||
$this->damage = $this->damage + 1;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getLandSound() : ?Sound{
|
||||
return new AnvilFallSound();
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ abstract class BaseBanner extends Transparent{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BannerPatternLayer[] $patterns
|
||||
* @param BannerPatternLayer[] $patterns
|
||||
*
|
||||
* @phpstan-param list<BannerPatternLayer> $patterns
|
||||
* @return $this
|
||||
@ -114,7 +114,14 @@ abstract class BaseBanner extends Transparent{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
return $block->isSolid();
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
|
||||
return false;
|
||||
}
|
||||
if($item instanceof ItemBanner){
|
||||
$this->color = $item->getColor();
|
||||
$this->setPatterns($item->getPatterns());
|
||||
@ -126,7 +133,7 @@ abstract class BaseBanner extends Transparent{
|
||||
abstract protected function getSupportingFace() : int;
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide($this->getSupportingFace())->getTypeId() === BlockTypeIds::AIR){
|
||||
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\CoralTypeTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\BlockDeathEvent;
|
||||
use pocketmine\item\Item;
|
||||
use function mt_rand;
|
||||
|
||||
@ -45,7 +46,11 @@ abstract class BaseCoral extends Transparent{
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
if(!$this->dead && !$this->isCoveredWithWater()){
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setDead(true));
|
||||
$ev = new BlockDeathEvent($this, $this->setDead(true));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,14 +88,13 @@ final class Bell extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
//TODO: this isn't the actual logic, but it's the closest approximation we can support for now
|
||||
return $block->isSolid();
|
||||
private function canBeSupportedBy(Block $block, int $face) : bool{
|
||||
return !$block->getSupportType($face)->equals(SupportType::NONE());
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face === Facing::UP){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->down()))){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->down()), Facing::UP)){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
@ -103,18 +102,18 @@ final class Bell extends Transparent{
|
||||
}
|
||||
$this->setAttachmentType(BellAttachmentType::FLOOR());
|
||||
}elseif($face === Facing::DOWN){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->up()))){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->up()), Facing::DOWN)){
|
||||
return false;
|
||||
}
|
||||
$this->setAttachmentType(BellAttachmentType::CEILING());
|
||||
}else{
|
||||
$this->setFacing($face);
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide(Facing::opposite($face))))){
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide(Facing::opposite($face))), $face)){
|
||||
$this->setAttachmentType(BellAttachmentType::ONE_WALL());
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide($face)))){
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide($face)), Facing::opposite($face))){
|
||||
$this->setAttachmentType(BellAttachmentType::TWO_WALLS());
|
||||
}
|
||||
}
|
||||
@ -123,10 +122,10 @@ final class Bell extends Transparent{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(
|
||||
($this->attachmentType->equals(BellAttachmentType::CEILING()) && !$this->canBeSupportedBy($this->getSide(Facing::UP))) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && !$this->canBeSupportedBy($this->getSide(Facing::DOWN))) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) && !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)))) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::TWO_WALLS()) && (!$this->canBeSupportedBy($this->getSide($this->facing)) || !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)))))
|
||||
($this->attachmentType->equals(BellAttachmentType::CEILING()) && !$this->canBeSupportedBy($this->getSide(Facing::UP), Facing::DOWN)) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && !$this->canBeSupportedBy($this->getSide(Facing::DOWN), Facing::UP)) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) && !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::TWO_WALLS()) && (!$this->canBeSupportedBy($this->getSide($this->facing), Facing::opposite($this->facing)) || !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)))
|
||||
){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
@ -135,21 +134,20 @@ final class Bell extends Transparent{
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player !== null){
|
||||
$faceHit = Facing::opposite($player->getHorizontalFacing());
|
||||
if($this->attachmentType->equals(BellAttachmentType::CEILING())){
|
||||
$this->ring($faceHit);
|
||||
}
|
||||
if($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)){
|
||||
$this->ring($faceHit);
|
||||
}
|
||||
if(
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
|
||||
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
|
||||
$this->attachmentType->equals(BellAttachmentType::CEILING()) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)) ||
|
||||
(
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
|
||||
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
|
||||
)
|
||||
){
|
||||
$this->ring($faceHit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ring(int $faceHit) : void{
|
||||
|
@ -63,7 +63,7 @@ class Block{
|
||||
protected ?array $collisionBoxes = null;
|
||||
|
||||
/**
|
||||
* @param string $name English name of the block type (TODO: implement translations)
|
||||
* @param string $name English name of the block type (TODO: implement translations)
|
||||
*/
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
|
||||
$this->idInfo = $idInfo;
|
||||
@ -305,6 +305,14 @@ class Block{
|
||||
* Generates a block transaction to set all blocks affected by placing this block. Usually this is just the block
|
||||
* itself, but may be multiple blocks in some cases (such as doors).
|
||||
*
|
||||
* @param BlockTransaction $tx Blocks to be set should be added to this transaction (do not modify thr world directly)
|
||||
* @param Item $item Item used to place the block
|
||||
* @param Block $blockReplace Block expected to be replaced
|
||||
* @param Block $blockClicked Block that was clicked using the item
|
||||
* @param int $face Face of the clicked block which was clicked
|
||||
* @param Vector3 $clickVector Exact position inside the clicked block where the click occurred, relative to the block's position
|
||||
* @param Player|null $player Player who placed the block, or null if it was not a player
|
||||
*
|
||||
* @return bool whether the placement should go ahead
|
||||
*/
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
|
@ -85,7 +85,7 @@ class BlockFactory{
|
||||
* NOTE: If you are registering a new block type, you will need to add it to the creative inventory yourself - it
|
||||
* will not automatically appear there.
|
||||
*
|
||||
* @param bool $override Whether to override existing registrations
|
||||
* @param bool $override Whether to override existing registrations
|
||||
*
|
||||
* @throws \InvalidArgumentException if something attempted to override an already-registered block without specifying the
|
||||
* $override parameter.
|
||||
|
@ -704,8 +704,13 @@ final class BlockTypeIds{
|
||||
public const MANGROVE_ROOTS = 10677;
|
||||
public const MUDDY_MANGROVE_ROOTS = 10678;
|
||||
public const FROGLIGHT = 10679;
|
||||
public const TWISTING_VINES = 10680;
|
||||
public const WEEPING_VINES = 10681;
|
||||
public const CHAIN = 10682;
|
||||
public const SCULK = 10683;
|
||||
public const GLOWING_ITEM_FRAME = 10684;
|
||||
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10680;
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10685;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;
|
||||
|
||||
|
@ -24,9 +24,11 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
final class BlockTypeTags{
|
||||
private const PREFIX = "pocketmine:";
|
||||
|
||||
public const DIRT = "dirt";
|
||||
public const MUD = "mud";
|
||||
public const SAND = "sand";
|
||||
public const POTTABLE_PLANTS = "pottable";
|
||||
public const DIRT = self::PREFIX . "dirt";
|
||||
public const MUD = self::PREFIX . "mud";
|
||||
public const SAND = self::PREFIX . "sand";
|
||||
public const POTTABLE_PLANTS = self::PREFIX . "pottable";
|
||||
public const FIRE = self::PREFIX . "fire";
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ abstract class Button extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->canBeSupportedBy($blockClicked, $face)){
|
||||
if($this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CandleTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataReader;
|
||||
use pocketmine\data\runtime\RuntimeDataWriter;
|
||||
use pocketmine\item\Item;
|
||||
@ -94,6 +95,10 @@ class Candle extends Transparent{
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
protected function getCandleIfCompatibleType(Block $block) : ?Candle{
|
||||
return $block instanceof Candle && $block->isSameType($this) ? $block : null;
|
||||
}
|
||||
|
48
src/block/Chain.php
Normal file
48
src/block/Chain.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\PillarRotationTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
|
||||
final class Chain extends Transparent{
|
||||
use PillarRotationTrait;
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return $this->axis === Axis::Y && Facing::axis($facing) === Axis::Y ? SupportType::CENTER() : SupportType::NONE();
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$bb = AxisAlignedBB::one();
|
||||
foreach([Axis::Y, Axis::Z, Axis::X] as $axis){
|
||||
if($axis !== $this->axis){
|
||||
$bb->squash($axis, 13 / 32);
|
||||
}
|
||||
}
|
||||
return [$bb];
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\CoralTypeTrait;
|
||||
use pocketmine\event\block\BlockDeathEvent;
|
||||
use pocketmine\item\Item;
|
||||
use function mt_rand;
|
||||
|
||||
@ -54,7 +55,11 @@ final class CoralBlock extends Opaque{
|
||||
}
|
||||
}
|
||||
if(!$hasWater){
|
||||
$world->setBlock($this->position, $this->setDead(true));
|
||||
$ev = new BlockDeathEvent($this, $this->setDead(true));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\tile\Furnace as TileFurnace;
|
||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\data\runtime\RuntimeDataReader;
|
||||
use pocketmine\data\runtime\RuntimeDataWriter;
|
||||
use pocketmine\item\Item;
|
||||
@ -37,8 +38,15 @@ class Furnace extends Opaque{
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
use HorizontalFacingTrait;
|
||||
|
||||
protected FurnaceType $furnaceType;
|
||||
|
||||
protected bool $lit = false;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, FurnaceType $furnaceType){
|
||||
$this->furnaceType = $furnaceType;
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
}
|
||||
|
||||
public function getRequiredStateDataBits() : int{ return 3; }
|
||||
|
||||
protected function describeState(RuntimeDataReader|RuntimeDataWriter $w) : void{
|
||||
@ -46,6 +54,10 @@ class Furnace extends Opaque{
|
||||
$w->bool($this->lit);
|
||||
}
|
||||
|
||||
public function getFurnaceType() : FurnaceType{
|
||||
return $this->furnaceType;
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return $this->lit ? 13 : 0;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\ItemFrame as TileItemFrame;
|
||||
use pocketmine\block\utils\AnyFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataReader;
|
||||
use pocketmine\data\runtime\RuntimeDataWriter;
|
||||
use pocketmine\item\Item;
|
||||
@ -32,6 +33,9 @@ use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\ItemFrameAddItemSound;
|
||||
use pocketmine\world\sound\ItemFrameRemoveItemSound;
|
||||
use pocketmine\world\sound\ItemFrameRotateItemSound;
|
||||
use function is_infinite;
|
||||
use function is_nan;
|
||||
use function lcg_value;
|
||||
@ -41,20 +45,12 @@ class ItemFrame extends Flowable{
|
||||
|
||||
public const ROTATIONS = 8;
|
||||
|
||||
protected bool $glowing = false;
|
||||
|
||||
protected bool $hasMap = false; //makes frame appear large if set
|
||||
|
||||
protected ?Item $framedItem = null;
|
||||
protected int $itemRotation = 0;
|
||||
protected float $itemDropChance = 1.0;
|
||||
|
||||
public function getRequiredTypeDataBits() : int{ return 1; }
|
||||
|
||||
protected function describeType(RuntimeDataReader|RuntimeDataWriter $w) : void{
|
||||
$w->bool($this->glowing);
|
||||
}
|
||||
|
||||
public function getRequiredStateDataBits() : int{ return 4; }
|
||||
|
||||
protected function describeState(RuntimeDataReader|RuntimeDataWriter $w) : void{
|
||||
@ -138,19 +134,15 @@ class ItemFrame extends Flowable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isGlowing() : bool{ return $this->glowing; }
|
||||
|
||||
/** @return $this */
|
||||
public function setGlowing(bool $glowing) : self{
|
||||
$this->glowing = $glowing;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->framedItem !== null){
|
||||
$this->itemRotation = ($this->itemRotation + 1) % self::ROTATIONS;
|
||||
|
||||
$this->position->getWorld()->addSound($this->position, new ItemFrameRotateItemSound());
|
||||
}elseif(!$item->isNull()){
|
||||
$this->framedItem = $item->pop();
|
||||
|
||||
$this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
@ -167,20 +159,25 @@ class ItemFrame extends Flowable{
|
||||
$world = $this->position->getWorld();
|
||||
if(lcg_value() <= $this->itemDropChance){
|
||||
$world->dropItem($this->position->add(0.5, 0.5, 0.5), clone $this->framedItem);
|
||||
$world->addSound($this->position, new ItemFrameRemoveItemSound());
|
||||
}
|
||||
$this->setFramedItem(null);
|
||||
$world->setBlock($this->position, $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block, int $face) : bool{
|
||||
return !$block->getSupportType($face)->equals(SupportType::NONE());
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->getSide(Facing::opposite($this->facing))->isSolid()){
|
||||
if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$blockClicked->isSolid()){
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\tile\Jukebox as JukeboxTile;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Record;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\RecordSound;
|
||||
@ -44,7 +45,7 @@ class Jukebox extends Opaque{
|
||||
if($this->record !== null){
|
||||
$this->ejectRecord();
|
||||
}elseif($item instanceof Record){
|
||||
$player->sendJukeboxPopup("record.nowPlaying", [$player->getLanguage()->translate($item->getRecordType()->getTranslatableName())]);
|
||||
$player->sendJukeboxPopup(KnownTranslationFactory::record_nowPlaying($item->getRecordType()->getTranslatableName()));
|
||||
$this->insertRecord($item->pop());
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ class Ladder extends Transparent{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->canBeSupportedBy($blockClicked, $face) && Facing::axis($face) !== Axis::Y){
|
||||
if($this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face) && Facing::axis($face) !== Axis::Y){
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ class Lever extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockClicked, $face)){
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
196
src/block/NetherVines.php
Normal file
196
src/block/NetherVines.php
Normal file
@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataReader;
|
||||
use pocketmine\data\runtime\RuntimeDataWriter;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function min;
|
||||
use function mt_rand;
|
||||
|
||||
/**
|
||||
* This class is used for Weeping & Twisting vines, because they have same behaviour
|
||||
*/
|
||||
class NetherVines extends Flowable{
|
||||
public const MAX_AGE = 25;
|
||||
|
||||
/** Direction the vine grows towards. */
|
||||
private int $growthFace;
|
||||
|
||||
protected int $age = 0;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, int $growthFace){
|
||||
$this->growthFace = $growthFace;
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
}
|
||||
|
||||
public function getRequiredStateDataBits() : int{
|
||||
return 5;
|
||||
}
|
||||
|
||||
public function describeState(RuntimeDataWriter|RuntimeDataReader $w) : void{
|
||||
$w->boundedInt(5, 0, self::MAX_AGE, $this->age);
|
||||
}
|
||||
|
||||
public function getAge() : int{
|
||||
return $this->age;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function setAge(int $age) : self{
|
||||
if($age < 0 || $age > self::MAX_AGE){
|
||||
throw new \InvalidArgumentException("Age must be in range 0-" . self::MAX_AGE);
|
||||
}
|
||||
|
||||
$this->age = $age;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canClimb() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
private function getSupportFace() : int{
|
||||
return Facing::opposite($this->growthFace);
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
return $block->getSupportType($this->getSupportFace())->hasCenterSupport() || $block->isSameType($this);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedBy($this->getSide($this->getSupportFace()))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block at the end of the vine structure furthest from the supporting block.
|
||||
*/
|
||||
private function seekToTip() : NetherVines{
|
||||
$top = $this;
|
||||
while(($next = $top->getSide($this->growthFace)) instanceof NetherVines && $next->isSameType($this)){
|
||||
$top = $next;
|
||||
}
|
||||
return $top;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportFace()))){
|
||||
return false;
|
||||
}
|
||||
$this->age = mt_rand(0, self::MAX_AGE - 1);
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer){
|
||||
if($this->grow($player, mt_rand(1, 5))){
|
||||
$item->pop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if(mt_rand(1, 10) === 1 && $this->age < self::MAX_AGE){
|
||||
if($this->getSide($this->growthFace)->canBeReplaced()){
|
||||
$this->grow(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function grow(?Player $player, int $growthAmount = 1) : bool{
|
||||
$top = $this->seekToTip();
|
||||
$age = $top->getAge();
|
||||
$pos = $top->getPosition();
|
||||
$world = $pos->getWorld();
|
||||
$changedBlocks = 0;
|
||||
|
||||
$tx = new BlockTransaction($world);
|
||||
|
||||
for($i = 1; $i <= $growthAmount; $i++){
|
||||
$growthPos = $pos->getSide($this->growthFace, $i);
|
||||
if(!$world->isInWorld($growthPos->getFloorX(), $growthPos->getFloorY(), $growthPos->getFloorZ()) || !$world->getBlock($growthPos)->canBeReplaced()){
|
||||
break;
|
||||
}
|
||||
$tx->addBlock($growthPos, (clone $top)->setAge(min(++$age, self::MAX_AGE)));
|
||||
$changedBlocks++;
|
||||
}
|
||||
|
||||
if($changedBlocks > 0){
|
||||
$ev = new StructureGrowEvent($top, $tx, $player);
|
||||
$ev->call();
|
||||
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
}
|
||||
|
||||
return $tx->apply();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasEntityCollision() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityInside(Entity $entity) : bool{
|
||||
$entity->resetFallDistance();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0 || mt_rand(1, 3) === 1){
|
||||
return [$this->asItem()];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ abstract class PressurePlate extends Transparent{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->canBeSupportedBy($blockClicked)){
|
||||
if($this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
return false;
|
||||
@ -55,5 +55,11 @@ abstract class PressurePlate extends Transparent{
|
||||
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE());
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
41
src/block/Sculk.php
Normal file
41
src/block/Sculk.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?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;
|
||||
|
||||
final class Sculk extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getXpDropAmount() : int{
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@ class Thin extends Transparent{
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$side = $this->getSide($facing);
|
||||
if($side instanceof Thin || $side->isFullCube()){
|
||||
if($side instanceof Thin || $side instanceof Wall || $side->isFullCube()){
|
||||
$this->connections[$facing] = true;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
|
@ -59,7 +59,6 @@ class Torch extends Flowable{
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$below = $this->getSide(Facing::DOWN);
|
||||
$face = Facing::opposite($this->facing);
|
||||
|
||||
if(!$this->canBeSupportedBy($this->getSide($face), $this->facing)){
|
||||
@ -68,10 +67,7 @@ class Torch extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($blockClicked->canBeReplaced() && $this->canBeSupportedBy($blockClicked->getSide(Facing::DOWN), Facing::UP)){
|
||||
$this->facing = Facing::UP;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}elseif($face !== Facing::DOWN && $this->canBeSupportedBy($blockClicked, $face)){
|
||||
if($face !== Facing::DOWN && $this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}else{
|
||||
|
@ -43,6 +43,7 @@ use pocketmine\block\tile\DaylightSensor as TileDaylightSensor;
|
||||
use pocketmine\block\tile\EnchantTable as TileEnchantingTable;
|
||||
use pocketmine\block\tile\EnderChest as TileEnderChest;
|
||||
use pocketmine\block\tile\FlowerPot as TileFlowerPot;
|
||||
use pocketmine\block\tile\GlowingItemFrame as TileGlowingItemFrame;
|
||||
use pocketmine\block\tile\Hopper as TileHopper;
|
||||
use pocketmine\block\tile\ItemFrame as TileItemFrame;
|
||||
use pocketmine\block\tile\Jukebox as TileJukebox;
|
||||
@ -55,9 +56,15 @@ use pocketmine\block\tile\Skull as TileSkull;
|
||||
use pocketmine\block\tile\Smoker as TileSmoker;
|
||||
use pocketmine\block\utils\TreeType;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ToolTier;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\utils\CloningRegistryTrait;
|
||||
use pocketmine\world\sound\AmethystBlockChimeSound;
|
||||
use pocketmine\world\sound\BlockPunchSound;
|
||||
use function mb_strtolower;
|
||||
|
||||
/**
|
||||
@ -147,6 +154,7 @@ use function mb_strtolower;
|
||||
* @method static CartographyTable CARTOGRAPHY_TABLE()
|
||||
* @method static CarvedPumpkin CARVED_PUMPKIN()
|
||||
* @method static Cauldron CAULDRON()
|
||||
* @method static Chain CHAIN()
|
||||
* @method static ChemicalHeat CHEMICAL_HEAT()
|
||||
* @method static Chest CHEST()
|
||||
* @method static Opaque CHISELED_DEEPSLATE()
|
||||
@ -402,6 +410,7 @@ use function mb_strtolower;
|
||||
* @method static Glass GLASS()
|
||||
* @method static GlassPane GLASS_PANE()
|
||||
* @method static GlazedTerracotta GLAZED_TERRACOTTA()
|
||||
* @method static ItemFrame GLOWING_ITEM_FRAME()
|
||||
* @method static GlowingObsidian GLOWING_OBSIDIAN()
|
||||
* @method static Glowstone GLOWSTONE()
|
||||
* @method static Opaque GOLD()
|
||||
@ -622,6 +631,7 @@ use function mb_strtolower;
|
||||
* @method static Slab SANDSTONE_SLAB()
|
||||
* @method static Stair SANDSTONE_STAIRS()
|
||||
* @method static Wall SANDSTONE_WALL()
|
||||
* @method static Sculk SCULK()
|
||||
* @method static SeaLantern SEA_LANTERN()
|
||||
* @method static SeaPickle SEA_PICKLE()
|
||||
* @method static Opaque SHROOMLIGHT()
|
||||
@ -691,6 +701,7 @@ use function mb_strtolower;
|
||||
* @method static Tripwire TRIPWIRE()
|
||||
* @method static TripwireHook TRIPWIRE_HOOK()
|
||||
* @method static Opaque TUFF()
|
||||
* @method static NetherVines TWISTING_VINES()
|
||||
* @method static UnderwaterTorch UNDERWATER_TORCH()
|
||||
* @method static Vine VINES()
|
||||
* @method static WallBanner WALL_BANNER()
|
||||
@ -711,6 +722,7 @@ use function mb_strtolower;
|
||||
* @method static Opaque WARPED_WART_BLOCK()
|
||||
* @method static Water WATER()
|
||||
* @method static WaterCauldron WATER_CAULDRON()
|
||||
* @method static NetherVines WEEPING_VINES()
|
||||
* @method static WeightedPressurePlateHeavy WEIGHTED_PRESSURE_PLATE_HEAVY()
|
||||
* @method static WeightedPressurePlateLight WEIGHTED_PRESSURE_PLATE_LIGHT()
|
||||
* @method static Wheat WHEAT()
|
||||
@ -821,7 +833,7 @@ final class VanillaBlocks{
|
||||
|
||||
self::register("ender_chest", new EnderChest(new BID(Ids::ENDER_CHEST, TileEnderChest::class), "Ender Chest", new Info(BreakInfo::pickaxe(22.5, ToolTier::WOOD(), 3000.0))));
|
||||
self::register("farmland", new Farmland(new BID(Ids::FARMLAND), "Farmland", new Info(BreakInfo::shovel(0.6), [Tags::DIRT])));
|
||||
self::register("fire", new Fire(new BID(Ids::FIRE), "Fire Block", new Info(BreakInfo::instant())));
|
||||
self::register("fire", new Fire(new BID(Ids::FIRE), "Fire Block", new Info(BreakInfo::instant(), [Tags::FIRE])));
|
||||
self::register("fletching_table", new FletchingTable(new BID(Ids::FLETCHING_TABLE), "Fletching Table", new Info(BreakInfo::axe(2.5, null, 2.5))));
|
||||
|
||||
$flowerTypeInfo = new Info(BreakInfo::instant(), [Tags::POTTABLE_PLANTS]);
|
||||
@ -839,9 +851,9 @@ final class VanillaBlocks{
|
||||
self::register("white_tulip", new Flower(new BID(Ids::WHITE_TULIP), "White Tulip", $flowerTypeInfo));
|
||||
self::register("flower_pot", new FlowerPot(new BID(Ids::FLOWER_POT, TileFlowerPot::class), "Flower Pot", $flowerTypeInfo));
|
||||
self::register("frosted_ice", new FrostedIce(new BID(Ids::FROSTED_ICE), "Frosted Ice", new Info(BreakInfo::pickaxe(2.5))));
|
||||
self::register("furnace", new Furnace(new BID(Ids::FURNACE, TileNormalFurnace::class), "Furnace", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD()))));
|
||||
self::register("blast_furnace", new Furnace(new BID(Ids::BLAST_FURNACE, TileBlastFurnace::class), "Blast Furnace", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD()))));
|
||||
self::register("smoker", new Furnace(new BID(Ids::SMOKER, TileSmoker::class), "Smoker", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD()))));
|
||||
self::register("furnace", new Furnace(new BID(Ids::FURNACE, TileNormalFurnace::class), "Furnace", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD())), FurnaceType::FURNACE()));
|
||||
self::register("blast_furnace", new Furnace(new BID(Ids::BLAST_FURNACE, TileBlastFurnace::class), "Blast Furnace", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD())), FurnaceType::BLAST_FURNACE()));
|
||||
self::register("smoker", new Furnace(new BID(Ids::SMOKER, TileSmoker::class), "Smoker", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD())), FurnaceType::SMOKER()));
|
||||
|
||||
$glassBreakInfo = new Info(new BreakInfo(0.3));
|
||||
self::register("glass", new Glass(new BID(Ids::GLASS), "Glass", $glassBreakInfo));
|
||||
@ -876,7 +888,11 @@ final class VanillaBlocks{
|
||||
$ironDoorBreakInfo = new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD(), 25.0));
|
||||
self::register("iron_door", new Door(new BID(Ids::IRON_DOOR), "Iron Door", $ironDoorBreakInfo));
|
||||
self::register("iron_trapdoor", new Trapdoor(new BID(Ids::IRON_TRAPDOOR), "Iron Trapdoor", $ironDoorBreakInfo));
|
||||
self::register("item_frame", new ItemFrame(new BID(Ids::ITEM_FRAME, TileItemFrame::class), "Item Frame", new Info(new BreakInfo(0.25))));
|
||||
|
||||
$itemFrameInfo = new Info(new BreakInfo(0.25));
|
||||
self::register("item_frame", new ItemFrame(new BID(Ids::ITEM_FRAME, TileItemFrame::class), "Item Frame", $itemFrameInfo));
|
||||
self::register("glowing_item_frame", new ItemFrame(new BID(Ids::GLOWING_ITEM_FRAME, TileGlowingItemFrame::class), "Glow Item Frame", $itemFrameInfo));
|
||||
|
||||
self::register("jukebox", new Jukebox(new BID(Ids::JUKEBOX, TileJukebox::class), "Jukebox", new Info(BreakInfo::axe(0.8)))); //TODO: in PC the hardness is 2.0, not 0.8, unsure if this is a MCPE bug or not
|
||||
self::register("ladder", new Ladder(new BID(Ids::LADDER), "Ladder", new Info(BreakInfo::axe(0.4))));
|
||||
|
||||
@ -1177,6 +1193,7 @@ final class VanillaBlocks{
|
||||
self::register("mangrove_roots", new MangroveRoots(new BID(Ids::MANGROVE_ROOTS), "Mangrove Roots", new Info(BreakInfo::axe(0.7))));
|
||||
self::register("muddy_mangrove_roots", new SimplePillar(new BID(Ids::MUDDY_MANGROVE_ROOTS), "Muddy Mangrove Roots", new Info(BreakInfo::shovel(0.7), [Tags::MUD])));
|
||||
self::register("froglight", new Froglight(new BID(Ids::FROGLIGHT), "Froglight", new Info(new BreakInfo(0.3))));
|
||||
self::register("sculk", new Sculk(new BID(Ids::SCULK), "Sculk", new Info(new BreakInfo(0.6, ToolType::HOE))));
|
||||
|
||||
self::registerBlocksR13();
|
||||
self::registerBlocksR14();
|
||||
@ -1449,7 +1466,7 @@ final class VanillaBlocks{
|
||||
self::register("cracked_polished_blackstone_bricks", new Opaque(new BID(Ids::CRACKED_POLISHED_BLACKSTONE_BRICKS), "Cracked Polished Blackstone Bricks", $blackstoneBreakInfo));
|
||||
|
||||
self::register("soul_torch", new Torch(new BID(Ids::SOUL_TORCH), "Soul Torch", new Info(BreakInfo::instant())));
|
||||
self::register("soul_fire", new SoulFire(new BID(Ids::SOUL_FIRE), "Soul Fire", new Info(BreakInfo::instant())));
|
||||
self::register("soul_fire", new SoulFire(new BID(Ids::SOUL_FIRE), "Soul Fire", new Info(BreakInfo::instant(), [Tags::FIRE])));
|
||||
|
||||
//TODO: soul soul ought to have 0.5 hardness (as per java) but it's 1.0 in Bedrock (probably parity bug)
|
||||
self::register("soul_soil", new Opaque(new BID(Ids::SOUL_SOIL), "Soul Soil", new Info(BreakInfo::shovel(1.0))));
|
||||
@ -1462,11 +1479,21 @@ final class VanillaBlocks{
|
||||
self::register("crying_obsidian", new class(new BID(Ids::CRYING_OBSIDIAN), "Crying Obsidian", new Info(BreakInfo::pickaxe(35.0 /* 50 in Java */, ToolTier::DIAMOND(), 6000.0))) extends Opaque{
|
||||
public function getLightLevel() : int{ return 10;}
|
||||
});
|
||||
|
||||
self::register("twisting_vines", new NetherVines(new BID(Ids::TWISTING_VINES), "Twisting Vines", new Info(BreakInfo::instant()), Facing::UP));
|
||||
self::register("weeping_vines", new NetherVines(new BID(Ids::WEEPING_VINES), "Weeping Vines", new Info(BreakInfo::instant()), Facing::DOWN));
|
||||
|
||||
self::register("chain", new Chain(new BID(Ids::CHAIN), "Chain", new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD()))));
|
||||
}
|
||||
|
||||
private static function registerBlocksR17() : void{
|
||||
//in java this can be acquired using any tool - seems to be a parity issue in bedrock
|
||||
self::register("amethyst", new Opaque(new BID(Ids::AMETHYST), "Amethyst", new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD()))));
|
||||
self::register("amethyst", new class(new BID(Ids::AMETHYST), "Amethyst", new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD()))) extends Opaque{
|
||||
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
|
||||
$this->position->getWorld()->addSound($this->position, new AmethystBlockChimeSound());
|
||||
$this->position->getWorld()->addSound($this->position, new BlockPunchSound($this));
|
||||
}
|
||||
});
|
||||
|
||||
self::register("calcite", new Opaque(new BID(Ids::CALCITE), "Calcite", new Info(BreakInfo::pickaxe(0.75, ToolTier::WOOD()))));
|
||||
self::register("tuff", new Opaque(new BID(Ids::TUFF), "Tuff", new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD(), 30.0))));
|
||||
|
@ -105,7 +105,7 @@ class Vine extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$blockClicked->isFullCube() || Facing::axis($face) === Axis::Y){
|
||||
if(!$blockReplace->getSide(Facing::opposite($face))->isFullCube() || Facing::axis($face) === Axis::Y){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ class Wall extends Transparent{
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$block = $this->getSide($facing);
|
||||
if($block instanceof static || $block instanceof FenceGate || ($block->isSolid() && !$block->isTransparent())){
|
||||
if($block instanceof static || $block instanceof FenceGate || $block instanceof Thin || ($block->isSolid() && !$block->isTransparent())){
|
||||
if(!isset($this->connections[$facing])){
|
||||
$this->connections[$facing] = WallConnectionType::SHORT();
|
||||
$changed++;
|
||||
|
@ -45,7 +45,7 @@ final class WallCoralFan extends BaseCoral{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$axis = Facing::axis($face);
|
||||
if(($axis !== Axis::X && $axis !== Axis::Z) || !$this->canBeSupportedBy($blockClicked, $face)){
|
||||
if(($axis !== Axis::X && $axis !== Axis::Z) || !$this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
return false;
|
||||
}
|
||||
$this->facing = $face;
|
||||
|
@ -39,19 +39,23 @@ class WaterLily extends Flowable{
|
||||
return [AxisAlignedBB::one()->contract(1 / 16, 0, 1 / 16)->trim(Facing::UP, 63 / 64)];
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($blockClicked instanceof Water){
|
||||
$up = $blockClicked->getSide(Facing::UP);
|
||||
if($up->canBeReplaced()){
|
||||
return parent::place($tx, $item, $up, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
}
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return !$blockReplace instanceof Water && parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
}
|
||||
|
||||
return false;
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
return $block instanceof Water;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){
|
||||
return false;
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!($this->getSide(Facing::DOWN) instanceof Water)){
|
||||
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ class Banner extends Spawnable{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BannerPatternLayer[] $patterns
|
||||
* @param BannerPatternLayer[] $patterns
|
||||
*
|
||||
* @phpstan-param list<BannerPatternLayer> $patterns
|
||||
*/
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\data\bedrock\item\SavedItemStackData;
|
||||
use pocketmine\data\SavedDataLoadingException;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\item\Item;
|
||||
@ -51,7 +52,7 @@ trait ContainerTrait{
|
||||
/** @var CompoundTag $itemNBT */
|
||||
foreach($inventoryTag as $itemNBT){
|
||||
try{
|
||||
$newContents[$itemNBT->getByte("Slot")] = Item::nbtDeserialize($itemNBT);
|
||||
$newContents[$itemNBT->getByte(SavedItemStackData::TAG_SLOT)] = Item::nbtDeserialize($itemNBT);
|
||||
}catch(SavedDataLoadingException $e){
|
||||
//TODO: not the best solution
|
||||
\GlobalLogger::get()->logException($e);
|
||||
|
32
src/block/tile/GlowingItemFrame.php
Normal file
32
src/block/tile/GlowingItemFrame.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?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\tile;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see \pocketmine\block\ItemFrame
|
||||
*/
|
||||
final class GlowingItemFrame extends ItemFrame{
|
||||
|
||||
}
|
@ -76,9 +76,9 @@ final class TileFactory{
|
||||
$this->register(Smoker::class, ["Smoker", "minecraft:smoker"]);
|
||||
$this->register(SporeBlossom::class, ["SporeBlossom", "minecraft:spore_blossom"]);
|
||||
$this->register(Skull::class, ["Skull", "minecraft:skull"]);
|
||||
$this->register(GlowingItemFrame::class, ["GlowItemFrame"]);
|
||||
|
||||
//TODO: Campfire
|
||||
//TODO: Cauldron
|
||||
//TODO: ChalkboardBlock
|
||||
//TODO: ChemistryTable
|
||||
//TODO: CommandBlock
|
||||
|
@ -24,6 +24,8 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\entity\object\FallingBlock;
|
||||
use pocketmine\world\sound\Sound;
|
||||
|
||||
interface Fallable{
|
||||
|
||||
@ -33,4 +35,15 @@ interface Fallable{
|
||||
* Return null if you don't want to change the usual behaviour.
|
||||
*/
|
||||
public function tickFalling() : ?Block;
|
||||
|
||||
/**
|
||||
* Called when FallingBlock hits the ground.
|
||||
* Returns whether the block should be placed.
|
||||
*/
|
||||
public function onHitGround(FallingBlock $blockEntity) : bool;
|
||||
|
||||
/**
|
||||
* Returns the sound that will be played when FallingBlock hits the ground.
|
||||
*/
|
||||
public function getLandSound() : ?Sound;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\entity\object\FallingBlock;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\Sound;
|
||||
|
||||
/**
|
||||
* This trait handles falling behaviour for blocks that need them.
|
||||
@ -58,4 +59,12 @@ trait FallableTrait{
|
||||
public function tickFalling() : ?Block{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onHitGround(FallingBlock $blockEntity) : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getLandSound() : ?Sound{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -36,12 +36,15 @@ use pocketmine\utils\EnumTrait;
|
||||
*
|
||||
* @method static RecordType DISK_11()
|
||||
* @method static RecordType DISK_13()
|
||||
* @method static RecordType DISK_5()
|
||||
* @method static RecordType DISK_BLOCKS()
|
||||
* @method static RecordType DISK_CAT()
|
||||
* @method static RecordType DISK_CHIRP()
|
||||
* @method static RecordType DISK_FAR()
|
||||
* @method static RecordType DISK_MALL()
|
||||
* @method static RecordType DISK_MELLOHI()
|
||||
* @method static RecordType DISK_OTHERSIDE()
|
||||
* @method static RecordType DISK_PIGSTEP()
|
||||
* @method static RecordType DISK_STAL()
|
||||
* @method static RecordType DISK_STRAD()
|
||||
* @method static RecordType DISK_WAIT()
|
||||
@ -55,18 +58,20 @@ final class RecordType{
|
||||
protected static function setup() : void{
|
||||
self::registerAll(
|
||||
new RecordType("disk_13", "C418 - 13", LevelSoundEvent::RECORD_13, KnownTranslationFactory::item_record_13_desc()),
|
||||
new RecordType("disk_5", "Samuel Åberg - 5", LevelSoundEvent::RECORD_5, KnownTranslationFactory::item_record_5_desc()),
|
||||
new RecordType("disk_cat", "C418 - cat", LevelSoundEvent::RECORD_CAT, KnownTranslationFactory::item_record_cat_desc()),
|
||||
new RecordType("disk_blocks", "C418 - blocks", LevelSoundEvent::RECORD_BLOCKS, KnownTranslationFactory::item_record_blocks_desc()),
|
||||
new RecordType("disk_chirp", "C418 - chirp", LevelSoundEvent::RECORD_CHIRP, KnownTranslationFactory::item_record_chirp_desc()),
|
||||
new RecordType("disk_far", "C418 - far", LevelSoundEvent::RECORD_FAR, KnownTranslationFactory::item_record_far_desc()),
|
||||
new RecordType("disk_mall", "C418 - mall", LevelSoundEvent::RECORD_MALL, KnownTranslationFactory::item_record_mall_desc()),
|
||||
new RecordType("disk_mellohi", "C418 - mellohi", LevelSoundEvent::RECORD_MELLOHI, KnownTranslationFactory::item_record_mellohi_desc()),
|
||||
new RecordType("disk_otherside", "Lena Raine - otherside", LevelSoundEvent::RECORD_OTHERSIDE, KnownTranslationFactory::item_record_otherside_desc()),
|
||||
new RecordType("disk_pigstep", "Lena Raine - Pigstep", LevelSoundEvent::RECORD_PIGSTEP, KnownTranslationFactory::item_record_pigstep_desc()),
|
||||
new RecordType("disk_stal", "C418 - stal", LevelSoundEvent::RECORD_STAL, KnownTranslationFactory::item_record_stal_desc()),
|
||||
new RecordType("disk_strad", "C418 - strad", LevelSoundEvent::RECORD_STRAD, KnownTranslationFactory::item_record_strad_desc()),
|
||||
new RecordType("disk_ward", "C418 - ward", LevelSoundEvent::RECORD_WARD, KnownTranslationFactory::item_record_ward_desc()),
|
||||
new RecordType("disk_11", "C418 - 11", LevelSoundEvent::RECORD_11, KnownTranslationFactory::item_record_11_desc()),
|
||||
new RecordType("disk_wait", "C418 - wait", LevelSoundEvent::RECORD_WAIT, KnownTranslationFactory::item_record_wait_desc())
|
||||
//TODO: Lena Raine - Pigstep
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ use function array_slice;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function is_int;
|
||||
use function strpos;
|
||||
use function str_contains;
|
||||
|
||||
class SignText{
|
||||
public const LINE_COUNT = 4;
|
||||
@ -57,7 +57,7 @@ class SignText{
|
||||
foreach($lines as $k => $line){
|
||||
$this->checkLineIndex($k);
|
||||
Utils::checkUTF8($line);
|
||||
if(strpos($line, "\n") !== false){
|
||||
if(str_contains($line, "\n")){
|
||||
throw new \InvalidArgumentException("Line must not contain newlines");
|
||||
}
|
||||
//TODO: add length checks
|
||||
@ -87,10 +87,7 @@ class SignText{
|
||||
return $this->lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $index
|
||||
*/
|
||||
private function checkLineIndex($index) : void{
|
||||
private function checkLineIndex(int|string $index) : void{
|
||||
if(!is_int($index)){
|
||||
throw new \InvalidArgumentException("Index must be an integer");
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace pocketmine\command;
|
||||
interface CommandExecutor{
|
||||
|
||||
/**
|
||||
* @param string[] $args
|
||||
* @param string[] $args
|
||||
*/
|
||||
public function onCommand(CommandSender $sender, Command $command, string $label, array $args) : bool;
|
||||
|
||||
|
@ -53,7 +53,7 @@ class FormattedCommandAlias extends Command{
|
||||
string $alias,
|
||||
private array $formatStrings
|
||||
){
|
||||
parent::__construct($alias);
|
||||
parent::__construct($alias, KnownTranslationFactory::pocketmine_command_userDefined_description());
|
||||
}
|
||||
|
||||
public function execute(CommandSender $sender, string $commandLabel, array $args){
|
||||
|
@ -73,8 +73,8 @@ use pocketmine\utils\TextFormat;
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function str_contains;
|
||||
use function strcasecmp;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
@ -89,46 +89,46 @@ class SimpleCommandMap implements CommandMap{
|
||||
|
||||
private function setDefaultCommands() : void{
|
||||
$this->registerAll("pocketmine", [
|
||||
new BanCommand("ban"),
|
||||
new BanIpCommand("ban-ip"),
|
||||
new BanListCommand("banlist"),
|
||||
new ClearCommand("clear"),
|
||||
new DefaultGamemodeCommand("defaultgamemode"),
|
||||
new DeopCommand("deop"),
|
||||
new DifficultyCommand("difficulty"),
|
||||
new DumpMemoryCommand("dumpmemory"),
|
||||
new EffectCommand("effect"),
|
||||
new EnchantCommand("enchant"),
|
||||
new GamemodeCommand("gamemode"),
|
||||
new GarbageCollectorCommand("gc"),
|
||||
new GiveCommand("give"),
|
||||
new HelpCommand("help"),
|
||||
new KickCommand("kick"),
|
||||
new KillCommand("kill"),
|
||||
new ListCommand("list"),
|
||||
new MeCommand("me"),
|
||||
new OpCommand("op"),
|
||||
new PardonCommand("pardon"),
|
||||
new PardonIpCommand("pardon-ip"),
|
||||
new ParticleCommand("particle"),
|
||||
new PluginsCommand("plugins"),
|
||||
new SaveCommand("save-all"),
|
||||
new SaveOffCommand("save-off"),
|
||||
new SaveOnCommand("save-on"),
|
||||
new SayCommand("say"),
|
||||
new SeedCommand("seed"),
|
||||
new SetWorldSpawnCommand("setworldspawn"),
|
||||
new SpawnpointCommand("spawnpoint"),
|
||||
new StatusCommand("status"),
|
||||
new StopCommand("stop"),
|
||||
new TeleportCommand("tp"),
|
||||
new TellCommand("tell"),
|
||||
new TimeCommand("time"),
|
||||
new TimingsCommand("timings"),
|
||||
new TitleCommand("title"),
|
||||
new TransferServerCommand("transferserver"),
|
||||
new VersionCommand("version"),
|
||||
new WhitelistCommand("whitelist")
|
||||
new BanCommand(),
|
||||
new BanIpCommand(),
|
||||
new BanListCommand(),
|
||||
new ClearCommand(),
|
||||
new DefaultGamemodeCommand(),
|
||||
new DeopCommand(),
|
||||
new DifficultyCommand(),
|
||||
new DumpMemoryCommand(),
|
||||
new EffectCommand(),
|
||||
new EnchantCommand(),
|
||||
new GamemodeCommand(),
|
||||
new GarbageCollectorCommand(),
|
||||
new GiveCommand(),
|
||||
new HelpCommand(),
|
||||
new KickCommand(),
|
||||
new KillCommand(),
|
||||
new ListCommand(),
|
||||
new MeCommand(),
|
||||
new OpCommand(),
|
||||
new PardonCommand(),
|
||||
new PardonIpCommand(),
|
||||
new ParticleCommand(),
|
||||
new PluginsCommand(),
|
||||
new SaveCommand(),
|
||||
new SaveOffCommand(),
|
||||
new SaveOnCommand(),
|
||||
new SayCommand(),
|
||||
new SeedCommand(),
|
||||
new SetWorldSpawnCommand(),
|
||||
new SpawnpointCommand(),
|
||||
new StatusCommand(),
|
||||
new StopCommand(),
|
||||
new TeleportCommand(),
|
||||
new TellCommand(),
|
||||
new TimeCommand(),
|
||||
new TimingsCommand(),
|
||||
new TitleCommand(),
|
||||
new TransferServerCommand(),
|
||||
new VersionCommand(),
|
||||
new WhitelistCommand()
|
||||
]);
|
||||
}
|
||||
|
||||
@ -242,7 +242,7 @@ class SimpleCommandMap implements CommandMap{
|
||||
$values = $this->server->getCommandAliases();
|
||||
|
||||
foreach($values as $alias => $commandStrings){
|
||||
if(strpos($alias, ":") !== false){
|
||||
if(str_contains($alias, ":")){
|
||||
$this->server->getLogger()->warning($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_command_alias_illegal($alias)));
|
||||
continue;
|
||||
}
|
||||
|
@ -35,9 +35,9 @@ use function implode;
|
||||
|
||||
class BanCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"ban",
|
||||
KnownTranslationFactory::pocketmine_command_ban_player_description(),
|
||||
KnownTranslationFactory::commands_ban_usage()
|
||||
);
|
||||
@ -55,7 +55,7 @@ class BanCommand extends VanillaCommand{
|
||||
$sender->getServer()->getNameBans()->addBan($name, $reason, null, $sender->getName());
|
||||
|
||||
if(($player = $sender->getServer()->getPlayerExact($name)) instanceof Player){
|
||||
$player->kick($reason !== "" ? "Banned by admin. Reason: " . $reason : "Banned by admin.");
|
||||
$player->kick($reason !== "" ? KnownTranslationFactory::pocketmine_disconnect_ban($reason) : KnownTranslationFactory::pocketmine_disconnect_ban_noReason());
|
||||
}
|
||||
|
||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_ban_success($player !== null ? $player->getName() : $name));
|
||||
|
@ -36,9 +36,9 @@ use function inet_pton;
|
||||
|
||||
class BanIpCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"ban-ip",
|
||||
KnownTranslationFactory::pocketmine_command_ban_ip_description(),
|
||||
KnownTranslationFactory::commands_banip_usage()
|
||||
);
|
||||
@ -78,7 +78,7 @@ class BanIpCommand extends VanillaCommand{
|
||||
|
||||
foreach($sender->getServer()->getOnlinePlayers() as $player){
|
||||
if($player->getNetworkSession()->getIp() === $ip){
|
||||
$player->kick("Banned by admin. Reason: " . ($reason !== "" ? $reason : "IP banned."));
|
||||
$player->kick(KnownTranslationFactory::pocketmine_disconnect_ban($reason !== "" ? $reason : KnownTranslationFactory::pocketmine_disconnect_ban_ip()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,9 @@ use const SORT_STRING;
|
||||
|
||||
class BanListCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"banlist",
|
||||
KnownTranslationFactory::pocketmine_command_banlist_description(),
|
||||
KnownTranslationFactory::commands_banlist_usage()
|
||||
);
|
||||
|
@ -33,7 +33,6 @@ use pocketmine\item\LegacyStringToItemParserException;
|
||||
use pocketmine\item\StringToItemParser;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function count;
|
||||
use function implode;
|
||||
@ -41,9 +40,9 @@ use function min;
|
||||
|
||||
class ClearCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"clear",
|
||||
KnownTranslationFactory::pocketmine_command_clear_description(),
|
||||
KnownTranslationFactory::pocketmine_command_clear_usage()
|
||||
);
|
||||
@ -55,23 +54,9 @@ class ClearCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
if(isset($args[0])){
|
||||
$target = $sender->getServer()->getPlayerByPrefix($args[0]);
|
||||
if($target === null){
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_generic_player_notFound()->prefix(TextFormat::RED));
|
||||
return true;
|
||||
}
|
||||
if($target !== $sender && !$this->testPermission($sender, DefaultPermissionNames::COMMAND_CLEAR_OTHER)){
|
||||
return true;
|
||||
}
|
||||
}elseif($sender instanceof Player){
|
||||
if(!$this->testPermission($sender, DefaultPermissionNames::COMMAND_CLEAR_SELF)){
|
||||
return true;
|
||||
}
|
||||
|
||||
$target = $sender;
|
||||
}else{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
$target = $this->fetchPermittedPlayerTarget($sender, $args[0] ?? null, DefaultPermissionNames::COMMAND_CLEAR_SELF, DefaultPermissionNames::COMMAND_CLEAR_OTHER);
|
||||
if($target === null){
|
||||
return true;
|
||||
}
|
||||
|
||||
$targetItem = null;
|
||||
|
@ -32,9 +32,9 @@ use function count;
|
||||
|
||||
class DefaultGamemodeCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"defaultgamemode",
|
||||
KnownTranslationFactory::pocketmine_command_defaultgamemode_description(),
|
||||
KnownTranslationFactory::commands_defaultgamemode_usage()
|
||||
);
|
||||
|
@ -35,9 +35,9 @@ use function count;
|
||||
|
||||
class DeopCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"deop",
|
||||
KnownTranslationFactory::pocketmine_command_deop_description(),
|
||||
KnownTranslationFactory::commands_deop_usage()
|
||||
);
|
||||
|
@ -33,9 +33,9 @@ use function count;
|
||||
|
||||
class DifficultyCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"difficulty",
|
||||
KnownTranslationFactory::pocketmine_command_difficulty_description(),
|
||||
KnownTranslationFactory::commands_difficulty_usage()
|
||||
);
|
||||
|
@ -24,17 +24,18 @@ declare(strict_types=1);
|
||||
namespace pocketmine\command\defaults;
|
||||
|
||||
use pocketmine\command\CommandSender;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function date;
|
||||
|
||||
class DumpMemoryCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"Dumps the memory",
|
||||
"/$name [path]"
|
||||
"dumpmemory",
|
||||
KnownTranslationFactory::pocketmine_command_dumpmemory_description(),
|
||||
"/dumpmemory [path]"
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_DUMPMEMORY);
|
||||
}
|
||||
|
@ -32,17 +32,21 @@ use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\utils\Limits;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function strtolower;
|
||||
|
||||
class EffectCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"effect",
|
||||
KnownTranslationFactory::pocketmine_command_effect_description(),
|
||||
KnownTranslationFactory::commands_effect_usage()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_EFFECT);
|
||||
$this->setPermission(implode(";", [
|
||||
DefaultPermissionNames::COMMAND_EFFECT_SELF,
|
||||
DefaultPermissionNames::COMMAND_EFFECT_OTHER
|
||||
]));
|
||||
}
|
||||
|
||||
public function execute(CommandSender $sender, string $commandLabel, array $args){
|
||||
@ -50,10 +54,8 @@ class EffectCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $sender->getServer()->getPlayerByPrefix($args[0]);
|
||||
|
||||
$player = $this->fetchPermittedPlayerTarget($sender, $args[0], DefaultPermissionNames::COMMAND_EFFECT_SELF, DefaultPermissionNames::COMMAND_EFFECT_OTHER);
|
||||
if($player === null){
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_generic_player_notFound()->prefix(TextFormat::RED));
|
||||
return true;
|
||||
}
|
||||
$effectManager = $player->getEffects();
|
||||
|
@ -29,18 +29,21 @@ use pocketmine\item\enchantment\EnchantmentInstance;
|
||||
use pocketmine\item\enchantment\StringToEnchantmentParser;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function count;
|
||||
use function implode;
|
||||
|
||||
class EnchantCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"enchant",
|
||||
KnownTranslationFactory::pocketmine_command_enchant_description(),
|
||||
KnownTranslationFactory::commands_enchant_usage()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_ENCHANT);
|
||||
$this->setPermission(implode(";", [
|
||||
DefaultPermissionNames::COMMAND_ENCHANT_SELF,
|
||||
DefaultPermissionNames::COMMAND_ENCHANT_OTHER
|
||||
]));
|
||||
}
|
||||
|
||||
public function execute(CommandSender $sender, string $commandLabel, array $args){
|
||||
@ -48,10 +51,8 @@ class EnchantCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $sender->getServer()->getPlayerByPrefix($args[0]);
|
||||
|
||||
$player = $this->fetchPermittedPlayerTarget($sender, $args[0], DefaultPermissionNames::COMMAND_ENCHANT_SELF, DefaultPermissionNames::COMMAND_ENCHANT_OTHER);
|
||||
if($player === null){
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_generic_player_notFound()->prefix(TextFormat::RED));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -29,19 +29,21 @@ use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\GameMode;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function count;
|
||||
use function implode;
|
||||
|
||||
class GamemodeCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"gamemode",
|
||||
KnownTranslationFactory::pocketmine_command_gamemode_description(),
|
||||
KnownTranslationFactory::commands_gamemode_usage()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_GAMEMODE);
|
||||
$this->setPermission(implode(";", [
|
||||
DefaultPermissionNames::COMMAND_GAMEMODE_SELF,
|
||||
DefaultPermissionNames::COMMAND_GAMEMODE_OTHER
|
||||
]));
|
||||
}
|
||||
|
||||
public function execute(CommandSender $sender, string $commandLabel, array $args){
|
||||
@ -55,17 +57,14 @@ class GamemodeCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(isset($args[1])){
|
||||
$target = $sender->getServer()->getPlayerByPrefix($args[1]);
|
||||
if($target === null){
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_generic_player_notFound()->prefix(TextFormat::RED));
|
||||
$target = $this->fetchPermittedPlayerTarget($sender, $args[1] ?? null, DefaultPermissionNames::COMMAND_GAMEMODE_SELF, DefaultPermissionNames::COMMAND_GAMEMODE_OTHER);
|
||||
if($target === null){
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}elseif($sender instanceof Player){
|
||||
$target = $sender;
|
||||
}else{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
if($target->getGamemode()->equals($gameMode)){
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_failure($target->getName()));
|
||||
return true;
|
||||
}
|
||||
|
||||
$target->setGamemode($gameMode);
|
||||
|
@ -34,9 +34,9 @@ use function round;
|
||||
|
||||
class GarbageCollectorCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"gc",
|
||||
KnownTranslationFactory::pocketmine_command_gc_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_GC);
|
||||
|
@ -41,13 +41,16 @@ use function implode;
|
||||
|
||||
class GiveCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"give",
|
||||
KnownTranslationFactory::pocketmine_command_give_description(),
|
||||
KnownTranslationFactory::pocketmine_command_give_usage()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_GIVE);
|
||||
$this->setPermission(implode(";", [
|
||||
DefaultPermissionNames::COMMAND_GIVE_SELF,
|
||||
DefaultPermissionNames::COMMAND_GIVE_OTHER
|
||||
]));
|
||||
}
|
||||
|
||||
public function execute(CommandSender $sender, string $commandLabel, array $args){
|
||||
@ -55,9 +58,8 @@ class GiveCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $sender->getServer()->getPlayerByPrefix($args[0]);
|
||||
$player = $this->fetchPermittedPlayerTarget($sender, $args[0], DefaultPermissionNames::COMMAND_GIVE_SELF, DefaultPermissionNames::COMMAND_GIVE_OTHER);
|
||||
if($player === null){
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_generic_player_notFound()->prefix(TextFormat::RED));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -44,9 +44,9 @@ use const SORT_NATURAL;
|
||||
|
||||
class HelpCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"help",
|
||||
KnownTranslationFactory::pocketmine_command_help_description(),
|
||||
KnownTranslationFactory::commands_help_usage(),
|
||||
["?"]
|
||||
|
@ -37,9 +37,9 @@ use function trim;
|
||||
|
||||
class KickCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"kick",
|
||||
KnownTranslationFactory::pocketmine_command_kick_description(),
|
||||
KnownTranslationFactory::commands_kick_usage()
|
||||
);
|
||||
@ -55,7 +55,7 @@ class KickCommand extends VanillaCommand{
|
||||
$reason = trim(implode(" ", $args));
|
||||
|
||||
if(($player = $sender->getServer()->getPlayerByPrefix($name)) instanceof Player){
|
||||
$player->kick("Kicked by admin." . ($reason !== "" ? " Reason: " . $reason : ""));
|
||||
$player->kick($reason !== "" ? KnownTranslationFactory::pocketmine_disconnect_kick($reason) : KnownTranslationFactory::pocketmine_disconnect_kick_noReason());
|
||||
if($reason !== ""){
|
||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_kick_success_reason($player->getName(), $reason));
|
||||
}else{
|
||||
|
@ -29,16 +29,14 @@ use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function count;
|
||||
use function implode;
|
||||
|
||||
class KillCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"kill",
|
||||
KnownTranslationFactory::pocketmine_command_kill_description(),
|
||||
KnownTranslationFactory::pocketmine_command_kill_usage(),
|
||||
["suicide"]
|
||||
@ -51,32 +49,16 @@ class KillCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
if(count($args) === 1){
|
||||
if(!$this->testPermission($sender, DefaultPermissionNames::COMMAND_KILL_OTHER)){
|
||||
return true;
|
||||
}
|
||||
|
||||
$player = $sender->getServer()->getPlayerByPrefix($args[0]);
|
||||
|
||||
if($player instanceof Player){
|
||||
$player->attack(new EntityDamageEvent($player, EntityDamageEvent::CAUSE_SUICIDE, 1000));
|
||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_kill_successful($player->getName()));
|
||||
}else{
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_generic_player_notFound()->prefix(TextFormat::RED));
|
||||
}
|
||||
|
||||
$player = $this->fetchPermittedPlayerTarget($sender, $args[0] ?? null, DefaultPermissionNames::COMMAND_KILL_SELF, DefaultPermissionNames::COMMAND_KILL_OTHER);
|
||||
if($player === null){
|
||||
return true;
|
||||
}
|
||||
|
||||
if($sender instanceof Player){
|
||||
if(!$this->testPermission($sender, DefaultPermissionNames::COMMAND_KILL_SELF)){
|
||||
return true;
|
||||
}
|
||||
|
||||
$sender->attack(new EntityDamageEvent($sender, EntityDamageEvent::CAUSE_SUICIDE, 1000));
|
||||
$player->attack(new EntityDamageEvent($player, EntityDamageEvent::CAUSE_SUICIDE, 1000));
|
||||
if($player === $sender){
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_kill_successful($sender->getName()));
|
||||
}else{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_kill_successful($player->getName()));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -36,9 +36,9 @@ use const SORT_STRING;
|
||||
|
||||
class ListCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"list",
|
||||
KnownTranslationFactory::pocketmine_command_list_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_LIST);
|
||||
|
@ -34,9 +34,9 @@ use function implode;
|
||||
|
||||
class MeCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"me",
|
||||
KnownTranslationFactory::pocketmine_command_me_description(),
|
||||
KnownTranslationFactory::commands_me_usage()
|
||||
);
|
||||
|
@ -35,9 +35,9 @@ use function count;
|
||||
|
||||
class OpCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"op",
|
||||
KnownTranslationFactory::pocketmine_command_op_description(),
|
||||
KnownTranslationFactory::commands_op_usage()
|
||||
);
|
||||
|
@ -32,9 +32,9 @@ use function count;
|
||||
|
||||
class PardonCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"pardon",
|
||||
KnownTranslationFactory::pocketmine_command_unban_player_description(),
|
||||
KnownTranslationFactory::commands_unban_usage(),
|
||||
["unban"]
|
||||
|
@ -33,9 +33,9 @@ use function inet_pton;
|
||||
|
||||
class PardonIpCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"pardon-ip",
|
||||
KnownTranslationFactory::pocketmine_command_unban_ip_description(),
|
||||
KnownTranslationFactory::commands_unbanip_usage(),
|
||||
["unban-ip"]
|
||||
|
@ -74,9 +74,9 @@ use function strtolower;
|
||||
|
||||
class ParticleCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"particle",
|
||||
KnownTranslationFactory::pocketmine_command_particle_description(),
|
||||
KnownTranslationFactory::pocketmine_command_particle_usage()
|
||||
);
|
||||
|
@ -36,9 +36,9 @@ use const SORT_STRING;
|
||||
|
||||
class PluginsCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"plugins",
|
||||
KnownTranslationFactory::pocketmine_command_plugins_description(),
|
||||
null,
|
||||
["pl"]
|
||||
|
@ -32,9 +32,9 @@ use function round;
|
||||
|
||||
class SaveCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"save-all",
|
||||
KnownTranslationFactory::pocketmine_command_save_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_SAVE_PERFORM);
|
||||
|
@ -30,9 +30,9 @@ use pocketmine\permission\DefaultPermissionNames;
|
||||
|
||||
class SaveOffCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"save-off",
|
||||
KnownTranslationFactory::pocketmine_command_saveoff_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_SAVE_DISABLE);
|
||||
|
@ -30,9 +30,9 @@ use pocketmine\permission\DefaultPermissionNames;
|
||||
|
||||
class SaveOnCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"save-on",
|
||||
KnownTranslationFactory::pocketmine_command_saveon_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_SAVE_ENABLE);
|
||||
|
@ -35,9 +35,9 @@ use function implode;
|
||||
|
||||
class SayCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"say",
|
||||
KnownTranslationFactory::pocketmine_command_say_description(),
|
||||
KnownTranslationFactory::commands_say_usage()
|
||||
);
|
||||
|
@ -30,9 +30,9 @@ use pocketmine\player\Player;
|
||||
|
||||
class SeedCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"seed",
|
||||
KnownTranslationFactory::pocketmine_command_seed_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_SEED);
|
||||
|
@ -36,9 +36,9 @@ use function count;
|
||||
|
||||
class SetWorldSpawnCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"setworldspawn",
|
||||
KnownTranslationFactory::pocketmine_command_setworldspawn_description(),
|
||||
KnownTranslationFactory::commands_setworldspawn_usage()
|
||||
);
|
||||
|
@ -29,41 +29,30 @@ use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\World;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function round;
|
||||
|
||||
class SpawnpointCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"spawnpoint",
|
||||
KnownTranslationFactory::pocketmine_command_spawnpoint_description(),
|
||||
KnownTranslationFactory::commands_spawnpoint_usage()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_SPAWNPOINT);
|
||||
$this->setPermission(implode(";", [
|
||||
DefaultPermissionNames::COMMAND_SPAWNPOINT_SELF,
|
||||
DefaultPermissionNames::COMMAND_SPAWNPOINT_OTHER
|
||||
]));
|
||||
}
|
||||
|
||||
public function execute(CommandSender $sender, string $commandLabel, array $args){
|
||||
$target = null;
|
||||
|
||||
if(count($args) === 0){
|
||||
if($sender instanceof Player){
|
||||
$target = $sender;
|
||||
}else{
|
||||
$sender->sendMessage(TextFormat::RED . "Please provide a player!");
|
||||
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
$target = $sender->getServer()->getPlayerByPrefix($args[0]);
|
||||
if($target === null){
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_generic_player_notFound()->prefix(TextFormat::RED));
|
||||
|
||||
return true;
|
||||
}
|
||||
$target = $this->fetchPermittedPlayerTarget($sender, $args[0] ?? null, DefaultPermissionNames::COMMAND_SPAWNPOINT_SELF, DefaultPermissionNames::COMMAND_SPAWNPOINT_OTHER);
|
||||
if($target === null){
|
||||
return true;
|
||||
}
|
||||
|
||||
if(count($args) === 4){
|
||||
@ -77,19 +66,13 @@ class SpawnpointCommand extends VanillaCommand{
|
||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_spawnpoint_success($target->getName(), (string) round($x, 2), (string) round($y, 2), (string) round($z, 2)));
|
||||
|
||||
return true;
|
||||
}elseif(count($args) <= 1){
|
||||
if($sender instanceof Player){
|
||||
$cpos = $sender->getPosition();
|
||||
$pos = Position::fromObject($cpos->floor(), $cpos->getWorld());
|
||||
$target->setSpawn($pos);
|
||||
}elseif(count($args) <= 1 && $sender instanceof Player){
|
||||
$cpos = $sender->getPosition();
|
||||
$pos = Position::fromObject($cpos->floor(), $cpos->getWorld());
|
||||
$target->setSpawn($pos);
|
||||
|
||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_spawnpoint_success($target->getName(), (string) round($pos->x, 2), (string) round($pos->y, 2), (string) round($pos->z, 2)));
|
||||
return true;
|
||||
}else{
|
||||
$sender->sendMessage(TextFormat::RED . "Please provide a player!");
|
||||
|
||||
return true;
|
||||
}
|
||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_spawnpoint_success($target->getName(), (string) round($pos->x, 2), (string) round($pos->y, 2), (string) round($pos->z, 2)));
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new InvalidCommandSyntaxException();
|
||||
|
@ -36,9 +36,9 @@ use function round;
|
||||
|
||||
class StatusCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"status",
|
||||
KnownTranslationFactory::pocketmine_command_status_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_STATUS);
|
||||
|
@ -30,9 +30,9 @@ use pocketmine\permission\DefaultPermissionNames;
|
||||
|
||||
class StopCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"stop",
|
||||
KnownTranslationFactory::pocketmine_command_stop_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_STOP);
|
||||
|
@ -35,18 +35,22 @@ use pocketmine\utils\TextFormat;
|
||||
use pocketmine\world\World;
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function round;
|
||||
|
||||
class TeleportCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"tp",
|
||||
KnownTranslationFactory::pocketmine_command_tp_description(),
|
||||
KnownTranslationFactory::commands_tp_usage(),
|
||||
["teleport"]
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_TELEPORT);
|
||||
$this->setPermission(implode(";", [
|
||||
DefaultPermissionNames::COMMAND_TELEPORT_SELF,
|
||||
DefaultPermissionNames::COMMAND_TELEPORT_OTHER
|
||||
]));
|
||||
}
|
||||
|
||||
private function findPlayer(CommandSender $sender, string $playerName) : ?Player{
|
||||
@ -63,31 +67,25 @@ class TeleportCommand extends VanillaCommand{
|
||||
case 1: // /tp targetPlayer
|
||||
case 3: // /tp x y z
|
||||
case 5: // /tp x y z yaw pitch - TODO: 5 args could be target x y z yaw :(
|
||||
if(!($sender instanceof Player)){
|
||||
$sender->sendMessage(TextFormat::RED . "Please provide a player!");
|
||||
return true;
|
||||
}
|
||||
|
||||
$subject = $sender;
|
||||
$targetArgs = $args;
|
||||
$subjectName = null; //self
|
||||
break;
|
||||
case 2: // /tp player1 player2
|
||||
case 4: // /tp player1 x y z - TODO: 4 args could be x y z yaw :(
|
||||
case 6: // /tp player1 x y z yaw pitch
|
||||
$subject = $this->findPlayer($sender, $args[0]);
|
||||
if($subject === null){
|
||||
return true;
|
||||
}
|
||||
$targetArgs = $args;
|
||||
array_shift($targetArgs);
|
||||
$subjectName = array_shift($args);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
switch(count($targetArgs)){
|
||||
$subject = $this->fetchPermittedPlayerTarget($sender, $subjectName, DefaultPermissionNames::COMMAND_TELEPORT_SELF, DefaultPermissionNames::COMMAND_TELEPORT_OTHER);
|
||||
if($subject === null){
|
||||
return true;
|
||||
}
|
||||
|
||||
switch(count($args)){
|
||||
case 1:
|
||||
$targetPlayer = $this->findPlayer($sender, $targetArgs[0]);
|
||||
$targetPlayer = $this->findPlayer($sender, $args[0]);
|
||||
if($targetPlayer === null){
|
||||
return true;
|
||||
}
|
||||
@ -99,17 +97,17 @@ class TeleportCommand extends VanillaCommand{
|
||||
case 3:
|
||||
case 5:
|
||||
$base = $subject->getLocation();
|
||||
if(count($targetArgs) === 5){
|
||||
$yaw = (float) $targetArgs[3];
|
||||
$pitch = (float) $targetArgs[4];
|
||||
if(count($args) === 5){
|
||||
$yaw = (float) $args[3];
|
||||
$pitch = (float) $args[4];
|
||||
}else{
|
||||
$yaw = $base->yaw;
|
||||
$pitch = $base->pitch;
|
||||
}
|
||||
|
||||
$x = $this->getRelativeDouble($base->x, $sender, $targetArgs[0]);
|
||||
$y = $this->getRelativeDouble($base->y, $sender, $targetArgs[1], World::Y_MIN, World::Y_MAX);
|
||||
$z = $this->getRelativeDouble($base->z, $sender, $targetArgs[2]);
|
||||
$x = $this->getRelativeDouble($base->x, $sender, $args[0]);
|
||||
$y = $this->getRelativeDouble($base->y, $sender, $args[1], World::Y_MIN, World::Y_MAX);
|
||||
$z = $this->getRelativeDouble($base->z, $sender, $args[2]);
|
||||
$targetLocation = new Location($x, $y, $z, $base->getWorld(), $yaw, $pitch);
|
||||
|
||||
$subject->teleport($targetLocation);
|
||||
|
@ -36,9 +36,9 @@ use function implode;
|
||||
|
||||
class TellCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(string $name){
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
$name,
|
||||
"tell",
|
||||
KnownTranslationFactory::pocketmine_command_tell_description(),
|
||||
KnownTranslationFactory::commands_message_usage(),
|
||||
["w", "msg"]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user