mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-11 12:08:05 +00:00
Compare commits
106 Commits
Author | SHA1 | Date | |
---|---|---|---|
9f60484212 | |||
3031d89ec5 | |||
883e135bc0 | |||
4448f603a6 | |||
9365525efa | |||
17bee5e349 | |||
c6e0753c3e | |||
2ae7ba275b | |||
6aa0a82341 | |||
0af08a7375 | |||
81c1613e5d | |||
9cf8f608d8 | |||
dd4f26a9cf | |||
f976545f56 | |||
9929fb0abd | |||
37e453b875 | |||
b7578fef9c | |||
09eb904f6b | |||
b47d6bbc22 | |||
aa26ddf8b1 | |||
119c72980f | |||
eba888449d | |||
dac76f0e0f | |||
89fe8f7f10 | |||
2d77b1e364 | |||
e59a4296f8 | |||
6856761946 | |||
4fe3401182 | |||
e80ad22702 | |||
c22ab37372 | |||
1f9d672cfc | |||
974cbae725 | |||
b53f88027e | |||
9a0f723dff | |||
ab2003a85d | |||
4befd9095a | |||
06623d788a | |||
730ee74a65 | |||
700e0afee0 | |||
4b9712fdee | |||
dbd015b866 | |||
a498b0415a | |||
5b01cf72dd | |||
ec21c2baa0 | |||
11a0d9b502 | |||
a7fc245291 | |||
6db51e2380 | |||
d6f35f2342 | |||
d1df72ec78 | |||
9bd6d5c67e | |||
aaa23361d1 | |||
691d92a959 | |||
50101663f2 | |||
e369966890 | |||
63f57841de | |||
ac3bba0a11 | |||
1ff3df6ff0 | |||
4e29b216bf | |||
809dad2ac8 | |||
e238d583b8 | |||
3f89bd7bff | |||
8da7e789fd | |||
0766952f39 | |||
eeee1fbe73 | |||
46c224da86 | |||
3c001b310f | |||
198a106b9f | |||
1f5e0bc96d | |||
41f7c07703 | |||
f0a0c9a85f | |||
5b620d964e | |||
756840f11d | |||
df2c3136c9 | |||
a6b5cddd5a | |||
5b9453af43 | |||
8bba25f4f5 | |||
f9bd7016aa | |||
213406fc60 | |||
7ff6e5895e | |||
2e6b62fdec | |||
4fc5b9772a | |||
5d4880b0a7 | |||
2b1a0e1e72 | |||
cd022f1592 | |||
4ae3fd7734 | |||
b2249f93c0 | |||
303344783a | |||
75e0844ff5 | |||
18fabf5466 | |||
2751c59979 | |||
d99ffbd66c | |||
a34f3261cb | |||
8ce0022de6 | |||
fb6491ddeb | |||
3b961d0e5f | |||
a60fc4cc28 | |||
b747899fdd | |||
57b6451e16 | |||
8cf025a2df | |||
8480ee82ea | |||
a6c1b7bf9c | |||
c267137fde | |||
461bc94236 | |||
4fed08bcd4 | |||
e990c5a0a5 | |||
c616d9bb7c |
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Help & support on Discord
|
||||
url: https://discord.gg/bmSAZBG
|
||||
about: We don't accept support requests on the issue tracker. Please try asking on Discord instead.
|
||||
- name: Help & support on forums
|
||||
url: https://forums.pmmp.io
|
||||
about: We don't accept support requests on the issue tracker. Please try asking on forums instead.
|
||||
- name: Documentation
|
||||
url: https://pmmp.rtfd.io
|
||||
about: PocketMine-MP documentation
|
14
.github/ISSUE_TEMPLATE/help---support.md
vendored
14
.github/ISSUE_TEMPLATE/help---support.md
vendored
@ -1,14 +0,0 @@
|
||||
---
|
||||
name: Help & support
|
||||
about: We don't accept support requests here. Try the links on the README.
|
||||
title: ''
|
||||
labels: Support request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
We don't accept support requests on the issue tracker. Please try the following links instead:
|
||||
|
||||
Documentation: http://pmmp.rtfd.io
|
||||
Forums: https://forums.pmmp.io
|
||||
Discord: https://discord.gg/bmSAZBG
|
@ -1,12 +0,0 @@
|
||||
---
|
||||
name: Security/DoS vulnerability
|
||||
about: 'Bug or exploit that can be used to attack servers (hint: don''t report it
|
||||
on a public issue tracker)'
|
||||
title: ''
|
||||
labels: 'Auto: Spam'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please DO NOT report security vulnerabilities here.
|
||||
Instead, send an email to team@pmmp.io or contact a developer directly, IN PRIVATE.
|
8
.gitmodules
vendored
8
.gitmodules
vendored
@ -1,12 +1,12 @@
|
||||
[submodule "src/pocketmine/lang/locale"]
|
||||
path = src/pocketmine/lang/locale
|
||||
url = https://github.com/pmmp/PocketMine-Language.git
|
||||
url = https://github.com/pmmp/Language.git
|
||||
[submodule "tests/preprocessor"]
|
||||
path = build/preprocessor
|
||||
url = https://github.com/pmmp/preprocessor.git
|
||||
[submodule "tests/plugins/PocketMine-DevTools"]
|
||||
path = tests/plugins/PocketMine-DevTools
|
||||
url = https://github.com/pmmp/PocketMine-DevTools.git
|
||||
[submodule "tests/plugins/DevTools"]
|
||||
path = tests/plugins/DevTools
|
||||
url = https://github.com/pmmp/DevTools.git
|
||||
[submodule "build/php"]
|
||||
path = build/php
|
||||
url = https://github.com/pmmp/php-build-scripts.git
|
||||
|
19
.travis.yml
19
.travis.yml
@ -1,20 +1,5 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.3
|
||||
|
||||
before_script:
|
||||
- phpenv config-rm xdebug.ini
|
||||
- echo | pecl install channel://pecl.php.net/yaml-2.1.0
|
||||
- git clone https://github.com/pmmp/pthreads.git
|
||||
- cd pthreads
|
||||
- git checkout 646dac62ae0d48c1ada7b007e15575fb84f7d71d
|
||||
- phpize
|
||||
- ./configure
|
||||
- make
|
||||
- make install
|
||||
- cd ..
|
||||
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
import:
|
||||
source: ./tests/travis/setup-php.yml
|
||||
|
||||
script:
|
||||
- composer install --prefer-dist
|
||||
|
@ -116,7 +116,7 @@ class ExampleClass{
|
||||
<!-- TODO: RFC and voting on the forums instead -->
|
||||
### RFC and Voting
|
||||
* These are big Pull Requests or contributions that change important behavior.
|
||||
* RFCs will be tagged with the *PR: RFC* label
|
||||
* RFCs will be tagged with the *Type: Request For Comments* label
|
||||
* A vote will be held once the RFC is ready. All users can vote commenting on the Pull Request
|
||||
* Comments MUST use "Yes" or "No" on the FIRST sentence to signify the vote, except when they don't want it to be counted.
|
||||
* If your comment is a voting comment, specify the reason of your vote or it won't be counted.
|
||||
|
@ -19,7 +19,7 @@
|
||||
## For developers
|
||||
* [Building and running from source](BUILDING.md)
|
||||
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development
|
||||
* [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins
|
||||
* [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
|
||||
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
||||
* [Contributing Guidelines](CONTRIBUTING.md)
|
||||
|
||||
|
33
SECURITY.md
Normal file
33
SECURITY.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
The following release lines are currently receiving active security updates and bug fixes:
|
||||
|
||||
| Version | Supported |
|
||||
| -------- | ------------------ |
|
||||
| 3.15.x | :white_check_mark: |
|
||||
| < 3.15.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
**DO NOT report vulnerabilities on the GitHub issue tracker.**
|
||||
GitHub is public and anyone can see the issues you post on the issue tracker, including people who would exploit vulnerabilities for their own gain.
|
||||
|
||||
**WARNING: You may put live servers at risk by reporting a vulnerability on the GitHub issue tracker.**
|
||||
|
||||
**Contact us** by sending an email to [**team@pmmp.io**](mailto:team@pmmp.io?subject=Security%20Vulnerability%20in%20PocketMine-MP). Include the following information:
|
||||
|
||||
- Version of PocketMine-MP
|
||||
- Detailed description of the vulnerability (e.g. how to exploit it, what the effects are)
|
||||
|
||||
Please note that we can't guarantee a reply to every email.
|
||||
|
||||
## FAQ
|
||||
### Do you offer a bug bounty?
|
||||
No.
|
||||
|
||||
### How soon can I expect a fix for a vulnerability I've reported?
|
||||
This depends on the nature of the problem. We can't provide any general ETA (nor would it be wise to provide one).
|
||||
In general, it depends on when developers have time to look into the problem, how complex the problem is to fix, and how many users it impacts.
|
||||
|
||||
When a fix for a severe vulnerability is pushed, a patch release for the target version will usually be released within 24 hours so that users can update.
|
Submodule build/php updated: cec63c3093...3a3e3495c3
40
changelogs/3.14.md
Normal file
40
changelogs/3.14.md
Normal file
@ -0,0 +1,40 @@
|
||||
**For Minecraft: Bedrock Edition 1.16.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.14.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.16.0.
|
||||
- Removed compatibility with 1.14.60.
|
||||
|
||||
## Known issues (please don't open issues for these)
|
||||
- Walls don't connect to each other
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
|
||||
# 3.14.1
|
||||
- All skins are now trusted, bypassing the client-side trusted skin setting. Note that this means that NSFW skin filtering will **not** apply.
|
||||
- Fixed projectile motion being altered by ladders.
|
||||
- Fixed client-sided crashes when pressing E repeatedly very quickly on a high-latency connection.
|
||||
- `/plugins`, `/whitelist list`, `/banlist` and `/list` now show output in alphabetical order.
|
||||
- Some `pocketmine\event` APIs which accept arrays now have more robust type checking, fixing type errors caused by plugin input occurring in core code.
|
||||
- `Attribute::getAttributeByName()` is now aware of the `minecraft:lava_movement` attribute.
|
||||
|
||||
# 3.14.2
|
||||
- Exception stack traces are now logged as CRITICAL. It's hoped that users will recognize that they are just as important as the error message and not leave them out when asking for help with errors on Discord.
|
||||
- `TaskScheduler` no longer accepts tasks that already have a handler. This fixes undefined behaviour which occurs when scheduling the same task instance twice, but it does break plugins such as **MyPlot** which unintentionally used this buggy behaviour.
|
||||
- Players will now correctly receive the needed number of spawn chunks if they are teleported between `PlayerLoginEvent` and `PlayerJoinEvent`. This fixes a bug that could occur when teleporting players in delayed tasks between login and join.
|
||||
- `PlayerRespawnEvent->setRespawnPosition()` now throws an exception if the provided `Position` has an invalid world associated with it (null or unloaded).
|
||||
- Fixed a crash that occurred when stats reporting was enabled.
|
||||
|
||||
# 3.14.3
|
||||
- Fixed deprecation error when running `/whitelist list` on PHP 7.4.
|
||||
- Fixed podzol breaking animation being incorrect (incorrect hardness).
|
||||
- `Entity::getSaveId()` now reports the class name in the message thrown for unregistered entities.
|
||||
- Fixed `CraftingManager->validate()` producing different results when called multiple times for the same transaction.
|
||||
- Fixed various issues with batch-crafting items using the recipe book and shift-clicking.
|
||||
- `tests/plugins/PocketMine-DevTools` submodule has been renamed to `tests/plugins/DevTools`.
|
29
changelogs/3.15.md
Normal file
29
changelogs/3.15.md
Normal file
@ -0,0 +1,29 @@
|
||||
**For Minecraft: Bedrock Edition 1.16.20**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.15.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.16.20.
|
||||
- Removed compatibility with 1.16.0.
|
||||
|
||||
## Known issues (please don't open issues for these)
|
||||
- Walls don't connect to each other
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
|
||||
# 3.15.1
|
||||
- Fixed various PHP 7.4 compatibility issues in Composer dependencies (primarily callback-validator).
|
||||
- Fixed LevelDB worlds with corrupted `level.dat` crashing the server instead of failing gracefully.
|
||||
- Fixed error spam when using strings for layers in flatworld presets (`e.g. bedrock,3xdirt,grass`).
|
||||
- Fixed blocks not getting updated properly on explosions.
|
||||
- Fixed `BlockGrowEvent` not being called when sugarcane grows.
|
||||
- Potato crops now drop poisonous potatoes when harvested.
|
||||
- Fixed the wrong number of potatoes being dropped when harvesting potato crops.
|
||||
- Players no longer get pullbacks when sprinting on slabs, stairs and various other blocks when `player.anti-cheat.allow-movement-cheats` is set to `false`. (This bug has been around for over 5 years, so many of you will be used to its existence.)
|
||||
- Fixed entity collision box calculation not taking clip distance into account.
|
||||
- Entities now step up the correct height of the target block, instead of jumping into the air 0.6 blocks and falling back down.
|
@ -33,12 +33,12 @@
|
||||
"pocketmine/classloader": "^0.1.0",
|
||||
"pocketmine/log": "^0.2.0",
|
||||
"pocketmine/log-pthreads": "^0.1.0",
|
||||
"pocketmine/callback-validator": "^1.0.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"adhocore/json-comment": "^0.1.0",
|
||||
"ocramius/package-versions": "^1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "0.12.29",
|
||||
"phpstan/phpstan": "0.12.40",
|
||||
"phpstan/phpstan-phpunit": "^0.12.6",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.2",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
|
923
composer.lock
generated
923
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,6 @@ This site contains auto-generated API documentation for PocketMine-MP (and depen
|
||||
This site can be accessed via https://apidoc.pmmp.io.
|
||||
|
||||
### Additional developer resources
|
||||
- [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins
|
||||
- [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
|
||||
- [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
||||
- [DeveloperDocs](https://github.com/pmmp/DeveloperDocs/) - Reference, guides and specifications for the PocketMine-MP API
|
||||
|
@ -20,6 +20,8 @@ parameters:
|
||||
checkExplicitMixed: true
|
||||
bootstrapFiles:
|
||||
- tests/phpstan/bootstrap.php
|
||||
scanDirectories:
|
||||
- tests/plugins/TesterPlugin
|
||||
scanFiles:
|
||||
- src/pocketmine/PocketMine.php
|
||||
- build/make-release.php
|
||||
@ -29,6 +31,7 @@ parameters:
|
||||
- build/make-release.php
|
||||
- build/server-phar.php
|
||||
- tests/phpunit
|
||||
- tests/plugins/TesterPlugin
|
||||
dynamicConstantNames:
|
||||
- pocketmine\IS_DEVELOPMENT_BUILD
|
||||
- pocketmine\DEBUG
|
||||
|
@ -113,6 +113,7 @@ use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\BookEditPacket;
|
||||
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
|
||||
use pocketmine\network\mcpe\protocol\DataPacket;
|
||||
use pocketmine\network\mcpe\protocol\DisconnectPacket;
|
||||
use pocketmine\network\mcpe\protocol\InteractPacket;
|
||||
@ -148,6 +149,7 @@ use pocketmine\network\mcpe\protocol\types\CommandParameter;
|
||||
use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||
use pocketmine\network\mcpe\protocol\types\GameMode;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
use pocketmine\network\mcpe\protocol\types\PersonaPieceTintColor;
|
||||
use pocketmine\network\mcpe\protocol\types\PersonaSkinPiece;
|
||||
@ -156,6 +158,8 @@ use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinData;
|
||||
use pocketmine\network\mcpe\protocol\types\SkinImage;
|
||||
use pocketmine\network\mcpe\protocol\types\SpawnSettings;
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
|
||||
use pocketmine\network\mcpe\VerifyLoginTask;
|
||||
@ -173,6 +177,7 @@ use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\UUID;
|
||||
use function abs;
|
||||
use function array_key_exists;
|
||||
use function array_merge;
|
||||
use function array_values;
|
||||
use function assert;
|
||||
@ -225,6 +230,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
private const RESOURCE_PACK_CHUNK_SIZE = 128 * 1024; //128KB
|
||||
|
||||
//TODO: HACK!
|
||||
//these IDs are used for 1.16 to restore 1.14ish crafting & inventory behaviour; since they don't seem to have any
|
||||
//effect on the behaviour of inventory transactions I don't currently plan to integrate these into the main system.
|
||||
private const RESERVED_WINDOW_ID_RANGE_START = ContainerIds::LAST - 10;
|
||||
private const RESERVED_WINDOW_ID_RANGE_END = ContainerIds::LAST;
|
||||
public const HARDCODED_CRAFTING_GRID_WINDOW_ID = self::RESERVED_WINDOW_ID_RANGE_START + 1;
|
||||
public const HARDCODED_INVENTORY_WINDOW_ID = self::RESERVED_WINDOW_ID_RANGE_START + 2;
|
||||
|
||||
/**
|
||||
* Validates the given username.
|
||||
*/
|
||||
@ -304,6 +317,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
/** @var CraftingTransaction|null */
|
||||
protected $craftingTransaction = null;
|
||||
|
||||
/**
|
||||
* TODO: HACK! This tracks GUIs for inventories that the server considers "always open" so that the client can't
|
||||
* open them twice. (1.16 hack)
|
||||
* @var true[]
|
||||
* @phpstan-var array<int, true>
|
||||
* @internal
|
||||
*/
|
||||
public $openHardcodedWindows = [];
|
||||
|
||||
/** @var int */
|
||||
protected $messageCounter = 2;
|
||||
/** @var bool */
|
||||
@ -1230,11 +1252,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
$this->spawnPosition = new Position($pos->x, $pos->y, $pos->z, $level);
|
||||
$pk = new SetSpawnPositionPacket();
|
||||
$pk->x = $this->spawnPosition->getFloorX();
|
||||
$pk->y = $this->spawnPosition->getFloorY();
|
||||
$pk->z = $this->spawnPosition->getFloorZ();
|
||||
$pk->x = $pk->x2 = $this->spawnPosition->getFloorX();
|
||||
$pk->y = $pk->y2 = $this->spawnPosition->getFloorY();
|
||||
$pk->z = $pk->z2 = $this->spawnPosition->getFloorZ();
|
||||
$pk->dimension = DimensionIds::OVERWORLD;
|
||||
$pk->spawnType = SetSpawnPositionPacket::TYPE_PLAYER_SPAWN;
|
||||
$pk->spawnForced = false;
|
||||
|
||||
$this->dataPacket($pk);
|
||||
}
|
||||
|
||||
@ -1578,10 +1601,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$dy = $newPos->y - $this->y;
|
||||
$dz = $newPos->z - $this->z;
|
||||
|
||||
//the client likes to clip into blocks like stairs, but we do full server-side prediction of that without
|
||||
//help from the client's position changes, so we deduct the expected clip height from the moved distance.
|
||||
$expectedClipDistance = $this->ySize * (1 - self::STEP_CLIP_MULTIPLIER);
|
||||
$dy -= $expectedClipDistance;
|
||||
$this->move($dx, $dy, $dz);
|
||||
|
||||
$diff = $this->distanceSquared($newPos);
|
||||
|
||||
//TODO: Explore lowering this threshold now that stairs work properly.
|
||||
if($this->isSurvival() and $diff > 0.0625){
|
||||
$ev = new PlayerIllegalMoveEvent($this, $newPos, new Vector3($this->lastX, $this->lastY, $this->lastZ));
|
||||
$ev->setCancelled($this->allowMovementCheats);
|
||||
@ -1591,7 +1619,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
if(!$ev->isCancelled()){
|
||||
$revert = true;
|
||||
$this->server->getLogger()->debug($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidMove", [$this->getName()]));
|
||||
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $newPos);
|
||||
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $newPos . ", expected clip distance: $expectedClipDistance");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1875,7 +1903,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
|
||||
$this->close("", $this->server->getLanguage()->translateString("pocketmine.disconnect.incompatibleProtocol", [$packet->protocol ?? "unknown"]), false);
|
||||
$this->close("", $this->server->getLanguage()->translateString("pocketmine.disconnect.incompatibleProtocol", [$packet->protocol]), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2202,7 +2230,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$pk->pitch = $this->pitch;
|
||||
$pk->yaw = $this->yaw;
|
||||
$pk->seed = -1;
|
||||
$pk->dimension = DimensionIds::OVERWORLD; //TODO: implement this properly
|
||||
$pk->spawnSettings = new SpawnSettings(SpawnSettings::BIOME_TYPE_DEFAULT, "", DimensionIds::OVERWORLD); //TODO: implement this properly
|
||||
$pk->worldGamemode = Player::getClientFriendlyGamemode($this->server->getGamemode());
|
||||
$pk->difficulty = $this->level->getDifficulty();
|
||||
$pk->spawnX = $spawnPosition->getFloorX();
|
||||
@ -2370,22 +2398,17 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
/** @var InventoryAction[] $actions */
|
||||
$actions = [];
|
||||
$isCraftingPart = false;
|
||||
$isFinalCraftingPart = false;
|
||||
foreach($packet->actions as $networkInventoryAction){
|
||||
if(
|
||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER and
|
||||
$networkInventoryAction->windowId === ContainerIds::UI and
|
||||
$networkInventoryAction->inventorySlot === 50 and
|
||||
!$networkInventoryAction->oldItem->equalsExact($networkInventoryAction->newItem)
|
||||
){
|
||||
$isCraftingPart = true;
|
||||
if(!$networkInventoryAction->oldItem->isNull() and $networkInventoryAction->newItem->isNull()){
|
||||
$isFinalCraftingPart = true;
|
||||
}
|
||||
}elseif(
|
||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_TODO and (
|
||||
$networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT or
|
||||
$networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_USE_INGREDIENT
|
||||
) or (
|
||||
$this->craftingTransaction !== null &&
|
||||
!$networkInventoryAction->oldItem->equalsExact($networkInventoryAction->newItem) &&
|
||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER &&
|
||||
$networkInventoryAction->windowId === ContainerIds::UI &&
|
||||
$networkInventoryAction->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT
|
||||
)
|
||||
){
|
||||
$isCraftingPart = true;
|
||||
@ -2411,23 +2434,23 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
if($isFinalCraftingPart){
|
||||
//we get the actions for this in several packets, so we need to wait until we have all the pieces before
|
||||
//trying to execute it
|
||||
|
||||
$ret = true;
|
||||
try{
|
||||
$this->craftingTransaction->execute();
|
||||
}catch(TransactionValidationException $e){
|
||||
$this->server->getLogger()->debug("Failed to execute crafting transaction for " . $this->getName() . ": " . $e->getMessage());
|
||||
$ret = false;
|
||||
}
|
||||
|
||||
$this->craftingTransaction = null;
|
||||
return $ret;
|
||||
try{
|
||||
$this->craftingTransaction->validate();
|
||||
}catch(TransactionValidationException $e){
|
||||
//transaction is incomplete - crafting transaction comes in lots of little bits, so we have to collect
|
||||
//all of the parts before we can execute it
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
try{
|
||||
$this->craftingTransaction->execute();
|
||||
return true;
|
||||
}catch(TransactionValidationException $e){
|
||||
$this->server->getLogger()->debug("Failed to execute crafting transaction for " . $this->getName() . ": " . $e->getMessage());
|
||||
return false;
|
||||
}finally{
|
||||
$this->craftingTransaction = null;
|
||||
}
|
||||
}elseif($this->craftingTransaction !== null){
|
||||
$this->server->getLogger()->debug("Got unexpected normal inventory action with incomplete crafting transaction from " . $this->getName() . ", refusing to execute crafting");
|
||||
$this->craftingTransaction = null;
|
||||
@ -2789,6 +2812,21 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
case InteractPacket::ACTION_LEAVE_VEHICLE:
|
||||
case InteractPacket::ACTION_MOUSEOVER:
|
||||
break; //TODO: handle these
|
||||
case InteractPacket::ACTION_OPEN_INVENTORY:
|
||||
if($target === $this && !array_key_exists($windowId = self::HARDCODED_INVENTORY_WINDOW_ID, $this->openHardcodedWindows)){
|
||||
//TODO: HACK! this restores 1.14ish behaviour, but this should be able to be listened to and
|
||||
//controlled by plugins. However, the player is always a subscriber to their own inventory so it
|
||||
//doesn't integrate well with the regular container system right now.
|
||||
$this->openHardcodedWindows[$windowId] = true;
|
||||
$pk = new ContainerOpenPacket();
|
||||
$pk->windowId = $windowId;
|
||||
$pk->type = WindowTypes::INVENTORY;
|
||||
$pk->x = $pk->y = $pk->z = 0;
|
||||
$pk->entityUniqueId = $this->getId();
|
||||
$this->sendDataPacket($pk);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
$this->server->getLogger()->debug("Unhandled/unknown interaction type " . $packet->action . " received from " . $this->getName());
|
||||
|
||||
@ -2848,7 +2886,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$target = $this->level->getBlock($pos);
|
||||
|
||||
$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, null, $packet->face, PlayerInteractEvent::LEFT_CLICK_BLOCK);
|
||||
if($this->level->checkSpawnProtection($this, $target)){
|
||||
if($this->isSpectator() || $this->level->checkSpawnProtection($this, $target)){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
|
||||
@ -3002,18 +3040,23 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
}
|
||||
|
||||
public function handleContainerClose(ContainerClosePacket $packet) : bool{
|
||||
if(!$this->spawned or $packet->windowId === 0){
|
||||
if(!$this->spawned){
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->doCloseInventory();
|
||||
|
||||
if(array_key_exists($packet->windowId, $this->openHardcodedWindows)){
|
||||
unset($this->openHardcodedWindows[$packet->windowId]);
|
||||
$pk = new ContainerClosePacket();
|
||||
$pk->windowId = $packet->windowId;
|
||||
$this->sendDataPacket($pk);
|
||||
return true;
|
||||
}
|
||||
if(isset($this->windowIndex[$packet->windowId])){
|
||||
(new InventoryCloseEvent($this->windowIndex[$packet->windowId], $this))->call();
|
||||
$this->removeWindow($this->windowIndex[$packet->windowId]);
|
||||
return true;
|
||||
}elseif($packet->windowId === 255){
|
||||
//Closed a fake window
|
||||
//removeWindow handles sending the appropriate
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3865,10 +3908,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
if($targets !== null){
|
||||
if(in_array($this, $targets, true)){
|
||||
$this->forceMoveSync = $pos->asVector3();
|
||||
$this->ySize = 0;
|
||||
}
|
||||
$this->server->broadcastPacket($targets, $pk);
|
||||
}else{
|
||||
$this->forceMoveSync = $pos->asVector3();
|
||||
$this->ySize = 0;
|
||||
$this->dataPacket($pk);
|
||||
}
|
||||
}
|
||||
@ -3888,6 +3933,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
|
||||
$this->resetFallDistance();
|
||||
$this->nextChunkOrderRun = 0;
|
||||
if($this->spawnChunkLoadCount !== -1){
|
||||
$this->spawnChunkLoadCount = 0;
|
||||
}
|
||||
$this->stopSleep();
|
||||
|
||||
//TODO: workaround for player last pos not getting updated
|
||||
@ -3983,7 +4031,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
if($forceId === null){
|
||||
$cnt = $this->windowCnt;
|
||||
do{
|
||||
$cnt = max(ContainerIds::FIRST, ($cnt + 1) % ContainerIds::LAST);
|
||||
$cnt = max(ContainerIds::FIRST, ($cnt + 1) % self::RESERVED_WINDOW_ID_RANGE_START);
|
||||
if($cnt === $this->windowCnt){ //wraparound, no free slots
|
||||
throw new \InvalidStateException("No free window IDs found");
|
||||
}
|
||||
@ -3991,7 +4039,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$this->windowCnt = $cnt;
|
||||
}else{
|
||||
$cnt = $forceId;
|
||||
if(isset($this->windowIndex[$cnt])){
|
||||
if(isset($this->windowIndex[$cnt]) or ($cnt >= self::RESERVED_WINDOW_ID_RANGE_START && $cnt <= self::RESERVED_WINDOW_ID_RANGE_END)){
|
||||
throw new \InvalidArgumentException("Requested force ID $forceId already in use");
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
|
||||
const _VERSION_INFO_INCLUDED = true;
|
||||
|
||||
const NAME = "PocketMine-MP";
|
||||
const BASE_VERSION = "3.13.1";
|
||||
const BASE_VERSION = "3.15.1";
|
||||
const IS_DEVELOPMENT_BUILD = false;
|
||||
const BUILD_NUMBER = 0;
|
||||
|
@ -36,7 +36,7 @@ use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\metadata\Metadatable;
|
||||
use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use function array_merge;
|
||||
|
@ -25,7 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||
use function min;
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,10 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\inventory\CraftingGrid;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
use pocketmine\Player;
|
||||
use function array_key_exists;
|
||||
|
||||
class CraftingTable extends Solid{
|
||||
|
||||
@ -50,6 +53,19 @@ class CraftingTable extends Solid{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG));
|
||||
|
||||
if(!array_key_exists($windowId = Player::HARDCODED_CRAFTING_GRID_WINDOW_ID, $player->openHardcodedWindows)){
|
||||
//TODO: HACK! crafting grid doesn't fit very well into the current PM container system, so this hack allows
|
||||
//it to carry on working approximately the same way as it did in 1.14
|
||||
$pk = new ContainerOpenPacket();
|
||||
$pk->windowId = $windowId;
|
||||
$pk->type = WindowTypes::WORKBENCH;
|
||||
$pk->x = $this->getFloorX();
|
||||
$pk->y = $this->getFloorY();
|
||||
$pk->z = $this->getFloorZ();
|
||||
$player->sendDataPacket($pk);
|
||||
$player->openHardcodedWindows[$windowId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -58,7 +59,7 @@ class Ladder extends Transparent{
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
if($entity->asVector3()->floor()->distanceSquared($this) < 1){ //entity coordinates must be inside block
|
||||
if($entity instanceof Living and $entity->asVector3()->floor()->distanceSquared($this) < 1){ //entity coordinates must be inside block
|
||||
$entity->resetFallDistance();
|
||||
$entity->onGround = true;
|
||||
}
|
||||
|
@ -40,6 +40,6 @@ class Podzol extends Solid{
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2.5;
|
||||
return 0.5;
|
||||
}
|
||||
}
|
||||
|
@ -40,9 +40,13 @@ class Potato extends Crops{
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get(Item::POTATO, 0, $this->getDamage() >= 0x07 ? mt_rand(1, 4) : 1)
|
||||
$result = [
|
||||
ItemFactory::get(Item::POTATO, 0, $this->getDamage() >= 0x07 ? mt_rand(1, 5) : 1)
|
||||
];
|
||||
if($this->getDamage() >= 7 && mt_rand(0, 49) === 0){
|
||||
$result[] = ItemFactory::get(Item::POISONOUS_POTATO);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getPickedItem() : Item{
|
||||
|
@ -87,7 +87,12 @@ class Sugarcane extends Flowable{
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
if($b->getId() === self::AIR){
|
||||
$this->getLevelNonNull()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK));
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
break;
|
||||
}
|
||||
$this->getLevelNonNull()->setBlock($b, $ev->getNewState(), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,9 @@ use pocketmine\permission\BanEntry;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sort;
|
||||
use function strtolower;
|
||||
use const SORT_STRING;
|
||||
|
||||
class BanListCommand extends VanillaCommand{
|
||||
|
||||
@ -62,10 +64,11 @@ class BanListCommand extends VanillaCommand{
|
||||
$args[0] = "players";
|
||||
}
|
||||
|
||||
$list = $list->getEntries();
|
||||
$message = implode(", ", array_map(function(BanEntry $entry) : string{
|
||||
$list = array_map(function(BanEntry $entry) : string{
|
||||
return $entry->getName();
|
||||
}, $list));
|
||||
}, $list->getEntries());
|
||||
sort($list, SORT_STRING);
|
||||
$message = implode(", ", $list);
|
||||
|
||||
if($args[0] === "ips"){
|
||||
$sender->sendMessage(new TranslationContainer("commands.banlist.ips", [count($list)]));
|
||||
|
@ -30,6 +30,8 @@ use function array_filter;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sort;
|
||||
use const SORT_STRING;
|
||||
|
||||
class ListCommand extends VanillaCommand{
|
||||
|
||||
@ -52,6 +54,7 @@ class ListCommand extends VanillaCommand{
|
||||
}, array_filter($sender->getServer()->getOnlinePlayers(), function(Player $player) use ($sender) : bool{
|
||||
return $player->isOnline() and (!($sender instanceof Player) or $sender->canSee($player));
|
||||
}));
|
||||
sort($playerNames, SORT_STRING);
|
||||
|
||||
$sender->sendMessage(new TranslationContainer("commands.players.list", [count($playerNames), $sender->getServer()->getMaxPlayers()]));
|
||||
$sender->sendMessage(implode(", ", $playerNames));
|
||||
|
@ -30,6 +30,8 @@ use pocketmine\utils\TextFormat;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sort;
|
||||
use const SORT_STRING;
|
||||
|
||||
class PluginsCommand extends VanillaCommand{
|
||||
|
||||
@ -51,6 +53,7 @@ class PluginsCommand extends VanillaCommand{
|
||||
$list = array_map(function(Plugin $plugin) : string{
|
||||
return ($plugin->isEnabled() ? TextFormat::GREEN : TextFormat::RED) . $plugin->getDescription()->getFullName();
|
||||
}, $sender->getServer()->getPluginManager()->getPlugins());
|
||||
sort($list, SORT_STRING);
|
||||
|
||||
$sender->sendMessage(new TranslationContainer("pocketmine.command.plugins.success", [count($list), implode(TextFormat::WHITE . ", ", $list)]));
|
||||
return true;
|
||||
|
@ -31,7 +31,9 @@ use pocketmine\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sort;
|
||||
use function strtolower;
|
||||
use const SORT_STRING;
|
||||
|
||||
class WhitelistCommand extends VanillaCommand{
|
||||
|
||||
@ -71,7 +73,8 @@ class WhitelistCommand extends VanillaCommand{
|
||||
return true;
|
||||
case "list":
|
||||
$entries = $sender->getServer()->getWhitelisted()->getAll(true);
|
||||
$result = implode($entries, ", ");
|
||||
sort($entries, SORT_STRING);
|
||||
$result = implode(", ", $entries);
|
||||
$count = count($entries);
|
||||
|
||||
$sender->sendMessage(new TranslationContainer("commands.whitelist.list", [$count, $count]));
|
||||
|
@ -45,6 +45,7 @@ class Attribute{
|
||||
public const FALL_DAMAGE = 13;
|
||||
public const HORSE_JUMP_STRENGTH = 14;
|
||||
public const ZOMBIE_SPAWN_REINFORCEMENTS = 15;
|
||||
public const LAVA_MOVEMENT = 16;
|
||||
|
||||
/** @var int */
|
||||
private $id;
|
||||
@ -84,6 +85,7 @@ class Attribute{
|
||||
self::addAttribute(self::FALL_DAMAGE, "minecraft:fall_damage", 0.0, 340282346638528859811704183484516925440.0, 1.0);
|
||||
self::addAttribute(self::HORSE_JUMP_STRENGTH, "minecraft:horse.jump_strength", 0.0, 2.0, 0.7);
|
||||
self::addAttribute(self::ZOMBIE_SPAWN_REINFORCEMENTS, "minecraft:zombie.spawn_reinforcements", 0.0, 1.0, 0.0);
|
||||
self::addAttribute(self::LAVA_MOVEMENT, "minecraft:lava_movement", 0.0, 340282346638528859811704183484516925440.0, 0.02);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,6 +94,7 @@ use const M_PI_2;
|
||||
abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
|
||||
public const MOTION_THRESHOLD = 0.00001;
|
||||
protected const STEP_CLIP_MULTIPLIER = 0.4;
|
||||
|
||||
public const NETWORK_ID = -1;
|
||||
|
||||
@ -311,12 +312,15 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
public const DATA_FLAG_ROARING = 83;
|
||||
public const DATA_FLAG_DELAYED_ATTACKING = 84;
|
||||
public const DATA_FLAG_AVOIDING_MOBS = 85;
|
||||
public const DATA_FLAG_FACING_TARGET_TO_RANGE_ATTACK = 86;
|
||||
public const DATA_FLAG_HIDDEN_WHEN_INVISIBLE = 87; //??????????????????
|
||||
public const DATA_FLAG_IS_IN_UI = 88;
|
||||
public const DATA_FLAG_STALKING = 89;
|
||||
public const DATA_FLAG_EMOTING = 90;
|
||||
public const DATA_FLAG_CELEBRATING = 91;
|
||||
public const DATA_FLAG_AVOIDING_BLOCK = 86;
|
||||
public const DATA_FLAG_FACING_TARGET_TO_RANGE_ATTACK = 87;
|
||||
public const DATA_FLAG_HIDDEN_WHEN_INVISIBLE = 88; //??????????????????
|
||||
public const DATA_FLAG_IS_IN_UI = 89;
|
||||
public const DATA_FLAG_STALKING = 90;
|
||||
public const DATA_FLAG_EMOTING = 91;
|
||||
public const DATA_FLAG_CELEBRATING = 92;
|
||||
public const DATA_FLAG_ADMIRING = 93;
|
||||
public const DATA_FLAG_CELEBRATING_SPECIAL = 94;
|
||||
|
||||
public const DATA_PLAYER_FLAG_SLEEP = 1;
|
||||
public const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK
|
||||
@ -704,10 +708,10 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
|
||||
$this->boundingBox->setBounds(
|
||||
$this->x - $halfWidth,
|
||||
$this->y,
|
||||
$this->y + $this->ySize,
|
||||
$this->z - $halfWidth,
|
||||
$this->x + $halfWidth,
|
||||
$this->y + $this->height,
|
||||
$this->y + $this->height + $this->ySize,
|
||||
$this->z + $halfWidth
|
||||
);
|
||||
}
|
||||
@ -865,7 +869,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
*/
|
||||
public function getSaveId() : string{
|
||||
if(!isset(self::$saveNames[static::class])){
|
||||
throw new \InvalidStateException("Entity is not registered");
|
||||
throw new \InvalidStateException("Entity " . static::class . " is not registered");
|
||||
}
|
||||
reset(self::$saveNames[static::class]);
|
||||
return current(self::$saveNames[static::class]);
|
||||
@ -1535,7 +1539,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
if($this->keepMovement){
|
||||
$this->boundingBox->offset($dx, $dy, $dz);
|
||||
}else{
|
||||
$this->ySize *= 0.4;
|
||||
$this->ySize *= self::STEP_CLIP_MULTIPLIER;
|
||||
|
||||
/*
|
||||
if($this->isColliding){ //With cobweb?
|
||||
@ -1602,7 +1606,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
|
||||
$this->boundingBox->offset(0, 0, $dz);
|
||||
|
||||
if($this->stepHeight > 0 and $fallingFlag and $this->ySize < 0.05 and ($movX != $dx or $movZ != $dz)){
|
||||
if($this->stepHeight > 0 and $fallingFlag and ($movX != $dx or $movZ != $dz)){
|
||||
$cx = $dx;
|
||||
$cy = $dy;
|
||||
$cz = $dz;
|
||||
@ -1634,13 +1638,20 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
||||
|
||||
$this->boundingBox->offset(0, 0, $dz);
|
||||
|
||||
$reverseDY = -$dy;
|
||||
foreach($list as $bb){
|
||||
$reverseDY = $bb->calculateYOffset($this->boundingBox, $reverseDY);
|
||||
}
|
||||
$dy += $reverseDY;
|
||||
$this->boundingBox->offset(0, $reverseDY, 0);
|
||||
|
||||
if(($cx ** 2 + $cz ** 2) >= ($dx ** 2 + $dz ** 2)){
|
||||
$dx = $cx;
|
||||
$dy = $cy;
|
||||
$dz = $cz;
|
||||
$this->boundingBox->setBB($axisalignedbb1);
|
||||
}else{
|
||||
$this->ySize += 0.5; //FIXME: this should be the height of the block it walked up, not fixed 0.5
|
||||
$this->ySize += $dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
use pocketmine\network\mcpe\protocol\ActorEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobEffectPacket;
|
||||
@ -97,17 +98,15 @@ abstract class Living extends Entity implements Damageable{
|
||||
//TODO: load/save armor inventory contents
|
||||
$this->armorInventory->setEventProcessor(new ArmorInventoryEventProcessor($this));
|
||||
|
||||
$health = $this->getMaxHealth();
|
||||
|
||||
if($this->namedtag->hasTag("HealF", FloatTag::class)){
|
||||
$health = $this->namedtag->getFloat("HealF");
|
||||
$this->namedtag->removeTag("HealF");
|
||||
}elseif($this->namedtag->hasTag("Health")){
|
||||
$healthTag = $this->namedtag->getTag("Health");
|
||||
$health = (float) $healthTag->getValue(); //Older versions of PocketMine-MP incorrectly saved this as a short instead of a float
|
||||
if(!($healthTag instanceof FloatTag)){
|
||||
$this->namedtag->removeTag("Health");
|
||||
}
|
||||
}elseif($this->namedtag->hasTag("Health", ShortTag::class)){
|
||||
//Older versions of PocketMine-MP incorrectly saved this as a short instead of a float
|
||||
$health = $this->namedtag->getShort("Health");
|
||||
$this->namedtag->removeTag("Health");
|
||||
}else{
|
||||
$health = $this->namedtag->getFloat("Health", $this->getMaxHealth());
|
||||
}
|
||||
|
||||
$this->setHealth($health);
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\entity\utils;
|
||||
|
||||
use pocketmine\math\Math;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use function max;
|
||||
|
||||
abstract class ExperienceUtils{
|
||||
@ -59,6 +60,9 @@ abstract class ExperienceUtils{
|
||||
* This returns a floating-point number, the decimal part being the progress through the resulting level.
|
||||
*/
|
||||
public static function getLevelFromXp(int $xp) : float{
|
||||
if($xp < 0){
|
||||
throw new \InvalidArgumentException("XP must be at least 0");
|
||||
}
|
||||
if($xp <= self::getXpToReachLevel(16)){
|
||||
$a = 1;
|
||||
$b = 6;
|
||||
@ -74,6 +78,9 @@ abstract class ExperienceUtils{
|
||||
}
|
||||
|
||||
$x = Math::solveQuadratic($a, $b, $c - $xp);
|
||||
if(count($x) === 0){
|
||||
throw new AssumptionFailedError("Expected at least 1 solution");
|
||||
}
|
||||
|
||||
return max($x); //we're only interested in the positive solution
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\event\block;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
@ -79,6 +80,7 @@ class SignChangeEvent extends BlockEvent implements Cancellable{
|
||||
if(count($lines) !== 4){
|
||||
throw new \InvalidArgumentException("Array size must be 4!");
|
||||
}
|
||||
Utils::validateArrayValueType($lines, function(string $_) : void{});
|
||||
$this->lines = $lines;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
/**
|
||||
* @phpstan-extends EntityEvent<Living>
|
||||
@ -62,6 +63,7 @@ class EntityDeathEvent extends EntityEvent{
|
||||
* @param Item[] $drops
|
||||
*/
|
||||
public function setDrops(array $drops) : void{
|
||||
Utils::validateArrayValueType($drops, function(Item $_) : void{});
|
||||
$this->drops = $drops;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\block\Block;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
/**
|
||||
* Called when a entity explodes
|
||||
@ -67,6 +68,7 @@ class EntityExplodeEvent extends EntityEvent implements Cancellable{
|
||||
* @param Block[] $blocks
|
||||
*/
|
||||
public function setBlockList(array $blocks) : void{
|
||||
Utils::validateArrayValueType($blocks, function(Block $_) : void{});
|
||||
$this->blocks = $blocks;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\event\Cancellable;
|
||||
use pocketmine\permission\PermissionManager;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\Utils;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
@ -97,6 +98,7 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{
|
||||
* @param CommandSender[] $recipients
|
||||
*/
|
||||
public function setRecipients(array $recipients) : void{
|
||||
Utils::validateArrayValueType($recipients, function(CommandSender $_) : void{});
|
||||
$this->recipients = $recipients;
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,9 @@ class PlayerRespawnEvent extends PlayerEvent{
|
||||
}
|
||||
|
||||
public function setRespawnPosition(Position $position) : void{
|
||||
if(!$position->isValid()){
|
||||
throw new \InvalidArgumentException("Spawn position must reference a valid and loaded World");
|
||||
}
|
||||
$this->position = $position;
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\Utils;
|
||||
use function chr;
|
||||
use function count;
|
||||
use function str_replace;
|
||||
@ -145,6 +146,7 @@ class QueryRegenerateEvent extends ServerEvent{
|
||||
* @param Plugin[] $plugins
|
||||
*/
|
||||
public function setPlugins(array $plugins) : void{
|
||||
Utils::validateArrayValueType($plugins, function(Plugin $_) : void{});
|
||||
$this->plugins = $plugins;
|
||||
$this->destroyCache();
|
||||
}
|
||||
@ -160,6 +162,7 @@ class QueryRegenerateEvent extends ServerEvent{
|
||||
* @param Player[] $players
|
||||
*/
|
||||
public function setPlayerList(array $players) : void{
|
||||
Utils::validateArrayValueType($players, function(Player $_) : void{});
|
||||
$this->players = $players;
|
||||
$this->destroyCache();
|
||||
}
|
||||
|
@ -28,7 +28,9 @@ use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\Player;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
|
||||
class ArmorInventory extends BaseInventory{
|
||||
@ -109,7 +111,7 @@ class ArmorInventory extends BaseInventory{
|
||||
$pk2 = new InventorySlotPacket();
|
||||
$pk2->windowId = $player->getWindowId($this);
|
||||
$pk2->inventorySlot = $index;
|
||||
$pk2->item = $this->getItem($index);
|
||||
$pk2->item = ItemStackWrapper::legacy($this->getItem($index));
|
||||
$player->dataPacket($pk2);
|
||||
}else{
|
||||
$player->dataPacket($pk);
|
||||
@ -134,7 +136,7 @@ class ArmorInventory extends BaseInventory{
|
||||
if($player === $this->getHolder()){
|
||||
$pk2 = new InventoryContentPacket();
|
||||
$pk2->windowId = $player->getWindowId($this);
|
||||
$pk2->items = $this->getContents(true);
|
||||
$pk2->items = array_map([ItemStackWrapper::class, 'legacy'], $this->getContents(true));
|
||||
$player->dataPacket($pk2);
|
||||
}else{
|
||||
$player->dataPacket($pk);
|
||||
|
@ -31,7 +31,9 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\Player;
|
||||
use function array_map;
|
||||
use function array_slice;
|
||||
use function count;
|
||||
use function max;
|
||||
@ -433,7 +435,7 @@ abstract class BaseInventory implements Inventory{
|
||||
}
|
||||
|
||||
$pk = new InventoryContentPacket();
|
||||
$pk->items = $this->getContents(true);
|
||||
$pk->items = array_map([ItemStackWrapper::class, 'legacy'], $this->getContents(true));
|
||||
|
||||
foreach($target as $player){
|
||||
if(($id = $player->getWindowId($this)) === ContainerIds::NONE){
|
||||
@ -455,7 +457,7 @@ abstract class BaseInventory implements Inventory{
|
||||
|
||||
$pk = new InventorySlotPacket();
|
||||
$pk->inventorySlot = $index;
|
||||
$pk->item = $this->getItem($index);
|
||||
$pk->item = ItemStackWrapper::legacy($this->getItem($index));
|
||||
|
||||
foreach($target as $player){
|
||||
if(($id = $player->getWindowId($this)) === ContainerIds::NONE){
|
||||
|
@ -28,8 +28,10 @@ use pocketmine\network\mcpe\protocol\BatchPacket;
|
||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use function array_map;
|
||||
use function file_get_contents;
|
||||
use function is_array;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function usort;
|
||||
@ -52,41 +54,39 @@ class CraftingManager{
|
||||
|
||||
public function init() : void{
|
||||
$recipes = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla" . DIRECTORY_SEPARATOR . "recipes.json"), true);
|
||||
if(!is_array($recipes)){
|
||||
throw new AssumptionFailedError("recipes.json root should contain a map of recipe types");
|
||||
}
|
||||
|
||||
$itemDeserializerFunc = \Closure::fromCallable([Item::class, 'jsonDeserialize']);
|
||||
foreach($recipes as $recipe){
|
||||
switch($recipe["type"]){
|
||||
case "shapeless":
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
break;
|
||||
}
|
||||
$this->registerShapelessRecipe(new ShapelessRecipe(
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
));
|
||||
break;
|
||||
case "shaped":
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
break;
|
||||
}
|
||||
$this->registerShapedRecipe(new ShapedRecipe(
|
||||
$recipe["shape"],
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
));
|
||||
break;
|
||||
case "smelting":
|
||||
if($recipe["block"] !== "furnace"){ //TODO: filter others out for now to avoid breaking economics
|
||||
break;
|
||||
}
|
||||
$this->registerFurnaceRecipe(new FurnaceRecipe(
|
||||
Item::jsonDeserialize($recipe["output"]),
|
||||
Item::jsonDeserialize($recipe["input"]))
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
foreach($recipes["shapeless"] as $recipe){
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
continue;
|
||||
}
|
||||
$this->registerShapelessRecipe(new ShapelessRecipe(
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
));
|
||||
}
|
||||
foreach($recipes["shaped"] as $recipe){
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
continue;
|
||||
}
|
||||
$this->registerShapedRecipe(new ShapedRecipe(
|
||||
$recipe["shape"],
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
));
|
||||
}
|
||||
foreach($recipes["smelting"] as $recipe){
|
||||
if($recipe["block"] !== "furnace"){ //TODO: filter others out for now to avoid breaking economics
|
||||
continue;
|
||||
}
|
||||
$this->registerFurnaceRecipe(new FurnaceRecipe(
|
||||
Item::jsonDeserialize($recipe["output"]),
|
||||
Item::jsonDeserialize($recipe["input"]))
|
||||
);
|
||||
}
|
||||
|
||||
$this->buildCraftingDataCache();
|
||||
|
@ -26,10 +26,12 @@ namespace pocketmine\inventory;
|
||||
use pocketmine\entity\Human;
|
||||
use pocketmine\event\player\PlayerItemHeldEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\CreativeContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
|
||||
use pocketmine\Player;
|
||||
use function array_map;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
|
||||
@ -196,16 +198,11 @@ class PlayerInventory extends BaseInventory{
|
||||
if(!($holder instanceof Player)){
|
||||
throw new \LogicException("Cannot send creative inventory contents to non-player inventory holder");
|
||||
}
|
||||
$pk = new InventoryContentPacket();
|
||||
$pk->windowId = ContainerIds::CREATIVE;
|
||||
|
||||
if(!$holder->isSpectator()){ //fill it for all gamemodes except spectator
|
||||
foreach(Item::getCreativeItems() as $i => $item){
|
||||
$pk->items[$i] = clone $item;
|
||||
}
|
||||
}
|
||||
|
||||
$holder->dataPacket($pk);
|
||||
$nextEntryId = 1;
|
||||
$holder->sendDataPacket(CreativeContentPacket::create(array_map(function(Item $item) use (&$nextEntryId) : CreativeContentEntry{
|
||||
return new CreativeContentEntry($nextEntryId++, clone $item);
|
||||
}, $holder->isSpectator() ? [] : Item::getCreativeItems()))); //fill it for all gamemodes except spectator
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,7 +27,7 @@ use pocketmine\event\inventory\CraftItemEvent;
|
||||
use pocketmine\inventory\CraftingRecipe;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
|
||||
use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\Player;
|
||||
use function array_pop;
|
||||
use function count;
|
||||
use function intdiv;
|
||||
@ -165,7 +165,7 @@ class CraftingTransaction extends InventoryTransaction{
|
||||
* transaction goes wrong.
|
||||
*/
|
||||
$pk = new ContainerClosePacket();
|
||||
$pk->windowId = ContainerIds::NONE;
|
||||
$pk->windowId = Player::HARDCODED_CRAFTING_GRID_WINDOW_ID;
|
||||
$this->source->dataPacket($pk);
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,8 @@ class InventoryTransaction{
|
||||
* @throws TransactionValidationException
|
||||
*/
|
||||
protected function matchItems(array &$needItems, array &$haveItems) : void{
|
||||
$needItems = [];
|
||||
$haveItems = [];
|
||||
foreach($this->actions as $key => $action){
|
||||
if(!$action->getTargetItem()->isNull()){
|
||||
$needItems[] = $action->getTargetItem();
|
||||
|
@ -42,6 +42,7 @@ use pocketmine\nbt\tag\NamedTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Binary;
|
||||
use function array_map;
|
||||
use function base64_decode;
|
||||
@ -475,7 +476,12 @@ class Item implements ItemIds, \JsonSerializable{
|
||||
public function getLore() : array{
|
||||
$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
|
||||
if($display instanceof CompoundTag and ($lore = $display->getListTag(self::TAG_DISPLAY_LORE)) !== null){
|
||||
return $lore->getAllValues();
|
||||
return array_map(function(NamedTag $line) : string{
|
||||
if(!($line instanceof StringTag)){
|
||||
throw new AssumptionFailedError("Nobody bothered to handle this error case and we can't fix it until PM4, oops ... #blameshoghi");
|
||||
}
|
||||
return $line->getValue();
|
||||
}, $lore->getValue());
|
||||
}
|
||||
|
||||
return [];
|
||||
|
@ -69,6 +69,7 @@ class Enchantment{
|
||||
public const MULTISHOT = 33;
|
||||
public const PIERCING = 34;
|
||||
public const QUICK_CHARGE = 35;
|
||||
public const SOUL_SPEED = 36;
|
||||
|
||||
public const RARITY_COMMON = 10;
|
||||
public const RARITY_UNCOMMON = 5;
|
||||
|
@ -232,7 +232,9 @@ class Explosion{
|
||||
|
||||
$t->close();
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->affectedBlocks as $block){
|
||||
$pos = new Vector3($block->x, $block->y, $block->z);
|
||||
|
||||
for($side = 0; $side <= 5; $side++){
|
||||
|
@ -72,6 +72,7 @@ use pocketmine\metadata\Metadatable;
|
||||
use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||
use pocketmine\network\mcpe\protocol\AddActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\BatchPacket;
|
||||
use pocketmine\network\mcpe\protocol\DataPacket;
|
||||
@ -79,7 +80,6 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
|
||||
use pocketmine\network\mcpe\protocol\SetTimePacket;
|
||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\block\BlockFactory;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Spawnable;
|
||||
@ -691,13 +692,14 @@ class Chunk{
|
||||
|
||||
$level->timings->syncChunkLoadEntitiesTimer->startTiming();
|
||||
foreach($this->NBTentities as $nbt){
|
||||
if(!$nbt->hasTag("id")){ //allow mixed types (because of leveldb)
|
||||
$idTag = $nbt->getTag("id");
|
||||
if(!($idTag instanceof IntTag) && !($idTag instanceof StringTag)){ //allow mixed types (because of leveldb)
|
||||
$changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
try{
|
||||
$entity = Entity::createEntity($nbt->getTag("id")->getValue(), $level, $nbt);
|
||||
$entity = Entity::createEntity($idTag->getValue(), $level, $nbt);
|
||||
if(!($entity instanceof Entity)){
|
||||
$changed = true;
|
||||
continue;
|
||||
|
@ -131,7 +131,11 @@ class LevelDB extends BaseLevelProvider{
|
||||
throw new LevelException("Truncated level.dat");
|
||||
}
|
||||
$nbt = new LittleEndianNBTStream();
|
||||
$levelData = $nbt->read(substr($rawLevelData, 8));
|
||||
try{
|
||||
$levelData = $nbt->read(substr($rawLevelData, 8));
|
||||
}catch(\UnexpectedValueException $e){
|
||||
throw new LevelException("Invalid level.dat (" . $e->getMessage() . ")", 0, $e);
|
||||
}
|
||||
if($levelData instanceof CompoundTag){
|
||||
$this->levelData = $levelData;
|
||||
}else{
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\level\generator;
|
||||
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\biome\Biome;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\SimpleChunkManager;
|
||||
@ -59,6 +60,7 @@ class GeneratorRegisterTask extends AsyncTask{
|
||||
|
||||
public function onRun(){
|
||||
BlockFactory::init();
|
||||
ItemFactory::init();
|
||||
Biome::init();
|
||||
$manager = new SimpleChunkManager($this->seed, $this->worldHeight);
|
||||
$this->saveToThreadStore("generation.level{$this->levelId}.manager", $manager);
|
||||
|
@ -471,7 +471,7 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
/**
|
||||
* Reads and returns an EntityUniqueID
|
||||
*/
|
||||
public function getEntityUniqueId() : int{
|
||||
final public function getEntityUniqueId() : int{
|
||||
return $this->getVarLong();
|
||||
}
|
||||
|
||||
@ -485,7 +485,7 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
/**
|
||||
* Reads and returns an EntityRuntimeID
|
||||
*/
|
||||
public function getEntityRuntimeId() : int{
|
||||
final public function getEntityRuntimeId() : int{
|
||||
return $this->getUnsignedVarLong();
|
||||
}
|
||||
|
||||
@ -648,7 +648,8 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
$toEntityUniqueId = $this->getEntityUniqueId();
|
||||
$type = $this->getByte();
|
||||
$immediate = $this->getBool();
|
||||
return new EntityLink($fromEntityUniqueId, $toEntityUniqueId, $type, $immediate);
|
||||
$causedByRider = $this->getBool();
|
||||
return new EntityLink($fromEntityUniqueId, $toEntityUniqueId, $type, $immediate, $causedByRider);
|
||||
}
|
||||
|
||||
protected function putEntityLink(EntityLink $link) : void{
|
||||
@ -656,6 +657,7 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
$this->putEntityUniqueId($link->toEntityUniqueId);
|
||||
$this->putByte($link->type);
|
||||
$this->putBool($link->immediate);
|
||||
$this->putBool($link->causedByRider);
|
||||
}
|
||||
|
||||
protected function getCommandOriginData() : CommandOriginData{
|
||||
@ -747,4 +749,12 @@ class NetworkBinaryStream extends BinaryStream{
|
||||
$this->putStructureSettings($structureEditorData->structureSettings);
|
||||
$this->putVarInt($structureEditorData->structureRedstoneSaveMove);
|
||||
}
|
||||
|
||||
public function readGenericTypeNetworkId() : int{
|
||||
return $this->getVarInt();
|
||||
}
|
||||
|
||||
public function writeGenericTypeNetworkId(int $id) : void{
|
||||
$this->putVarInt($id);
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ use pocketmine\network\mcpe\protocol\ClientCacheBlobStatusPacket;
|
||||
use pocketmine\network\mcpe\protocol\ClientCacheMissResponsePacket;
|
||||
use pocketmine\network\mcpe\protocol\ClientCacheStatusPacket;
|
||||
use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket;
|
||||
use pocketmine\network\mcpe\protocol\CodeBuilderPacket;
|
||||
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
|
||||
use pocketmine\network\mcpe\protocol\CommandOutputPacket;
|
||||
use pocketmine\network\mcpe\protocol\CommandRequestPacket;
|
||||
@ -61,9 +62,12 @@ use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\CreativeContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\DataPacket;
|
||||
use pocketmine\network\mcpe\protocol\DebugInfoPacket;
|
||||
use pocketmine\network\mcpe\protocol\DisconnectPacket;
|
||||
use pocketmine\network\mcpe\protocol\EducationSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\EmoteListPacket;
|
||||
use pocketmine\network\mcpe\protocol\EmotePacket;
|
||||
use pocketmine\network\mcpe\protocol\EventPacket;
|
||||
use pocketmine\network\mcpe\protocol\GameRulesChangedPacket;
|
||||
@ -74,6 +78,8 @@ use pocketmine\network\mcpe\protocol\InventoryContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket;
|
||||
use pocketmine\network\mcpe\protocol\ItemStackRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\ItemStackResponsePacket;
|
||||
use pocketmine\network\mcpe\protocol\LabTablePacket;
|
||||
use pocketmine\network\mcpe\protocol\LecternUpdatePacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
|
||||
@ -99,15 +105,20 @@ use pocketmine\network\mcpe\protocol\NetworkSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
|
||||
use pocketmine\network\mcpe\protocol\NpcRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\OnScreenTextureAnimationPacket;
|
||||
use pocketmine\network\mcpe\protocol\PacketViolationWarningPacket;
|
||||
use pocketmine\network\mcpe\protocol\PhotoTransferPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerActionPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerArmorDamagePacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerEnchantOptionsPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerHotbarPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlaySoundPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
|
||||
use pocketmine\network\mcpe\protocol\PositionTrackingDBClientRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\PositionTrackingDBServerBroadcastPacket;
|
||||
use pocketmine\network\mcpe\protocol\PurchaseReceiptPacket;
|
||||
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\RemoveEntityPacket;
|
||||
@ -163,9 +174,9 @@ use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateBlockPropertiesPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateBlockSyncedPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateEquipPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdatePlayerGameTypePacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateSoftEnumPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateTradePacket;
|
||||
use pocketmine\network\mcpe\protocol\VideoStreamConnectPacket;
|
||||
|
||||
abstract class NetworkSession{
|
||||
|
||||
@ -666,10 +677,6 @@ abstract class NetworkSession{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleVideoStreamConnect(VideoStreamConnectPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleAddEntity(AddEntityPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
@ -741,4 +748,52 @@ abstract class NetworkSession{
|
||||
public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleCreativeContent(CreativeContentPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handlePlayerEnchantOptions(PlayerEnchantOptionsPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleItemStackRequest(ItemStackRequestPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleItemStackResponse(ItemStackResponsePacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handlePlayerArmorDamage(PlayerArmorDamagePacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleCodeBuilder(CodeBuilderPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleUpdatePlayerGameType(UpdatePlayerGameTypePacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleEmoteList(EmoteListPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handlePositionTrackingDBServerBroadcast(PositionTrackingDBServerBroadcastPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handlePositionTrackingDBClientRequest(PositionTrackingDBClientRequestPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleDebugInfo(DebugInfoPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handlePacketViolationWarning(PacketViolationWarningPacket $packet) : bool{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
|
||||
* Sometimes this gets changed when the MCPE-layer protocol gets broken to the point where old and new can't
|
||||
* communicate. It's important that we check this to avoid catastrophes.
|
||||
*/
|
||||
private const MCPE_RAKNET_PROTOCOL_VERSION = 9;
|
||||
private const MCPE_RAKNET_PROTOCOL_VERSION = 10;
|
||||
|
||||
/** @var Server */
|
||||
private $server;
|
||||
|
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\convert;
|
||||
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
|
||||
final class R12ToCurrentBlockMapEntry{
|
||||
|
||||
/** @var string */
|
||||
private $id;
|
||||
/** @var int */
|
||||
private $meta;
|
||||
/** @var CompoundTag */
|
||||
private $blockState;
|
||||
|
||||
public function __construct(string $id, int $meta, CompoundTag $blockState){
|
||||
$this->id = $id;
|
||||
$this->meta = $meta;
|
||||
$this->blockState = $blockState;
|
||||
}
|
||||
|
||||
public function getId() : string{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getMeta() : int{
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
public function getBlockState() : CompoundTag{
|
||||
return $this->blockState;
|
||||
}
|
||||
|
||||
public function __toString(){
|
||||
return "id=$this->id, meta=$this->meta, nbt=$this->blockState";
|
||||
}
|
||||
}
|
@ -21,13 +21,14 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types;
|
||||
namespace pocketmine\network\mcpe\convert;
|
||||
|
||||
use pocketmine\block\BlockIds;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use function file_get_contents;
|
||||
use function getmypid;
|
||||
use function json_decode;
|
||||
@ -66,9 +67,22 @@ final class RuntimeBlockMapping{
|
||||
|
||||
private static function setupLegacyMappings() : void{
|
||||
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true);
|
||||
$legacyStateMap = (new NetworkLittleEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.nbt"));
|
||||
if(!($legacyStateMap instanceof ListTag) or $legacyStateMap->getTagType() !== NBT::TAG_Compound){
|
||||
throw new \RuntimeException("Invalid legacy states mapping table, expected TAG_List<TAG_Compound> root");
|
||||
|
||||
/** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */
|
||||
$legacyStateMap = [];
|
||||
$legacyStateMapReader = new NetworkBinaryStream(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.bin"));
|
||||
$nbtReader = new NetworkLittleEndianNBTStream();
|
||||
while(!$legacyStateMapReader->feof()){
|
||||
$id = $legacyStateMapReader->getString();
|
||||
$meta = $legacyStateMapReader->getLShort();
|
||||
|
||||
$offset = $legacyStateMapReader->getOffset();
|
||||
$state = $nbtReader->read($legacyStateMapReader->getBuffer(), false, $offset);
|
||||
$legacyStateMapReader->setOffset($offset);
|
||||
if(!($state instanceof CompoundTag)){
|
||||
throw new \RuntimeException("Blockstate should be a TAG_Compound");
|
||||
}
|
||||
$legacyStateMap[] = new R12ToCurrentBlockMapEntry($id, $meta, $state);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,16 +92,17 @@ final class RuntimeBlockMapping{
|
||||
foreach(self::$bedrockKnownStates as $k => $state){
|
||||
$idToStatesMap[$state->getCompoundTag("block")->getString("name")][] = $k;
|
||||
}
|
||||
/** @var CompoundTag $pair */
|
||||
foreach($legacyStateMap as $pair){
|
||||
$oldState = $pair->getCompoundTag("old");
|
||||
$id = $legacyIdMap[$oldState->getString("name")];
|
||||
$data = $oldState->getShort("val");
|
||||
$id = $legacyIdMap[$pair->getId()] ?? null;
|
||||
if($id === null){
|
||||
throw new \RuntimeException("No legacy ID matches " . $pair->getId());
|
||||
}
|
||||
$data = $pair->getMeta();
|
||||
if($data > 15){
|
||||
//we can't handle metadata with more than 4 bits
|
||||
continue;
|
||||
}
|
||||
$mappedState = $pair->getCompoundTag("new");
|
||||
$mappedState = $pair->getBlockState();
|
||||
|
||||
//TODO HACK: idiotic NBT compare behaviour on 3.x compares keys which are stored by values
|
||||
$mappedState->setName("block");
|
@ -87,6 +87,7 @@ class ActorEventPacket extends DataPacket{
|
||||
public const TREASURE_HUNT = 72;
|
||||
public const AGENT_SUMMON = 73;
|
||||
public const CHARGED_CROSSBOW = 74;
|
||||
public const FALL = 75;
|
||||
|
||||
//TODO: add more events
|
||||
|
||||
|
@ -32,6 +32,7 @@ use function get_class;
|
||||
use function strlen;
|
||||
use function zlib_decode;
|
||||
use function zlib_encode;
|
||||
use const ZLIB_ENCODING_RAW;
|
||||
#ifndef COMPILE
|
||||
use pocketmine\utils\Binary;
|
||||
#endif
|
||||
@ -71,7 +72,7 @@ class BatchPacket extends DataPacket{
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->put(zlib_encode($this->payload, ZLIB_ENCODING_DEFLATE, $this->compressionLevel));
|
||||
$this->put(zlib_encode($this->payload, ZLIB_ENCODING_RAW, $this->compressionLevel));
|
||||
}
|
||||
|
||||
/**
|
||||
|
66
src/pocketmine/network/mcpe/protocol/CodeBuilderPacket.php
Normal file
66
src/pocketmine/network/mcpe/protocol/CodeBuilderPacket.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class CodeBuilderPacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::CODE_BUILDER_PACKET;
|
||||
|
||||
/** @var string */
|
||||
private $url;
|
||||
/** @var bool */
|
||||
private $openCodeBuilder;
|
||||
|
||||
public static function create(string $url, bool $openCodeBuilder) : self{
|
||||
$result = new self;
|
||||
$result->url = $url;
|
||||
$result->openCodeBuilder = $openCodeBuilder;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUrl() : string{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
public function openCodeBuilder() : bool{
|
||||
return $this->openCodeBuilder;
|
||||
}
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->url = $this->getString();
|
||||
$this->openCodeBuilder = $this->getBool();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putString($this->url);
|
||||
$this->putBool($this->openCodeBuilder);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleCodeBuilder($this);
|
||||
}
|
||||
}
|
@ -97,6 +97,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
$entry["uuid"] = $this->getUUID()->toString();
|
||||
$entry["block"] = $this->getString();
|
||||
$entry["priority"] = $this->getVarInt();
|
||||
$entry["net_id"] = $this->readGenericTypeNetworkId();
|
||||
|
||||
break;
|
||||
case self::ENTRY_SHAPED:
|
||||
@ -118,6 +119,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
$entry["uuid"] = $this->getUUID()->toString();
|
||||
$entry["block"] = $this->getString();
|
||||
$entry["priority"] = $this->getVarInt();
|
||||
$entry["net_id"] = $this->readGenericTypeNetworkId();
|
||||
|
||||
break;
|
||||
case self::ENTRY_FURNACE:
|
||||
@ -140,6 +142,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
break;
|
||||
case self::ENTRY_MULTI:
|
||||
$entry["uuid"] = $this->getUUID()->toString();
|
||||
$entry["net_id"] = $this->readGenericTypeNetworkId();
|
||||
break;
|
||||
default:
|
||||
throw new \UnexpectedValueException("Unhandled recipe type $recipeType!"); //do not continue attempting to decode
|
||||
@ -148,9 +151,12 @@ class CraftingDataPacket extends DataPacket{
|
||||
}
|
||||
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
|
||||
$input = $this->getVarInt();
|
||||
$inputMeta = $this->getVarInt();
|
||||
$ingredient = $this->getVarInt();
|
||||
$ingredientMeta = $this->getVarInt();
|
||||
$output = $this->getVarInt();
|
||||
$this->potionTypeRecipes[] = new PotionTypeRecipe($input, $ingredient, $output);
|
||||
$outputMeta = $this->getVarInt();
|
||||
$this->potionTypeRecipes[] = new PotionTypeRecipe($input, $inputMeta, $ingredient, $ingredientMeta, $output, $outputMeta);
|
||||
}
|
||||
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
|
||||
$input = $this->getVarInt();
|
||||
@ -193,6 +199,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
$stream->put(str_repeat("\x00", 16)); //Null UUID
|
||||
$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
|
||||
$stream->putVarInt(50); //TODO: priority
|
||||
$stream->writeGenericTypeNetworkId($pos); //TODO: ANOTHER recipe ID, only used on the network
|
||||
|
||||
return CraftingDataPacket::ENTRY_SHAPELESS;
|
||||
}
|
||||
@ -217,6 +224,7 @@ class CraftingDataPacket extends DataPacket{
|
||||
$stream->put(str_repeat("\x00", 16)); //Null UUID
|
||||
$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
|
||||
$stream->putVarInt(50); //TODO: priority
|
||||
$stream->writeGenericTypeNetworkId($pos); //TODO: ANOTHER recipe ID, only used on the network
|
||||
|
||||
return CraftingDataPacket::ENTRY_SHAPED;
|
||||
}
|
||||
@ -272,9 +280,12 @@ class CraftingDataPacket extends DataPacket{
|
||||
}
|
||||
$this->putUnsignedVarInt(count($this->potionTypeRecipes));
|
||||
foreach($this->potionTypeRecipes as $recipe){
|
||||
$this->putVarInt($recipe->getInputPotionType());
|
||||
$this->putVarInt($recipe->getInputItemId());
|
||||
$this->putVarInt($recipe->getInputItemMeta());
|
||||
$this->putVarInt($recipe->getIngredientItemId());
|
||||
$this->putVarInt($recipe->getOutputPotionType());
|
||||
$this->putVarInt($recipe->getIngredientItemMeta());
|
||||
$this->putVarInt($recipe->getOutputItemId());
|
||||
$this->putVarInt($recipe->getOutputItemMeta());
|
||||
}
|
||||
$this->putUnsignedVarInt(count($this->potionContainerRecipes));
|
||||
foreach($this->potionContainerRecipes as $recipe){
|
||||
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
|
||||
use function count;
|
||||
|
||||
class CreativeContentPacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::CREATIVE_CONTENT_PACKET;
|
||||
|
||||
/** @var CreativeContentEntry[] */
|
||||
private $entries;
|
||||
|
||||
/**
|
||||
* @param CreativeContentEntry[] $entries
|
||||
*/
|
||||
public static function create(array $entries) : self{
|
||||
$result = new self;
|
||||
$result->entries = $entries;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** @return CreativeContentEntry[] */
|
||||
public function getEntries() : array{ return $this->entries; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->entries = [];
|
||||
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$this->entries[] = CreativeContentEntry::read($this);
|
||||
}
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putUnsignedVarInt(count($this->entries));
|
||||
foreach($this->entries as $entry){
|
||||
$entry->write($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleCreativeContent($this);
|
||||
}
|
||||
}
|
65
src/pocketmine/network/mcpe/protocol/DebugInfoPacket.php
Normal file
65
src/pocketmine/network/mcpe/protocol/DebugInfoPacket.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class DebugInfoPacket extends DataPacket/* implements ClientboundPacket, ServerboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::DEBUG_INFO_PACKET;
|
||||
|
||||
/** @var int */
|
||||
private $entityUniqueId;
|
||||
/** @var string */
|
||||
private $data;
|
||||
|
||||
public static function create(int $entityUniqueId, string $data) : self{
|
||||
$result = new self;
|
||||
$result->entityUniqueId = $entityUniqueId;
|
||||
$result->data = $data;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: we can't call this getEntityRuntimeId() because of base class collision (crap architecture, thanks Shoghi)
|
||||
*/
|
||||
public function getEntityUniqueIdField() : int{ return $this->entityUniqueId; }
|
||||
|
||||
public function getData() : string{ return $this->data; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->entityUniqueId = $this->getEntityUniqueId();
|
||||
$this->data = $this->getString();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putEntityUniqueId($this->entityUniqueId);
|
||||
$this->putString($this->data);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleDebugInfo($this);
|
||||
}
|
||||
}
|
@ -32,12 +32,21 @@ class EducationSettingsPacket extends DataPacket{
|
||||
|
||||
/** @var string */
|
||||
private $codeBuilderDefaultUri;
|
||||
/** @var string */
|
||||
private $codeBuilderTitle;
|
||||
/** @var bool */
|
||||
private $canResizeCodeBuilder;
|
||||
/** @var string|null */
|
||||
private $codeBuilderOverrideUri;
|
||||
/** @var bool */
|
||||
private $hasQuiz;
|
||||
|
||||
public static function create(string $codeBuilderDefaultUri, bool $hasQuiz) : self{
|
||||
public static function create(string $codeBuilderDefaultUri, string $codeBuilderTitle, bool $canResizeCodeBuilder, ?string $codeBuilderOverrideUri, bool $hasQuiz) : self{
|
||||
$result = new self;
|
||||
$result->codeBuilderDefaultUri = $codeBuilderDefaultUri;
|
||||
$result->codeBuilderTitle = $codeBuilderTitle;
|
||||
$result->canResizeCodeBuilder = $canResizeCodeBuilder;
|
||||
$result->codeBuilderOverrideUri = $codeBuilderOverrideUri;
|
||||
$result->hasQuiz = $hasQuiz;
|
||||
return $result;
|
||||
}
|
||||
@ -46,17 +55,42 @@ class EducationSettingsPacket extends DataPacket{
|
||||
return $this->codeBuilderDefaultUri;
|
||||
}
|
||||
|
||||
public function getCodeBuilderTitle() : string{
|
||||
return $this->codeBuilderTitle;
|
||||
}
|
||||
|
||||
public function canResizeCodeBuilder() : bool{
|
||||
return $this->canResizeCodeBuilder;
|
||||
}
|
||||
|
||||
public function getCodeBuilderOverrideUri() : ?string{
|
||||
return $this->codeBuilderOverrideUri;
|
||||
}
|
||||
|
||||
public function getHasQuiz() : bool{
|
||||
return $this->hasQuiz;
|
||||
}
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->codeBuilderDefaultUri = $this->getString();
|
||||
$this->codeBuilderTitle = $this->getString();
|
||||
$this->canResizeCodeBuilder = $this->getBool();
|
||||
if($this->getBool()){
|
||||
$this->codeBuilderOverrideUri = $this->getString();
|
||||
}else{
|
||||
$this->codeBuilderOverrideUri = null;
|
||||
}
|
||||
$this->hasQuiz = $this->getBool();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putString($this->codeBuilderDefaultUri);
|
||||
$this->putString($this->codeBuilderTitle);
|
||||
$this->putBool($this->canResizeCodeBuilder);
|
||||
$this->putBool($this->codeBuilderOverrideUri !== null);
|
||||
if($this->codeBuilderOverrideUri !== null){
|
||||
$this->putString($this->codeBuilderOverrideUri);
|
||||
}
|
||||
$this->putBool($this->hasQuiz);
|
||||
}
|
||||
|
||||
|
74
src/pocketmine/network/mcpe/protocol/EmoteListPacket.php
Normal file
74
src/pocketmine/network/mcpe/protocol/EmoteListPacket.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\utils\UUID;
|
||||
use function count;
|
||||
|
||||
class EmoteListPacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::EMOTE_LIST_PACKET;
|
||||
|
||||
/** @var int */
|
||||
private $playerEntityRuntimeId;
|
||||
/** @var UUID[] */
|
||||
private $emoteIds;
|
||||
|
||||
/**
|
||||
* @param UUID[] $emoteIds
|
||||
*/
|
||||
public static function create(int $playerEntityRuntimeId, array $emoteIds) : self{
|
||||
$result = new self;
|
||||
$result->playerEntityRuntimeId = $playerEntityRuntimeId;
|
||||
$result->emoteIds = $emoteIds;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getPlayerEntityRuntimeId() : int{ return $this->playerEntityRuntimeId; }
|
||||
|
||||
/** @return UUID[] */
|
||||
public function getEmoteIds() : array{ return $this->emoteIds; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->playerEntityRuntimeId = $this->getEntityRuntimeId();
|
||||
$this->emoteIds = [];
|
||||
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$this->emoteIds[] = $this->getUUID();
|
||||
}
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putEntityRuntimeId($this->playerEntityRuntimeId);
|
||||
$this->putUnsignedVarInt(count($this->emoteIds));
|
||||
foreach($this->emoteIds as $emoteId){
|
||||
$this->putUUID($emoteId);
|
||||
}
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleEmoteList($this);
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ use pocketmine\network\mcpe\NetworkSession;
|
||||
class EmotePacket extends DataPacket/* implements ClientboundPacket, ServerboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::EMOTE_PACKET;
|
||||
|
||||
private const FLAG_SERVER = 1 << 0;
|
||||
public const FLAG_SERVER = 1 << 0;
|
||||
|
||||
/** @var int */
|
||||
private $entityRuntimeId;
|
||||
|
@ -30,14 +30,18 @@ use pocketmine\network\mcpe\NetworkSession;
|
||||
class HurtArmorPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::HURT_ARMOR_PACKET;
|
||||
|
||||
/** @var int */
|
||||
public $cause;
|
||||
/** @var int */
|
||||
public $health;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->cause = $this->getVarInt();
|
||||
$this->health = $this->getVarInt();
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->putVarInt($this->cause);
|
||||
$this->putVarInt($this->health);
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use function count;
|
||||
|
||||
class InventoryContentPacket extends DataPacket{
|
||||
@ -34,14 +34,14 @@ class InventoryContentPacket extends DataPacket{
|
||||
|
||||
/** @var int */
|
||||
public $windowId;
|
||||
/** @var Item[] */
|
||||
/** @var ItemStackWrapper[] */
|
||||
public $items = [];
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->windowId = $this->getUnsignedVarInt();
|
||||
$count = $this->getUnsignedVarInt();
|
||||
for($i = 0; $i < $count; ++$i){
|
||||
$this->items[] = $this->getSlot();
|
||||
$this->items[] = ItemStackWrapper::read($this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ class InventoryContentPacket extends DataPacket{
|
||||
$this->putUnsignedVarInt($this->windowId);
|
||||
$this->putUnsignedVarInt(count($this->items));
|
||||
foreach($this->items as $item){
|
||||
$this->putSlot($item);
|
||||
$item->write($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
|
||||
class InventorySlotPacket extends DataPacket{
|
||||
public const NETWORK_ID = ProtocolInfo::INVENTORY_SLOT_PACKET;
|
||||
@ -35,19 +35,19 @@ class InventorySlotPacket extends DataPacket{
|
||||
public $windowId;
|
||||
/** @var int */
|
||||
public $inventorySlot;
|
||||
/** @var Item */
|
||||
/** @var ItemStackWrapper */
|
||||
public $item;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->windowId = $this->getUnsignedVarInt();
|
||||
$this->inventorySlot = $this->getUnsignedVarInt();
|
||||
$this->item = $this->getSlot();
|
||||
$this->item = ItemStackWrapper::read($this);
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->putUnsignedVarInt($this->windowId);
|
||||
$this->putUnsignedVarInt($this->inventorySlot);
|
||||
$this->putSlot($this->item);
|
||||
$this->item->write($this);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\InventoryTransactionChangedSlotsHack;
|
||||
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
|
||||
use function count;
|
||||
|
||||
@ -48,8 +49,15 @@ class InventoryTransactionPacket extends DataPacket{
|
||||
public const USE_ITEM_ON_ENTITY_ACTION_INTERACT = 0;
|
||||
public const USE_ITEM_ON_ENTITY_ACTION_ATTACK = 1;
|
||||
|
||||
/** @var int */
|
||||
public $requestId;
|
||||
/** @var InventoryTransactionChangedSlotsHack[] */
|
||||
public $requestChangedSlots;
|
||||
|
||||
/** @var int */
|
||||
public $transactionType;
|
||||
/** @var bool */
|
||||
public $hasItemStackIds;
|
||||
|
||||
/** @var NetworkInventoryAction[] */
|
||||
public $actions = [];
|
||||
@ -58,10 +66,20 @@ class InventoryTransactionPacket extends DataPacket{
|
||||
public $trData;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->requestId = $this->readGenericTypeNetworkId();
|
||||
$this->requestChangedSlots = [];
|
||||
if($this->requestId !== 0){
|
||||
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$this->requestChangedSlots[] = InventoryTransactionChangedSlotsHack::read($this);
|
||||
}
|
||||
}
|
||||
|
||||
$this->transactionType = $this->getUnsignedVarInt();
|
||||
|
||||
$this->hasItemStackIds = $this->getBool();
|
||||
|
||||
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
|
||||
$this->actions[] = $action = (new NetworkInventoryAction())->read($this);
|
||||
$this->actions[] = $action = (new NetworkInventoryAction())->read($this, $this->hasItemStackIds);
|
||||
}
|
||||
|
||||
$this->trData = new \stdClass();
|
||||
@ -101,11 +119,21 @@ class InventoryTransactionPacket extends DataPacket{
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->writeGenericTypeNetworkId($this->requestId);
|
||||
if($this->requestId !== 0){
|
||||
$this->putUnsignedVarInt(count($this->requestChangedSlots));
|
||||
foreach($this->requestChangedSlots as $changedSlots){
|
||||
$changedSlots->write($this);
|
||||
}
|
||||
}
|
||||
|
||||
$this->putUnsignedVarInt($this->transactionType);
|
||||
|
||||
$this->putBool($this->hasItemStackIds);
|
||||
|
||||
$this->putUnsignedVarInt(count($this->actions));
|
||||
foreach($this->actions as $action){
|
||||
$action->write($this);
|
||||
$action->write($this, $this->hasItemStackIds);
|
||||
}
|
||||
|
||||
switch($this->transactionType){
|
||||
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\ItemStackRequest;
|
||||
use function count;
|
||||
|
||||
class ItemStackRequestPacket extends DataPacket/* implements ServerboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::ITEM_STACK_REQUEST_PACKET;
|
||||
|
||||
/** @var ItemStackRequest[] */
|
||||
private $requests;
|
||||
|
||||
/**
|
||||
* @param ItemStackRequest[] $requests
|
||||
*/
|
||||
public static function create(array $requests) : self{
|
||||
$result = new self;
|
||||
$result->requests = $requests;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** @return ItemStackRequest[] */
|
||||
public function getRequests() : array{ return $this->requests; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->requests = [];
|
||||
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$this->requests[] = ItemStackRequest::read($this);
|
||||
}
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putUnsignedVarInt(count($this->requests));
|
||||
foreach($this->requests as $request){
|
||||
$request->write($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleItemStackRequest($this);
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\stackresponse\ItemStackResponse;
|
||||
use function count;
|
||||
|
||||
class ItemStackResponsePacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::ITEM_STACK_RESPONSE_PACKET;
|
||||
|
||||
/** @var ItemStackResponse[] */
|
||||
private $responses;
|
||||
|
||||
/**
|
||||
* @param ItemStackResponse[] $responses
|
||||
*/
|
||||
public static function create(array $responses) : self{
|
||||
$result = new self;
|
||||
$result->responses = $responses;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** @return ItemStackResponse[] */
|
||||
public function getResponses() : array{ return $this->responses; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->responses = [];
|
||||
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$this->responses[] = ItemStackResponse::read($this);
|
||||
}
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putUnsignedVarInt(count($this->responses));
|
||||
foreach($this->responses as $response){
|
||||
$response->write($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleItemStackResponse($this);
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@ class LoginPacket extends DataPacket{
|
||||
}
|
||||
|
||||
public function mayHaveUnreadBytes() : bool{
|
||||
return $this->protocol !== null and $this->protocol !== ProtocolInfo::CURRENT_PROTOCOL;
|
||||
return $this->protocol !== ProtocolInfo::CURRENT_PROTOCOL;
|
||||
}
|
||||
|
||||
protected function decodePayload(){
|
||||
@ -92,7 +92,7 @@ class LoginPacket extends DataPacket{
|
||||
}
|
||||
|
||||
$logger = MainLogger::getLogger();
|
||||
$logger->debug(get_class($e) . " was thrown while decoding connection request in login (protocol version " . ($this->protocol ?? "unknown") . "): " . $e->getMessage());
|
||||
$logger->debug(get_class($e) . " was thrown while decoding connection request in login (protocol version $this->protocol): " . $e->getMessage());
|
||||
foreach(Utils::printableTrace($e->getTrace()) as $line){
|
||||
$logger->debug($line);
|
||||
}
|
||||
|
@ -159,7 +159,6 @@ class PacketPool{
|
||||
static::registerPacket(new LevelSoundEventPacket());
|
||||
static::registerPacket(new LevelEventGenericPacket());
|
||||
static::registerPacket(new LecternUpdatePacket());
|
||||
static::registerPacket(new VideoStreamConnectPacket());
|
||||
static::registerPacket(new AddEntityPacket());
|
||||
static::registerPacket(new RemoveEntityPacket());
|
||||
static::registerPacket(new ClientCacheStatusPacket());
|
||||
@ -178,6 +177,18 @@ class PacketPool{
|
||||
static::registerPacket(new CompletedUsingItemPacket());
|
||||
static::registerPacket(new NetworkSettingsPacket());
|
||||
static::registerPacket(new PlayerAuthInputPacket());
|
||||
static::registerPacket(new CreativeContentPacket());
|
||||
static::registerPacket(new PlayerEnchantOptionsPacket());
|
||||
static::registerPacket(new ItemStackRequestPacket());
|
||||
static::registerPacket(new ItemStackResponsePacket());
|
||||
static::registerPacket(new PlayerArmorDamagePacket());
|
||||
static::registerPacket(new CodeBuilderPacket());
|
||||
static::registerPacket(new UpdatePlayerGameTypePacket());
|
||||
static::registerPacket(new EmoteListPacket());
|
||||
static::registerPacket(new PositionTrackingDBServerBroadcastPacket());
|
||||
static::registerPacket(new PositionTrackingDBClientRequestPacket());
|
||||
static::registerPacket(new DebugInfoPacket());
|
||||
static::registerPacket(new PacketViolationWarningPacket());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class PacketViolationWarningPacket extends DataPacket/* implements ServerboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::PACKET_VIOLATION_WARNING_PACKET;
|
||||
|
||||
public const TYPE_MALFORMED = 0;
|
||||
|
||||
public const SEVERITY_WARNING = 0;
|
||||
public const SEVERITY_FINAL_WARNING = 1;
|
||||
public const SEVERITY_TERMINATING_CONNECTION = 2;
|
||||
|
||||
/** @var int */
|
||||
private $type;
|
||||
/** @var int */
|
||||
private $severity;
|
||||
/** @var int */
|
||||
private $packetId;
|
||||
/** @var string */
|
||||
private $message;
|
||||
|
||||
public static function create(int $type, int $severity, int $packetId, string $message) : self{
|
||||
$result = new self;
|
||||
|
||||
$result->type = $type;
|
||||
$result->severity = $severity;
|
||||
$result->packetId = $packetId;
|
||||
$result->message = $message;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getType() : int{ return $this->type; }
|
||||
|
||||
public function getSeverity() : int{ return $this->severity; }
|
||||
|
||||
public function getPacketId() : int{ return $this->packetId; }
|
||||
|
||||
public function getMessage() : string{ return $this->message; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->type = $this->getVarInt();
|
||||
$this->severity = $this->getVarInt();
|
||||
$this->packetId = $this->getVarInt();
|
||||
$this->message = $this->getString();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putVarInt($this->type);
|
||||
$this->putVarInt($this->severity);
|
||||
$this->putVarInt($this->packetId);
|
||||
$this->putString($this->message);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handlePacketViolationWarning($this);
|
||||
}
|
||||
}
|
@ -50,7 +50,7 @@ class PlayerActionPacket extends DataPacket{
|
||||
public const ACTION_BUILD_DENIED = 17;
|
||||
public const ACTION_CONTINUE_BREAK = 18;
|
||||
public const ACTION_CHANGE_SKIN = 19;
|
||||
public const ACTION_SET_ENCHANTMENT_SEED = 20;
|
||||
public const ACTION_SET_ENCHANTMENT_SEED = 20; //no longer used
|
||||
public const ACTION_START_SWIMMING = 21;
|
||||
public const ACTION_STOP_SWIMMING = 22;
|
||||
public const ACTION_START_SPIN_ATTACK = 23;
|
||||
|
108
src/pocketmine/network/mcpe/protocol/PlayerArmorDamagePacket.php
Normal file
108
src/pocketmine/network/mcpe/protocol/PlayerArmorDamagePacket.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class PlayerArmorDamagePacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::PLAYER_ARMOR_DAMAGE_PACKET;
|
||||
|
||||
private const FLAG_HEAD = 0;
|
||||
private const FLAG_CHEST = 1;
|
||||
private const FLAG_LEGS = 2;
|
||||
private const FLAG_FEET = 3;
|
||||
|
||||
/** @var int|null */
|
||||
private $headSlotDamage;
|
||||
/** @var int|null */
|
||||
private $chestSlotDamage;
|
||||
/** @var int|null */
|
||||
private $legsSlotDamage;
|
||||
/** @var int|null */
|
||||
private $feetSlotDamage;
|
||||
|
||||
public static function create(?int $headSlotDamage, ?int $chestSlotDamage, ?int $legsSlotDamage, ?int $feetSlotDamage) : self{
|
||||
$result = new self;
|
||||
$result->headSlotDamage = $headSlotDamage;
|
||||
$result->chestSlotDamage = $chestSlotDamage;
|
||||
$result->legsSlotDamage = $legsSlotDamage;
|
||||
$result->feetSlotDamage = $feetSlotDamage;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getHeadSlotDamage() : ?int{ return $this->headSlotDamage; }
|
||||
|
||||
public function getChestSlotDamage() : ?int{ return $this->chestSlotDamage; }
|
||||
|
||||
public function getLegsSlotDamage() : ?int{ return $this->legsSlotDamage; }
|
||||
|
||||
public function getFeetSlotDamage() : ?int{ return $this->feetSlotDamage; }
|
||||
|
||||
private function maybeReadDamage(int $flags, int $flag) : ?int{
|
||||
if(($flags & (1 << $flag)) !== 0){
|
||||
return $this->getVarInt();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$flags = $this->getByte();
|
||||
|
||||
$this->headSlotDamage = $this->maybeReadDamage($flags, self::FLAG_HEAD);
|
||||
$this->chestSlotDamage = $this->maybeReadDamage($flags, self::FLAG_CHEST);
|
||||
$this->legsSlotDamage = $this->maybeReadDamage($flags, self::FLAG_LEGS);
|
||||
$this->feetSlotDamage = $this->maybeReadDamage($flags, self::FLAG_FEET);
|
||||
}
|
||||
|
||||
private function composeFlag(?int $field, int $flag) : int{
|
||||
return $field !== null ? (1 << $flag) : 0;
|
||||
}
|
||||
|
||||
private function maybeWriteDamage(?int $field) : void{
|
||||
if($field !== null){
|
||||
$this->putVarInt($field);
|
||||
}
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putByte(
|
||||
$this->composeFlag($this->headSlotDamage, self::FLAG_HEAD) |
|
||||
$this->composeFlag($this->chestSlotDamage, self::FLAG_CHEST) |
|
||||
$this->composeFlag($this->legsSlotDamage, self::FLAG_LEGS) |
|
||||
$this->composeFlag($this->feetSlotDamage, self::FLAG_FEET)
|
||||
);
|
||||
|
||||
$this->maybeWriteDamage($this->headSlotDamage);
|
||||
$this->maybeWriteDamage($this->chestSlotDamage);
|
||||
$this->maybeWriteDamage($this->legsSlotDamage);
|
||||
$this->maybeWriteDamage($this->feetSlotDamage);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handlePlayerArmorDamage($this);
|
||||
}
|
||||
}
|
@ -128,8 +128,8 @@ class PlayerAuthInputPacket extends DataPacket/* implements ServerboundPacket*/{
|
||||
}
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->yaw = $this->getLFloat();
|
||||
$this->pitch = $this->getLFloat();
|
||||
$this->yaw = $this->getLFloat();
|
||||
$this->position = $this->getVector3();
|
||||
$this->moveVecX = $this->getLFloat();
|
||||
$this->moveVecZ = $this->getLFloat();
|
||||
@ -143,8 +143,8 @@ class PlayerAuthInputPacket extends DataPacket/* implements ServerboundPacket*/{
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putLFloat($this->yaw);
|
||||
$this->putLFloat($this->pitch);
|
||||
$this->putLFloat($this->yaw);
|
||||
$this->putVector3($this->position);
|
||||
$this->putLFloat($this->moveVecX);
|
||||
$this->putLFloat($this->moveVecZ);
|
||||
|
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\EnchantOption;
|
||||
use function count;
|
||||
|
||||
class PlayerEnchantOptionsPacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::PLAYER_ENCHANT_OPTIONS_PACKET;
|
||||
|
||||
/** @var EnchantOption[] */
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @param EnchantOption[] $options
|
||||
*/
|
||||
public static function create(array $options) : self{
|
||||
$result = new self;
|
||||
$result->options = $options;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EnchantOption[]
|
||||
*/
|
||||
public function getOptions() : array{ return $this->options; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->options = [];
|
||||
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$this->options[] = EnchantOption::read($this);
|
||||
}
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putUnsignedVarInt(count($this->options));
|
||||
foreach($this->options as $option){
|
||||
$option->write($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handlePlayerEnchantOptions($this);
|
||||
}
|
||||
}
|
@ -27,40 +27,38 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class VideoStreamConnectPacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::VIDEO_STREAM_CONNECT_PACKET;
|
||||
class PositionTrackingDBClientRequestPacket extends DataPacket/* implements ServerboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::POSITION_TRACKING_D_B_CLIENT_REQUEST_PACKET;
|
||||
|
||||
public const ACTION_CONNECT = 0;
|
||||
public const ACTION_DISCONNECT = 1;
|
||||
public const ACTION_QUERY = 0;
|
||||
|
||||
/** @var string */
|
||||
public $serverUri;
|
||||
/** @var float */
|
||||
public $frameSendFrequency;
|
||||
/** @var int */
|
||||
public $action;
|
||||
private $action;
|
||||
/** @var int */
|
||||
public $resolutionX;
|
||||
/** @var int */
|
||||
public $resolutionY;
|
||||
private $trackingId;
|
||||
|
||||
public static function create(int $action, int $trackingId) : self{
|
||||
$result = new self;
|
||||
$result->action = $action;
|
||||
$result->trackingId = $trackingId;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getAction() : int{ return $this->action; }
|
||||
|
||||
public function getTrackingId() : int{ return $this->trackingId; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->serverUri = $this->getString();
|
||||
$this->frameSendFrequency = $this->getLFloat();
|
||||
$this->action = $this->getByte();
|
||||
$this->resolutionX = $this->getLInt();
|
||||
$this->resolutionY = $this->getLInt();
|
||||
$this->trackingId = $this->getVarInt();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putString($this->serverUri);
|
||||
$this->putLFloat($this->frameSendFrequency);
|
||||
$this->putByte($this->action);
|
||||
$this->putLInt($this->resolutionX);
|
||||
$this->putLInt($this->resolutionY);
|
||||
$this->putVarInt($this->trackingId);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
return $session->handleVideoStreamConnect($this);
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handlePositionTrackingDBClientRequest($this);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
|
||||
class PositionTrackingDBServerBroadcastPacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::POSITION_TRACKING_D_B_SERVER_BROADCAST_PACKET;
|
||||
|
||||
public const ACTION_UPDATE = 0;
|
||||
public const ACTION_DESTROY = 1;
|
||||
public const ACTION_NOT_FOUND = 2;
|
||||
|
||||
/** @var int */
|
||||
private $action;
|
||||
/** @var int */
|
||||
private $trackingId;
|
||||
/** @var CompoundTag */
|
||||
private $nbt;
|
||||
|
||||
public static function create(int $action, int $trackingId, CompoundTag $nbt) : self{
|
||||
$result = new self;
|
||||
$result->action = $action;
|
||||
$result->trackingId = $trackingId;
|
||||
$result->nbt = $nbt;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getAction() : int{ return $this->action; }
|
||||
|
||||
public function getTrackingId() : int{ return $this->trackingId; }
|
||||
|
||||
public function getNbt() : CompoundTag{ return $this->nbt; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->action = $this->getByte();
|
||||
$this->trackingId = $this->getVarInt();
|
||||
$offset = $this->getOffset();
|
||||
$nbt = (new NetworkLittleEndianNBTStream())->read($this->getBuffer(), false, $offset);
|
||||
$this->setOffset($offset);
|
||||
if(!($nbt instanceof CompoundTag)){
|
||||
throw new \UnexpectedValueException("Expected TAG_Compound");
|
||||
}
|
||||
$this->nbt = $nbt;
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putByte($this->action);
|
||||
$this->putVarInt($this->trackingId);
|
||||
$this->put((new NetworkLittleEndianNBTStream())->write($this->nbt));
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handlePositionTrackingDBServerBroadcast($this);
|
||||
}
|
||||
}
|
@ -37,11 +37,11 @@ interface ProtocolInfo{
|
||||
*/
|
||||
|
||||
/** Actual Minecraft: PE protocol version */
|
||||
public const CURRENT_PROTOCOL = 390;
|
||||
public const CURRENT_PROTOCOL = 408;
|
||||
/** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */
|
||||
public const MINECRAFT_VERSION = 'v1.14.60';
|
||||
public const MINECRAFT_VERSION = 'v1.16.20';
|
||||
/** Version number sent to clients in ping responses. */
|
||||
public const MINECRAFT_VERSION_NETWORK = '1.14.60';
|
||||
public const MINECRAFT_VERSION_NETWORK = '1.16.20';
|
||||
|
||||
public const LOGIN_PACKET = 0x01;
|
||||
public const PLAY_STATUS_PACKET = 0x02;
|
||||
@ -168,7 +168,7 @@ interface ProtocolInfo{
|
||||
public const LEVEL_SOUND_EVENT_PACKET = 0x7b;
|
||||
public const LEVEL_EVENT_GENERIC_PACKET = 0x7c;
|
||||
public const LECTERN_UPDATE_PACKET = 0x7d;
|
||||
public const VIDEO_STREAM_CONNECT_PACKET = 0x7e;
|
||||
|
||||
public const ADD_ENTITY_PACKET = 0x7f;
|
||||
public const REMOVE_ENTITY_PACKET = 0x80;
|
||||
public const CLIENT_CACHE_STATUS_PACKET = 0x81;
|
||||
@ -187,5 +187,17 @@ interface ProtocolInfo{
|
||||
public const COMPLETED_USING_ITEM_PACKET = 0x8e;
|
||||
public const NETWORK_SETTINGS_PACKET = 0x8f;
|
||||
public const PLAYER_AUTH_INPUT_PACKET = 0x90;
|
||||
public const CREATIVE_CONTENT_PACKET = 0x91;
|
||||
public const PLAYER_ENCHANT_OPTIONS_PACKET = 0x92;
|
||||
public const ITEM_STACK_REQUEST_PACKET = 0x93;
|
||||
public const ITEM_STACK_RESPONSE_PACKET = 0x94;
|
||||
public const PLAYER_ARMOR_DAMAGE_PACKET = 0x95;
|
||||
public const CODE_BUILDER_PACKET = 0x96;
|
||||
public const UPDATE_PLAYER_GAME_TYPE_PACKET = 0x97;
|
||||
public const EMOTE_LIST_PACKET = 0x98;
|
||||
public const POSITION_TRACKING_D_B_SERVER_BROADCAST_PACKET = 0x99;
|
||||
public const POSITION_TRACKING_D_B_CLIENT_REQUEST_PACKET = 0x9a;
|
||||
public const DEBUG_INFO_PACKET = 0x9b;
|
||||
public const PACKET_VIOLATION_WARNING_PACKET = 0x9c;
|
||||
|
||||
}
|
||||
|
@ -41,19 +41,27 @@ class SetSpawnPositionPacket extends DataPacket{
|
||||
public $y;
|
||||
/** @var int */
|
||||
public $z;
|
||||
/** @var bool */
|
||||
public $spawnForced;
|
||||
/** @var int */
|
||||
public $dimension;
|
||||
/** @var int */
|
||||
public $x2;
|
||||
/** @var int */
|
||||
public $y2;
|
||||
/** @var int */
|
||||
public $z2;
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->spawnType = $this->getVarInt();
|
||||
$this->getBlockPosition($this->x, $this->y, $this->z);
|
||||
$this->spawnForced = $this->getBool();
|
||||
$this->dimension = $this->getVarInt();
|
||||
$this->getBlockPosition($this->x2, $this->y2, $this->z2);
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
$this->putVarInt($this->spawnType);
|
||||
$this->putBlockPosition($this->x, $this->y, $this->z);
|
||||
$this->putBool($this->spawnForced);
|
||||
$this->putVarInt($this->dimension);
|
||||
$this->putBlockPosition($this->x2, $this->y2, $this->z2);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $session) : bool{
|
||||
|
@ -28,6 +28,7 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\EducationEditionOffer;
|
||||
@ -35,7 +36,7 @@ use pocketmine\network\mcpe\protocol\types\GameRuleType;
|
||||
use pocketmine\network\mcpe\protocol\types\GeneratorType;
|
||||
use pocketmine\network\mcpe\protocol\types\MultiplayerGameVisibility;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use pocketmine\network\mcpe\protocol\types\SpawnSettings;
|
||||
use function count;
|
||||
use function file_get_contents;
|
||||
use function json_decode;
|
||||
@ -66,8 +67,8 @@ class StartGamePacket extends DataPacket{
|
||||
|
||||
/** @var int */
|
||||
public $seed;
|
||||
/** @var int */
|
||||
public $dimension;
|
||||
/** @var SpawnSettings */
|
||||
public $spawnSettings;
|
||||
/** @var int */
|
||||
public $generator = GeneratorType::OVERWORLD;
|
||||
/** @var int */
|
||||
@ -88,6 +89,8 @@ class StartGamePacket extends DataPacket{
|
||||
public $eduEditionOffer = EducationEditionOffer::NONE;
|
||||
/** @var bool */
|
||||
public $hasEduFeaturesEnabled = false;
|
||||
/** @var string */
|
||||
public $eduProductUUID = "";
|
||||
/** @var float */
|
||||
public $rainLevel;
|
||||
/** @var float */
|
||||
@ -137,9 +140,17 @@ class StartGamePacket extends DataPacket{
|
||||
public $isWorldTemplateOptionLocked = false;
|
||||
/** @var bool */
|
||||
public $onlySpawnV1Villagers = false;
|
||||
|
||||
/** @var string */
|
||||
public $vanillaVersion = ProtocolInfo::MINECRAFT_VERSION_NETWORK;
|
||||
/** @var int */
|
||||
public $limitedWorldWidth = 0;
|
||||
/** @var int */
|
||||
public $limitedWorldLength = 0;
|
||||
/** @var bool */
|
||||
public $isNewNether = true;
|
||||
/** @var bool|null */
|
||||
public $experimentalGameplayOverride = null;
|
||||
|
||||
/** @var string */
|
||||
public $levelId = ""; //base64 string, usually the same as world folder name in vanilla
|
||||
/** @var string */
|
||||
@ -164,6 +175,8 @@ class StartGamePacket extends DataPacket{
|
||||
* @phpstan-var array<string, int>|null
|
||||
*/
|
||||
public $itemTable = null;
|
||||
/** @var bool */
|
||||
public $enableNewInventorySystem = false; //TODO
|
||||
|
||||
protected function decodePayload(){
|
||||
$this->entityUniqueId = $this->getEntityUniqueId();
|
||||
@ -177,7 +190,7 @@ class StartGamePacket extends DataPacket{
|
||||
|
||||
//Level settings
|
||||
$this->seed = $this->getVarInt();
|
||||
$this->dimension = $this->getVarInt();
|
||||
$this->spawnSettings = SpawnSettings::read($this);
|
||||
$this->generator = $this->getVarInt();
|
||||
$this->worldGamemode = $this->getVarInt();
|
||||
$this->difficulty = $this->getVarInt();
|
||||
@ -186,6 +199,7 @@ class StartGamePacket extends DataPacket{
|
||||
$this->time = $this->getVarInt();
|
||||
$this->eduEditionOffer = $this->getVarInt();
|
||||
$this->hasEduFeaturesEnabled = $this->getBool();
|
||||
$this->eduProductUUID = $this->getString();
|
||||
$this->rainLevel = $this->getLFloat();
|
||||
$this->lightningLevel = $this->getLFloat();
|
||||
$this->hasConfirmedPlatformLockedContent = $this->getBool();
|
||||
@ -207,8 +221,16 @@ class StartGamePacket extends DataPacket{
|
||||
$this->isFromWorldTemplate = $this->getBool();
|
||||
$this->isWorldTemplateOptionLocked = $this->getBool();
|
||||
$this->onlySpawnV1Villagers = $this->getBool();
|
||||
|
||||
$this->vanillaVersion = $this->getString();
|
||||
$this->limitedWorldWidth = $this->getLInt();
|
||||
$this->limitedWorldLength = $this->getLInt();
|
||||
$this->isNewNether = $this->getBool();
|
||||
if($this->getBool()){
|
||||
$this->experimentalGameplayOverride = $this->getBool();
|
||||
}else{
|
||||
$this->experimentalGameplayOverride = null;
|
||||
}
|
||||
|
||||
$this->levelId = $this->getString();
|
||||
$this->worldName = $this->getString();
|
||||
$this->premiumWorldTemplateId = $this->getString();
|
||||
@ -233,6 +255,7 @@ class StartGamePacket extends DataPacket{
|
||||
}
|
||||
|
||||
$this->multiplayerCorrelationId = $this->getString();
|
||||
$this->enableNewInventorySystem = $this->getBool();
|
||||
}
|
||||
|
||||
protected function encodePayload(){
|
||||
@ -247,7 +270,7 @@ class StartGamePacket extends DataPacket{
|
||||
|
||||
//Level settings
|
||||
$this->putVarInt($this->seed);
|
||||
$this->putVarInt($this->dimension);
|
||||
$this->spawnSettings->write($this);
|
||||
$this->putVarInt($this->generator);
|
||||
$this->putVarInt($this->worldGamemode);
|
||||
$this->putVarInt($this->difficulty);
|
||||
@ -256,6 +279,7 @@ class StartGamePacket extends DataPacket{
|
||||
$this->putVarInt($this->time);
|
||||
$this->putVarInt($this->eduEditionOffer);
|
||||
$this->putBool($this->hasEduFeaturesEnabled);
|
||||
$this->putString($this->eduProductUUID);
|
||||
$this->putLFloat($this->rainLevel);
|
||||
$this->putLFloat($this->lightningLevel);
|
||||
$this->putBool($this->hasConfirmedPlatformLockedContent);
|
||||
@ -277,8 +301,15 @@ class StartGamePacket extends DataPacket{
|
||||
$this->putBool($this->isFromWorldTemplate);
|
||||
$this->putBool($this->isWorldTemplateOptionLocked);
|
||||
$this->putBool($this->onlySpawnV1Villagers);
|
||||
|
||||
$this->putString($this->vanillaVersion);
|
||||
$this->putLInt($this->limitedWorldWidth);
|
||||
$this->putLInt($this->limitedWorldLength);
|
||||
$this->putBool($this->isNewNether);
|
||||
$this->putBool($this->experimentalGameplayOverride !== null);
|
||||
if($this->experimentalGameplayOverride !== null){
|
||||
$this->putBool($this->experimentalGameplayOverride);
|
||||
}
|
||||
|
||||
$this->putString($this->levelId);
|
||||
$this->putString($this->worldName);
|
||||
$this->putString($this->premiumWorldTemplateId);
|
||||
@ -307,6 +338,7 @@ class StartGamePacket extends DataPacket{
|
||||
}
|
||||
|
||||
$this->putString($this->multiplayerCorrelationId);
|
||||
$this->putBool($this->enableNewInventorySystem);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,7 +40,8 @@ class TextPacket extends DataPacket{
|
||||
public const TYPE_SYSTEM = 6;
|
||||
public const TYPE_WHISPER = 7;
|
||||
public const TYPE_ANNOUNCEMENT = 8;
|
||||
public const TYPE_JSON = 9;
|
||||
public const TYPE_JSON_WHISPER = 9;
|
||||
public const TYPE_JSON = 10;
|
||||
|
||||
/** @var int */
|
||||
public $type;
|
||||
@ -69,6 +70,7 @@ class TextPacket extends DataPacket{
|
||||
case self::TYPE_RAW:
|
||||
case self::TYPE_TIP:
|
||||
case self::TYPE_SYSTEM:
|
||||
case self::TYPE_JSON_WHISPER:
|
||||
case self::TYPE_JSON:
|
||||
$this->message = $this->getString();
|
||||
break;
|
||||
@ -100,6 +102,7 @@ class TextPacket extends DataPacket{
|
||||
case self::TYPE_RAW:
|
||||
case self::TYPE_TIP:
|
||||
case self::TYPE_SYSTEM:
|
||||
case self::TYPE_JSON_WHISPER:
|
||||
case self::TYPE_JSON:
|
||||
$this->putString($this->message);
|
||||
break;
|
||||
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\types\GameMode;
|
||||
|
||||
class UpdatePlayerGameTypePacket extends DataPacket/* implements ClientboundPacket*/{
|
||||
public const NETWORK_ID = ProtocolInfo::UPDATE_PLAYER_GAME_TYPE_PACKET;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @see GameMode
|
||||
*/
|
||||
private $gameMode;
|
||||
|
||||
/** @var int */
|
||||
private $playerEntityUniqueId;
|
||||
|
||||
public static function create(int $gameMode, int $playerEntityUniqueId) : self{
|
||||
$result = new self;
|
||||
$result->gameMode = $gameMode;
|
||||
$result->playerEntityUniqueId = $playerEntityUniqueId;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getGameMode() : int{ return $this->gameMode; }
|
||||
|
||||
public function getPlayerEntityUniqueId() : int{ return $this->playerEntityUniqueId; }
|
||||
|
||||
protected function decodePayload() : void{
|
||||
$this->gameMode = $this->getVarInt();
|
||||
$this->playerEntityUniqueId = $this->getEntityUniqueId();
|
||||
}
|
||||
|
||||
protected function encodePayload() : void{
|
||||
$this->putVarInt($this->gameMode);
|
||||
$this->putEntityUniqueId($this->playerEntityUniqueId);
|
||||
}
|
||||
|
||||
public function handle(NetworkSession $handler) : bool{
|
||||
return $handler->handleUpdatePlayerGameType($this);
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ interface ContainerIds{
|
||||
public const LAST = 100;
|
||||
public const OFFHAND = 119;
|
||||
public const ARMOR = 120;
|
||||
public const CREATIVE = 121;
|
||||
|
||||
public const HOTBAR = 122;
|
||||
public const FIXED_INVENTORY = 123;
|
||||
public const UI = 124;
|
||||
|
53
src/pocketmine/network/mcpe/protocol/types/Enchant.php
Normal file
53
src/pocketmine/network/mcpe/protocol/types/Enchant.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
|
||||
final class Enchant{
|
||||
/** @var int */
|
||||
private $id;
|
||||
/** @var int */
|
||||
private $level;
|
||||
|
||||
public function __construct(int $id, int $level){
|
||||
$this->id = $id;
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
public function getId() : int{ return $this->id; }
|
||||
|
||||
public function getLevel() : int{ return $this->level; }
|
||||
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$id = $in->getByte();
|
||||
$level = $in->getByte();
|
||||
return new self($id, $level);
|
||||
}
|
||||
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->putByte($this->id);
|
||||
$out->putByte($this->level);
|
||||
}
|
||||
}
|
126
src/pocketmine/network/mcpe/protocol/types/EnchantOption.php
Normal file
126
src/pocketmine/network/mcpe/protocol/types/EnchantOption.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use function count;
|
||||
|
||||
final class EnchantOption{
|
||||
/** @var int */
|
||||
private $cost;
|
||||
|
||||
/** @var int */
|
||||
private $slotFlags;
|
||||
/** @var Enchant[] */
|
||||
private $equipActivatedEnchantments;
|
||||
/** @var Enchant[] */
|
||||
private $heldActivatedEnchantments;
|
||||
/** @var Enchant[] */
|
||||
private $selfActivatedEnchantments;
|
||||
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var int */
|
||||
private $optionId;
|
||||
|
||||
/**
|
||||
* @param Enchant[] $equipActivatedEnchantments
|
||||
* @param Enchant[] $heldActivatedEnchantments
|
||||
* @param Enchant[] $selfActivatedEnchantments
|
||||
*/
|
||||
public function __construct(int $cost, int $slotFlags, array $equipActivatedEnchantments, array $heldActivatedEnchantments, array $selfActivatedEnchantments, string $name, int $optionId){
|
||||
$this->cost = $cost;
|
||||
$this->slotFlags = $slotFlags;
|
||||
$this->equipActivatedEnchantments = $equipActivatedEnchantments;
|
||||
$this->heldActivatedEnchantments = $heldActivatedEnchantments;
|
||||
$this->selfActivatedEnchantments = $selfActivatedEnchantments;
|
||||
$this->name = $name;
|
||||
$this->optionId = $optionId;
|
||||
}
|
||||
|
||||
public function getCost() : int{ return $this->cost; }
|
||||
|
||||
public function getSlotFlags() : int{ return $this->slotFlags; }
|
||||
|
||||
/** @return Enchant[] */
|
||||
public function getEquipActivatedEnchantments() : array{ return $this->equipActivatedEnchantments; }
|
||||
|
||||
/** @return Enchant[] */
|
||||
public function getHeldActivatedEnchantments() : array{ return $this->heldActivatedEnchantments; }
|
||||
|
||||
/** @return Enchant[] */
|
||||
public function getSelfActivatedEnchantments() : array{ return $this->selfActivatedEnchantments; }
|
||||
|
||||
public function getName() : string{ return $this->name; }
|
||||
|
||||
public function getOptionId() : int{ return $this->optionId; }
|
||||
|
||||
/**
|
||||
* @return Enchant[]
|
||||
*/
|
||||
private static function readEnchantList(NetworkBinaryStream $in) : array{
|
||||
$result = [];
|
||||
for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$result[] = Enchant::read($in);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Enchant[] $list
|
||||
*/
|
||||
private static function writeEnchantList(NetworkBinaryStream $out, array $list) : void{
|
||||
$out->putUnsignedVarInt(count($list));
|
||||
foreach($list as $item){
|
||||
$item->write($out);
|
||||
}
|
||||
}
|
||||
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$cost = $in->getUnsignedVarInt();
|
||||
|
||||
$slotFlags = $in->getLInt();
|
||||
$equipActivatedEnchants = self::readEnchantList($in);
|
||||
$heldActivatedEnchants = self::readEnchantList($in);
|
||||
$selfActivatedEnchants = self::readEnchantList($in);
|
||||
|
||||
$name = $in->getString();
|
||||
$optionId = $in->readGenericTypeNetworkId();
|
||||
|
||||
return new self($cost, $slotFlags, $equipActivatedEnchants, $heldActivatedEnchants, $selfActivatedEnchants, $name, $optionId);
|
||||
}
|
||||
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->putUnsignedVarInt($this->cost);
|
||||
|
||||
$out->putLInt($this->slotFlags);
|
||||
self::writeEnchantList($out, $this->equipActivatedEnchantments);
|
||||
self::writeEnchantList($out, $this->heldActivatedEnchantments);
|
||||
self::writeEnchantList($out, $this->selfActivatedEnchantments);
|
||||
|
||||
$out->putString($this->name);
|
||||
$out->writeGenericTypeNetworkId($this->optionId);
|
||||
}
|
||||
}
|
@ -37,11 +37,14 @@ class EntityLink{
|
||||
public $type;
|
||||
/** @var bool */
|
||||
public $immediate; //for dismounting on mount death
|
||||
/** @var bool */
|
||||
public $causedByRider;
|
||||
|
||||
public function __construct(int $fromEntityUniqueId, int $toEntityUniqueId, int $type, bool $immediate){
|
||||
public function __construct(int $fromEntityUniqueId, int $toEntityUniqueId, int $type, bool $immediate, bool $causedByRider){
|
||||
$this->fromEntityUniqueId = $fromEntityUniqueId;
|
||||
$this->toEntityUniqueId = $toEntityUniqueId;
|
||||
$this->type = $type;
|
||||
$this->immediate = $immediate;
|
||||
$this->causedByRider = $causedByRider;
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,9 @@ use pocketmine\inventory\transaction\action\InventoryAction;
|
||||
use pocketmine\inventory\transaction\action\SlotChangeAction;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
|
||||
use pocketmine\Player;
|
||||
use function array_key_exists;
|
||||
|
||||
class NetworkInventoryAction{
|
||||
public const SOURCE_CONTAINER = 0;
|
||||
@ -81,11 +83,13 @@ class NetworkInventoryAction{
|
||||
public $oldItem;
|
||||
/** @var Item */
|
||||
public $newItem;
|
||||
/** @var int|null */
|
||||
public $newItemStackId = null;
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function read(NetworkBinaryStream $packet){
|
||||
public function read(NetworkBinaryStream $packet, bool $hasItemStackIds){
|
||||
$this->sourceType = $packet->getUnsignedVarInt();
|
||||
|
||||
switch($this->sourceType){
|
||||
@ -107,6 +111,9 @@ class NetworkInventoryAction{
|
||||
$this->inventorySlot = $packet->getUnsignedVarInt();
|
||||
$this->oldItem = $packet->getSlot();
|
||||
$this->newItem = $packet->getSlot();
|
||||
if($hasItemStackIds){
|
||||
$this->newItemStackId = $packet->readGenericTypeNetworkId();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -114,7 +121,7 @@ class NetworkInventoryAction{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function write(NetworkBinaryStream $packet){
|
||||
public function write(NetworkBinaryStream $packet, bool $hasItemStackIds){
|
||||
$packet->putUnsignedVarInt($this->sourceType);
|
||||
|
||||
switch($this->sourceType){
|
||||
@ -136,6 +143,12 @@ class NetworkInventoryAction{
|
||||
$packet->putUnsignedVarInt($this->inventorySlot);
|
||||
$packet->putSlot($this->oldItem);
|
||||
$packet->putSlot($this->newItem);
|
||||
if($hasItemStackIds){
|
||||
if($this->newItemStackId === null){
|
||||
throw new \InvalidStateException("Item stack ID for newItem must be provided");
|
||||
}
|
||||
$packet->writeGenericTypeNetworkId($this->newItemStackId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -151,21 +164,21 @@ class NetworkInventoryAction{
|
||||
switch($this->sourceType){
|
||||
case self::SOURCE_CONTAINER:
|
||||
if($this->windowId === ContainerIds::UI and $this->inventorySlot > 0){
|
||||
if($this->inventorySlot === 50){
|
||||
if($this->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT){
|
||||
return null; //useless noise
|
||||
}
|
||||
if($this->inventorySlot >= 28 and $this->inventorySlot <= 31){
|
||||
if(array_key_exists($this->inventorySlot, UIInventorySlotOffset::CRAFTING2X2_INPUT)){
|
||||
$window = $player->getCraftingGrid();
|
||||
if($window->getGridWidth() !== CraftingGrid::SIZE_SMALL){
|
||||
throw new \UnexpectedValueException("Expected small crafting grid");
|
||||
}
|
||||
$slot = $this->inventorySlot - 28;
|
||||
}elseif($this->inventorySlot >= 32 and $this->inventorySlot <= 40){
|
||||
$slot = UIInventorySlotOffset::CRAFTING2X2_INPUT[$this->inventorySlot];
|
||||
}elseif(array_key_exists($this->inventorySlot, UIInventorySlotOffset::CRAFTING3X3_INPUT)){
|
||||
$window = $player->getCraftingGrid();
|
||||
if($window->getGridWidth() !== CraftingGrid::SIZE_BIG){
|
||||
throw new \UnexpectedValueException("Expected big crafting grid");
|
||||
}
|
||||
$slot = $this->inventorySlot - 32;
|
||||
$slot = UIInventorySlotOffset::CRAFTING3X3_INPUT[$this->inventorySlot];
|
||||
}else{
|
||||
throw new \UnexpectedValueException("Unhandled magic UI slot offset $this->inventorySlot");
|
||||
}
|
||||
|
@ -25,27 +25,48 @@ namespace pocketmine\network\mcpe\protocol\types;
|
||||
|
||||
class PotionTypeRecipe{
|
||||
/** @var int */
|
||||
private $inputPotionType;
|
||||
private $inputItemId;
|
||||
/** @var int */
|
||||
private $inputItemMeta;
|
||||
/** @var int */
|
||||
private $ingredientItemId;
|
||||
/** @var int */
|
||||
private $outputPotionType;
|
||||
private $ingredientItemMeta;
|
||||
/** @var int */
|
||||
private $outputItemId;
|
||||
/** @var int */
|
||||
private $outputItemMeta;
|
||||
|
||||
public function __construct(int $inputPotionType, int $ingredientItemId, int $outputPotionType){
|
||||
$this->inputPotionType = $inputPotionType;
|
||||
public function __construct(int $inputItemId, int $inputItemMeta, int $ingredientItemId, int $ingredientItemMeta, int $outputItemId, int $outputItemMeta){
|
||||
$this->inputItemId = $inputItemId;
|
||||
$this->inputItemMeta = $inputItemMeta;
|
||||
$this->ingredientItemId = $ingredientItemId;
|
||||
$this->outputPotionType = $outputPotionType;
|
||||
$this->ingredientItemMeta = $ingredientItemMeta;
|
||||
$this->outputItemId = $outputItemId;
|
||||
$this->outputItemMeta = $outputItemMeta;
|
||||
}
|
||||
|
||||
public function getInputPotionType() : int{
|
||||
return $this->inputPotionType;
|
||||
public function getInputItemId() : int{
|
||||
return $this->inputItemId;
|
||||
}
|
||||
|
||||
public function getInputItemMeta() : int{
|
||||
return $this->inputItemMeta;
|
||||
}
|
||||
|
||||
public function getIngredientItemId() : int{
|
||||
return $this->ingredientItemId;
|
||||
}
|
||||
|
||||
public function getOutputPotionType() : int{
|
||||
return $this->outputPotionType;
|
||||
public function getIngredientItemMeta() : int{
|
||||
return $this->ingredientItemMeta;
|
||||
}
|
||||
|
||||
public function getOutputItemId() : int{
|
||||
return $this->outputItemId;
|
||||
}
|
||||
|
||||
public function getOutputItemMeta() : int{
|
||||
return $this->outputItemMeta;
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ class SkinData{
|
||||
* @param PersonaSkinPiece[] $personaPieces
|
||||
* @param PersonaPieceTintColor[] $pieceTintColors
|
||||
*/
|
||||
public function __construct(string $skinId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = "", ?string $fullSkinId = null, string $armSize = self::ARM_SIZE_WIDE, string $skinColor = "", array $personaPieces = [], array $pieceTintColors = [], bool $isVerified = false){
|
||||
public function __construct(string $skinId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = "", ?string $fullSkinId = null, string $armSize = self::ARM_SIZE_WIDE, string $skinColor = "", array $personaPieces = [], array $pieceTintColors = [], bool $isVerified = true){
|
||||
$this->skinId = $skinId;
|
||||
$this->resourcePatch = $resourcePatch;
|
||||
$this->skinImage = $skinImage;
|
||||
|
73
src/pocketmine/network/mcpe/protocol/types/SpawnSettings.php
Normal file
73
src/pocketmine/network/mcpe/protocol/types/SpawnSettings.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
|
||||
final class SpawnSettings{
|
||||
public const BIOME_TYPE_DEFAULT = 0;
|
||||
public const BIOME_TYPE_USER_DEFINED = 1;
|
||||
|
||||
/** @var int */
|
||||
private $biomeType;
|
||||
/** @var string */
|
||||
private $biomeName;
|
||||
/** @var int */
|
||||
private $dimension;
|
||||
|
||||
public function __construct(int $biomeType, string $biomeName, int $dimension){
|
||||
$this->biomeType = $biomeType;
|
||||
$this->biomeName = $biomeName;
|
||||
$this->dimension = $dimension;
|
||||
}
|
||||
|
||||
public function getBiomeType() : int{
|
||||
return $this->biomeType;
|
||||
}
|
||||
|
||||
public function getBiomeName() : string{
|
||||
return $this->biomeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DimensionIds
|
||||
*/
|
||||
public function getDimension() : int{
|
||||
return $this->dimension;
|
||||
}
|
||||
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$biomeType = $in->getLShort();
|
||||
$biomeName = $in->getString();
|
||||
$dimension = $in->getVarInt();
|
||||
|
||||
return new self($biomeType, $biomeName, $dimension);
|
||||
}
|
||||
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->putLShort($this->biomeType);
|
||||
$out->putString($this->biomeName);
|
||||
$out->putVarInt($this->dimension);
|
||||
}
|
||||
}
|
@ -59,5 +59,8 @@ interface WindowTypes{
|
||||
public const SMOKER = 28;
|
||||
public const STONECUTTER = 29;
|
||||
public const CARTOGRAPHY = 30;
|
||||
public const HUD = 31;
|
||||
public const JIGSAW_EDITOR = 32;
|
||||
public const SMITHING_TABLE = 33;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
|
||||
final class CreativeContentEntry{
|
||||
|
||||
/** @var int */
|
||||
private $entryId;
|
||||
/** @var Item */
|
||||
private $item;
|
||||
|
||||
public function __construct(int $entryId, Item $item){
|
||||
$this->entryId = $entryId;
|
||||
$this->item = $item;
|
||||
}
|
||||
|
||||
public function getEntryId() : int{ return $this->entryId; }
|
||||
|
||||
public function getItem() : Item{ return $this->item; }
|
||||
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$entryId = $in->readGenericTypeNetworkId();
|
||||
$item = $in->getSlot();
|
||||
return new self($entryId, $item);
|
||||
}
|
||||
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->writeGenericTypeNetworkId($this->entryId);
|
||||
$out->putSlot($this->item);
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
use function count;
|
||||
|
||||
final class InventoryTransactionChangedSlotsHack{
|
||||
|
||||
/** @var int */
|
||||
private $containerId;
|
||||
/** @var int[] */
|
||||
private $changedSlotIndexes;
|
||||
|
||||
/**
|
||||
* @param int[] $changedSlotIndexes
|
||||
*/
|
||||
public function __construct(int $containerId, array $changedSlotIndexes){
|
||||
$this->containerId = $containerId;
|
||||
$this->changedSlotIndexes = $changedSlotIndexes;
|
||||
}
|
||||
|
||||
public function getContainerId() : int{ return $this->containerId; }
|
||||
|
||||
/** @return int[] */
|
||||
public function getChangedSlotIndexes() : array{ return $this->changedSlotIndexes; }
|
||||
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$containerId = $in->getByte();
|
||||
$changedSlots = [];
|
||||
for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){
|
||||
$changedSlots[] = $in->getByte();
|
||||
}
|
||||
return new self($containerId, $changedSlots);
|
||||
}
|
||||
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->putByte($this->containerId);
|
||||
$out->putUnsignedVarInt(count($this->changedSlotIndexes));
|
||||
foreach($this->changedSlotIndexes as $index){
|
||||
$out->putByte($index);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
|
||||
final class ItemStackWrapper{
|
||||
|
||||
/** @var int */
|
||||
private $stackId;
|
||||
/** @var Item */
|
||||
private $itemStack;
|
||||
|
||||
public function __construct(int $stackId, Item $itemStack){
|
||||
$this->stackId = $stackId;
|
||||
$this->itemStack = $itemStack;
|
||||
}
|
||||
|
||||
public static function legacy(Item $itemStack) : self{
|
||||
return new self($itemStack->isNull() ? 0 : 1, $itemStack);
|
||||
}
|
||||
|
||||
public function getStackId() : int{ return $this->stackId; }
|
||||
|
||||
public function getItemStack() : Item{ return $this->itemStack; }
|
||||
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$stackId = $in->readGenericTypeNetworkId();
|
||||
$stack = $in->getSlot();
|
||||
return new self($stackId, $stack);
|
||||
}
|
||||
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->writeGenericTypeNetworkId($this->stackId);
|
||||
$out->putSlot($this->itemStack);
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory;
|
||||
|
||||
final class UIInventorySlotOffset{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public const CURSOR = 0;
|
||||
public const ANVIL = [
|
||||
1 => 0,
|
||||
2 => 1,
|
||||
];
|
||||
public const STONE_CUTTER_INPUT = 3;
|
||||
public const TRADE2_INGREDIENT = [
|
||||
4 => 0,
|
||||
5 => 1,
|
||||
];
|
||||
public const TRADE_INGREDIENT = [
|
||||
6 => 0,
|
||||
7 => 1,
|
||||
];
|
||||
public const MATERIAL_REDUCER_INPUT = 8;
|
||||
public const LOOM = [
|
||||
9 => 0,
|
||||
10 => 1,
|
||||
11 => 2,
|
||||
];
|
||||
public const CARTOGRAPHY_TABLE = [
|
||||
12 => 0,
|
||||
13 => 1,
|
||||
];
|
||||
public const ENCHANTING_TABLE = [
|
||||
14 => 0,
|
||||
15 => 1,
|
||||
];
|
||||
public const GRINDSTONE = [
|
||||
16 => 0,
|
||||
17 => 1,
|
||||
];
|
||||
public const COMPOUND_CREATOR_INPUT = [
|
||||
18 => 0,
|
||||
19 => 1,
|
||||
20 => 2,
|
||||
21 => 3,
|
||||
22 => 4,
|
||||
23 => 5,
|
||||
24 => 6,
|
||||
25 => 7,
|
||||
26 => 8,
|
||||
];
|
||||
public const BEACON_PAYMENT = 27;
|
||||
public const CRAFTING2X2_INPUT = [
|
||||
28 => 0,
|
||||
29 => 1,
|
||||
30 => 2,
|
||||
31 => 3,
|
||||
];
|
||||
public const CRAFTING3X3_INPUT = [
|
||||
32 => 0,
|
||||
33 => 1,
|
||||
34 => 2,
|
||||
35 => 3,
|
||||
36 => 4,
|
||||
37 => 5,
|
||||
38 => 6,
|
||||
39 => 7,
|
||||
40 => 8,
|
||||
];
|
||||
public const MATERIAL_REDUCER_OUTPUT = [
|
||||
41 => 0,
|
||||
42 => 1,
|
||||
43 => 2,
|
||||
44 => 3,
|
||||
45 => 4,
|
||||
46 => 5,
|
||||
47 => 6,
|
||||
48 => 7,
|
||||
49 => 8,
|
||||
];
|
||||
public const CREATED_ITEM_OUTPUT = 50;
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
|
||||
|
||||
use pocketmine\network\mcpe\NetworkBinaryStream;
|
||||
|
||||
/**
|
||||
* Completes a transaction involving a beacon consuming input to produce effects.
|
||||
*/
|
||||
final class BeaconPaymentStackRequestAction extends ItemStackRequestAction{
|
||||
|
||||
/** @var int */
|
||||
private $primaryEffectId;
|
||||
/** @var int */
|
||||
private $secondaryEffectId;
|
||||
|
||||
public function __construct(int $primaryEffectId, int $secondaryEffectId){
|
||||
$this->primaryEffectId = $primaryEffectId;
|
||||
$this->secondaryEffectId = $secondaryEffectId;
|
||||
}
|
||||
|
||||
public function getPrimaryEffectId() : int{ return $this->primaryEffectId; }
|
||||
|
||||
public function getSecondaryEffectId() : int{ return $this->secondaryEffectId; }
|
||||
|
||||
public static function getTypeId() : int{ return ItemStackRequestActionType::BEACON_PAYMENT; }
|
||||
|
||||
public static function read(NetworkBinaryStream $in) : self{
|
||||
$primary = $in->getVarInt();
|
||||
$secondary = $in->getVarInt();
|
||||
return new self($primary, $secondary);
|
||||
}
|
||||
|
||||
public function write(NetworkBinaryStream $out) : void{
|
||||
$out->putVarInt($this->primaryEffectId);
|
||||
$out->putVarInt($this->secondaryEffectId);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
|
||||
|
||||
/**
|
||||
* Tells that the current transaction crafted the specified recipe, using the recipe book. This is effectively the same
|
||||
* as the regular crafting result action.
|
||||
*/
|
||||
final class CraftRecipeAutoStackRequestAction extends ItemStackRequestAction{
|
||||
use CraftRecipeStackRequestActionTrait;
|
||||
|
||||
public static function getTypeId() : int{ return ItemStackRequestActionType::CRAFTING_RECIPE_AUTO; }
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user