mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-20 02:14:01 +00:00
Merge branch 'stable' into next-minor
This commit is contained in:
commit
16ed16722a
8
.github/workflows/build-docker-image.yml
vendored
8
.github/workflows/build-docker-image.yml
vendored
@ -46,7 +46,7 @@ jobs:
|
|||||||
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
|
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
|
||||||
|
|
||||||
- name: Build image for tag
|
- name: Build image for tag
|
||||||
uses: docker/build-push-action@v3.0.0
|
uses: docker/build-push-action@v3.1.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
context: ./pocketmine-mp
|
context: ./pocketmine-mp
|
||||||
@ -59,7 +59,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build image for major tag
|
- name: Build image for major tag
|
||||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||||
uses: docker/build-push-action@v3.0.0
|
uses: docker/build-push-action@v3.1.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
context: ./pocketmine-mp
|
context: ./pocketmine-mp
|
||||||
@ -72,7 +72,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build image for minor tag
|
- name: Build image for minor tag
|
||||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||||
uses: docker/build-push-action@v3.0.0
|
uses: docker/build-push-action@v3.1.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
context: ./pocketmine-mp
|
context: ./pocketmine-mp
|
||||||
@ -85,7 +85,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build image for latest tag
|
- name: Build image for latest tag
|
||||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||||
uses: docker/build-push-action@v3.0.0
|
uses: docker/build-push-action@v3.1.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
context: ./pocketmine-mp
|
context: ./pocketmine-mp
|
||||||
|
2
.github/workflows/draft-release.yml
vendored
2
.github/workflows/draft-release.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@2.20.0
|
uses: shivammathur/setup-php@2.21.0
|
||||||
with:
|
with:
|
||||||
php-version: 8.0
|
php-version: 8.0
|
||||||
|
|
||||||
|
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -195,7 +195,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup PHP and tools
|
- name: Setup PHP and tools
|
||||||
uses: shivammathur/setup-php@2.20.0
|
uses: shivammathur/setup-php@2.21.0
|
||||||
with:
|
with:
|
||||||
php-version: 8.0
|
php-version: 8.0
|
||||||
tools: php-cs-fixer:3.2
|
tools: php-cs-fixer:3.2
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 11103498ca761be83598f9759cc7196c167fcb7e
|
Subproject commit f292501a703352ab793b07b7861f3e1b3860ed86
|
@ -12,3 +12,20 @@ Released 13th July 2022.
|
|||||||
## General
|
## General
|
||||||
- Added support for Minecraft: Bedrock Edition 1.19.10.
|
- Added support for Minecraft: Bedrock Edition 1.19.10.
|
||||||
- Removed support for older versions.
|
- Removed support for older versions.
|
||||||
|
|
||||||
|
# 4.6.1
|
||||||
|
Released 22nd July 2022.
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
- `build/generate-registry-annotations.php` now supports processing single files (useful for PhpStorm file watchers).
|
||||||
|
|
||||||
|
## API
|
||||||
|
- Updated documentation for `AsyncTask`.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
- Fixed incorrect items being displayed in item frames.
|
||||||
|
- Fixed books not showing in lecterns.
|
||||||
|
- Fixed incorrect damage interval of Wither status effect.
|
||||||
|
- Fixed incorrect fire ticks when being set on fire by lava (8 seconds in Bedrock instead of 15).
|
||||||
|
- `Entity->attack()` now cancels damage from `FIRE` and `FIRE_TICK` damage causes if the entity is fireproof.
|
||||||
|
- Fixed inventory windows getting force-closed when the client attempts to use an enchanting table or anvil.
|
||||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
|||||||
|
|
||||||
final class VersionInfo{
|
final class VersionInfo{
|
||||||
public const NAME = "PocketMine-MP";
|
public const NAME = "PocketMine-MP";
|
||||||
public const BASE_VERSION = "4.6.1";
|
public const BASE_VERSION = "4.6.2";
|
||||||
public const IS_DEVELOPMENT_BUILD = true;
|
public const IS_DEVELOPMENT_BUILD = true;
|
||||||
public const BUILD_CHANNEL = "beta";
|
public const BUILD_CHANNEL = "beta";
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ use pocketmine\network\mcpe\convert\TypeConverter;
|
|||||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||||
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
|
||||||
use pocketmine\network\mcpe\protocol\types\DeviceOS;
|
use pocketmine\network\mcpe\protocol\types\DeviceOS;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||||
@ -57,12 +58,15 @@ use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
|
|||||||
use pocketmine\network\mcpe\protocol\types\GameMode;
|
use pocketmine\network\mcpe\protocol\types\GameMode;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\UpdateAbilitiesPacketLayer;
|
||||||
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
||||||
use pocketmine\player\Player;
|
use pocketmine\player\Player;
|
||||||
use pocketmine\utils\Limits;
|
use pocketmine\utils\Limits;
|
||||||
use pocketmine\world\sound\TotemUseSound;
|
use pocketmine\world\sound\TotemUseSound;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use Ramsey\Uuid\UuidInterface;
|
use Ramsey\Uuid\UuidInterface;
|
||||||
|
use function array_fill;
|
||||||
use function array_filter;
|
use function array_filter;
|
||||||
use function array_key_exists;
|
use function array_key_exists;
|
||||||
use function array_merge;
|
use function array_merge;
|
||||||
@ -481,7 +485,14 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
|||||||
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())),
|
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())),
|
||||||
GameMode::SURVIVAL,
|
GameMode::SURVIVAL,
|
||||||
$this->getAllNetworkData(),
|
$this->getAllNetworkData(),
|
||||||
UpdateAbilitiesPacket::create(0, 0, $this->getId() /* TODO: this should be unique ID */, []),
|
UpdateAbilitiesPacket::create(CommandPermissions::NORMAL, PlayerPermissions::VISITOR, $this->getId() /* TODO: this should be unique ID */, [
|
||||||
|
new UpdateAbilitiesPacketLayer(
|
||||||
|
UpdateAbilitiesPacketLayer::LAYER_BASE,
|
||||||
|
array_fill(0, UpdateAbilitiesPacketLayer::NUMBER_OF_ABILITIES, false),
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
)
|
||||||
|
]),
|
||||||
[], //TODO: entity links
|
[], //TODO: entity links
|
||||||
"", //device ID (we intentionally don't send this - secvuln)
|
"", //device ID (we intentionally don't send this - secvuln)
|
||||||
DeviceOS::UNKNOWN //we intentionally don't send this (secvuln)
|
DeviceOS::UNKNOWN //we intentionally don't send this (secvuln)
|
||||||
|
@ -145,6 +145,11 @@ class InGamePacketHandler extends PacketHandler{
|
|||||||
/** @var UseItemTransactionData|null */
|
/** @var UseItemTransactionData|null */
|
||||||
protected $lastRightClickData = null;
|
protected $lastRightClickData = null;
|
||||||
|
|
||||||
|
protected ?Vector3 $lastPlayerAuthInputPosition = null;
|
||||||
|
protected ?float $lastPlayerAuthInputYaw = null;
|
||||||
|
protected ?float $lastPlayerAuthInputPitch = null;
|
||||||
|
protected ?int $lastPlayerAuthInputFlags = null;
|
||||||
|
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
public $forceMoveSync = false;
|
public $forceMoveSync = false;
|
||||||
|
|
||||||
@ -168,9 +173,10 @@ class InGamePacketHandler extends PacketHandler{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resolveOnOffInputFlags(PlayerAuthInputPacket $packet, int $startFlag, int $stopFlag) : ?bool{
|
private function resolveOnOffInputFlags(int $inputFlags, int $startFlag, int $stopFlag) : ?bool{
|
||||||
$enabled = $packet->hasFlag($startFlag);
|
$enabled = ($inputFlags & (1 << $startFlag)) !== 0;
|
||||||
if($enabled !== $packet->hasFlag($stopFlag)){
|
$disabled = ($inputFlags & (1 << $stopFlag)) !== 0;
|
||||||
|
if($enabled !== $disabled){
|
||||||
return $enabled;
|
return $enabled;
|
||||||
}
|
}
|
||||||
//neither flag was set, or both were set
|
//neither flag was set, or both were set
|
||||||
@ -179,51 +185,68 @@ class InGamePacketHandler extends PacketHandler{
|
|||||||
|
|
||||||
public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
|
public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
|
||||||
$rawPos = $packet->getPosition();
|
$rawPos = $packet->getPosition();
|
||||||
foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->getYaw(), $packet->getHeadYaw(), $packet->getPitch()] as $float){
|
$rawYaw = $packet->getYaw();
|
||||||
|
$rawPitch = $packet->getPitch();
|
||||||
|
foreach([$rawPos->x, $rawPos->y, $rawPos->z, $rawYaw, $packet->getHeadYaw(), $rawPitch] as $float){
|
||||||
if(is_infinite($float) || is_nan($float)){
|
if(is_infinite($float) || is_nan($float)){
|
||||||
$this->session->getLogger()->debug("Invalid movement received, contains NAN/INF components");
|
$this->session->getLogger()->debug("Invalid movement received, contains NAN/INF components");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$yaw = fmod($packet->getYaw(), 360);
|
if($rawYaw !== $this->lastPlayerAuthInputYaw || $rawPitch !== $this->lastPlayerAuthInputPitch){
|
||||||
$pitch = fmod($packet->getPitch(), 360);
|
$this->lastPlayerAuthInputYaw = $rawYaw;
|
||||||
if($yaw < 0){
|
$this->lastPlayerAuthInputPitch = $rawPitch;
|
||||||
$yaw += 360;
|
|
||||||
|
$yaw = fmod($rawYaw, 360);
|
||||||
|
$pitch = fmod($rawPitch, 360);
|
||||||
|
if($yaw < 0){
|
||||||
|
$yaw += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->player->setRotation($yaw, $pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->player->setRotation($yaw, $pitch);
|
$hasMoved = $this->lastPlayerAuthInputPosition === null || !$this->lastPlayerAuthInputPosition->equals($rawPos);
|
||||||
|
|
||||||
$curPos = $this->player->getLocation();
|
|
||||||
$newPos = $rawPos->round(4)->subtract(0, 1.62, 0);
|
$newPos = $rawPos->round(4)->subtract(0, 1.62, 0);
|
||||||
|
|
||||||
if($this->forceMoveSync && $newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
|
if($this->forceMoveSync && $hasMoved){
|
||||||
$this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos);
|
$curPos = $this->player->getLocation();
|
||||||
//Still getting movements from before teleport, ignore them
|
|
||||||
return false;
|
if($newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
|
||||||
|
$this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos);
|
||||||
|
//Still getting movements from before teleport, ignore them
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock
|
||||||
|
$this->forceMoveSync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock
|
$inputFlags = $packet->getInputFlags();
|
||||||
$this->forceMoveSync = false;
|
if($inputFlags !== $this->lastPlayerAuthInputFlags){
|
||||||
|
$this->lastPlayerAuthInputFlags = $inputFlags;
|
||||||
|
|
||||||
$sneaking = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING);
|
$sneaking = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING);
|
||||||
$sprinting = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING);
|
$sprinting = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING);
|
||||||
$swimming = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING);
|
$swimming = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING);
|
||||||
$gliding = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING);
|
$gliding = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING);
|
||||||
$mismatch =
|
$mismatch =
|
||||||
($sneaking !== null && !$this->player->toggleSneak($sneaking)) |
|
($sneaking !== null && !$this->player->toggleSneak($sneaking)) |
|
||||||
($sprinting !== null && !$this->player->toggleSprint($sprinting)) |
|
($sprinting !== null && !$this->player->toggleSprint($sprinting)) |
|
||||||
($swimming !== null && !$this->player->toggleSwim($swimming)) |
|
($swimming !== null && !$this->player->toggleSwim($swimming)) |
|
||||||
($gliding !== null && !$this->player->toggleGlide($gliding));
|
($gliding !== null && !$this->player->toggleGlide($gliding));
|
||||||
if((bool) $mismatch){
|
if((bool) $mismatch){
|
||||||
$this->player->sendData([$this->player]);
|
$this->player->sendData([$this->player]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){
|
||||||
|
$this->player->jump();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){
|
if(!$this->forceMoveSync && $hasMoved){
|
||||||
$this->player->jump();
|
$this->lastPlayerAuthInputPosition = $rawPos;
|
||||||
}
|
|
||||||
|
|
||||||
if(!$this->forceMoveSync){
|
|
||||||
//TODO: this packet has WAYYYYY more useful information that we're not using
|
//TODO: this packet has WAYYYYY more useful information that we're not using
|
||||||
$this->player->handleMovement($newPos);
|
$this->player->handleMovement($newPos);
|
||||||
}
|
}
|
||||||
|
@ -1180,7 +1180,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$oldPos = $this->getLocation();
|
$oldPos = $this->location;
|
||||||
$distanceSquared = $newPos->distanceSquared($oldPos);
|
$distanceSquared = $newPos->distanceSquared($oldPos);
|
||||||
|
|
||||||
$revert = false;
|
$revert = false;
|
||||||
@ -1198,7 +1198,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
* asking for help if you suffer the consequences of messing with this.
|
* asking for help if you suffer the consequences of messing with this.
|
||||||
*/
|
*/
|
||||||
$this->logger->debug("Moved too fast, reverting movement");
|
$this->logger->debug("Moved too fast, reverting movement");
|
||||||
$this->logger->debug("Old position: " . $this->location->asVector3() . ", new position: " . $newPos);
|
$this->logger->debug("Old position: " . $oldPos->asVector3() . ", new position: " . $newPos);
|
||||||
$revert = true;
|
$revert = true;
|
||||||
}elseif(!$this->getWorld()->isInLoadedTerrain($newPos)){
|
}elseif(!$this->getWorld()->isInLoadedTerrain($newPos)){
|
||||||
$revert = true;
|
$revert = true;
|
||||||
@ -1206,9 +1206,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!$revert && $distanceSquared != 0){
|
if(!$revert && $distanceSquared != 0){
|
||||||
$dx = $newPos->x - $this->location->x;
|
$dx = $newPos->x - $oldPos->x;
|
||||||
$dy = $newPos->y - $this->location->y;
|
$dy = $newPos->y - $oldPos->y;
|
||||||
$dz = $newPos->z - $this->location->z;
|
$dz = $newPos->z - $oldPos->z;
|
||||||
|
|
||||||
$this->move($dx, $dy, $dz);
|
$this->move($dx, $dy, $dz);
|
||||||
}
|
}
|
||||||
|
@ -33,19 +33,31 @@ use function spl_object_id;
|
|||||||
/**
|
/**
|
||||||
* Class used to run async tasks in other threads.
|
* Class used to run async tasks in other threads.
|
||||||
*
|
*
|
||||||
* An AsyncTask does not have its own thread. It is queued into an AsyncPool and executed if there is an async worker
|
* An AsyncTask is run by a thread pool of reusable threads, and doesn't have its own dedicated thread. A thread is
|
||||||
* with no AsyncTask running. Therefore, an AsyncTask SHOULD NOT execute for more than a few seconds. For tasks that
|
* usually chosen from the pool at random to run the task (though a specific thread in the pool may be selected
|
||||||
* run for a long time or infinitely, start another thread instead.
|
* manually, if needed).
|
||||||
|
* Reusing threads this way has a much lower performance cost than starting an entirely new thread for every operation.
|
||||||
|
* AsyncTasks are therefore suitable for brief CPU-bound tasks, such as world generation, compression/decompression of
|
||||||
|
* data, etc.
|
||||||
|
*
|
||||||
|
* AsyncTask SHOULD NOT be used for I/O-bound tasks, such as network I/O, file I/O, database I/O, etc. The server's
|
||||||
|
* central AsyncPool is used for things like compressing network packets for sending, so using AsyncTask for I/O will
|
||||||
|
* slow the whole server down, stall chunk loading, etc.
|
||||||
|
*
|
||||||
|
* An AsyncTask SHOULD NOT run for more than a few seconds. For tasks that run for a long time or indefinitely, create
|
||||||
|
* a dedicated thread instead.
|
||||||
|
*
|
||||||
|
* The Server instance is not accessible inside {@link AsyncTask::onRun()}. It can only be accessed in the main server
|
||||||
|
* thread, e.g. during {@link AsyncTask::onCompletion()} or {@link AsyncTask::onProgressUpdate()}. This means that
|
||||||
|
* whatever you do in onRun() must be able to work without the Server instance.
|
||||||
*
|
*
|
||||||
* WARNING: Any non-Threaded objects WILL BE SERIALIZED when assigned to members of AsyncTasks or other Threaded object.
|
* WARNING: Any non-Threaded objects WILL BE SERIALIZED when assigned to members of AsyncTasks or other Threaded object.
|
||||||
* If later accessed from said Threaded object, you will be operating on a COPY OF THE OBJECT, NOT THE ORIGINAL OBJECT.
|
* If later accessed from said Threaded object, you will be operating on a COPY OF THE OBJECT, NOT THE ORIGINAL OBJECT.
|
||||||
* If you want to store non-serializable objects to access when the task completes, store them using
|
* If you want to store non-serializable objects to access when the task completes, store them using
|
||||||
* {@link AsyncTask::storeLocal}.
|
* {@link AsyncTask::storeLocal}.
|
||||||
*
|
*
|
||||||
* WARNING: As of pthreads v3.1.6, arrays are converted to Volatile objects when assigned as members of Threaded objects.
|
* WARNING: Arrays are converted to Volatile objects when assigned as members of Threaded objects.
|
||||||
* Keep this in mind when using arrays stored as members of your AsyncTask.
|
* Keep this in mind when using arrays stored as members of your AsyncTask.
|
||||||
*
|
|
||||||
* WARNING: Do not call PocketMine-MP API methods from other Threads!!
|
|
||||||
*/
|
*/
|
||||||
abstract class AsyncTask extends \Threaded{
|
abstract class AsyncTask extends \Threaded{
|
||||||
/**
|
/**
|
||||||
|
@ -23,25 +23,20 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\world\particle;
|
namespace pocketmine\world\particle;
|
||||||
|
|
||||||
|
use pocketmine\block\VanillaBlocks;
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\entity\Skin;
|
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
use pocketmine\network\mcpe\protocol\AddActorPacket;
|
||||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
|
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
|
||||||
use pocketmine\network\mcpe\protocol\types\DeviceOS;
|
use pocketmine\network\mcpe\protocol\types\entity\ByteMetadataProperty;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty;
|
use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\entity\IntMetadataProperty;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\LongMetadataProperty;
|
use pocketmine\network\mcpe\protocol\types\entity\LongMetadataProperty;
|
||||||
use pocketmine\network\mcpe\protocol\types\GameMode;
|
use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
|
||||||
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
|
||||||
use Ramsey\Uuid\Uuid;
|
|
||||||
use function str_repeat;
|
|
||||||
|
|
||||||
class FloatingTextParticle implements Particle{
|
class FloatingTextParticle implements Particle{
|
||||||
//TODO: HACK!
|
//TODO: HACK!
|
||||||
@ -94,38 +89,34 @@ class FloatingTextParticle implements Particle{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!$this->invisible){
|
if(!$this->invisible){
|
||||||
$uuid = Uuid::uuid4();
|
|
||||||
$name = $this->title . ($this->text !== "" ? "\n" . $this->text : "");
|
$name = $this->title . ($this->text !== "" ? "\n" . $this->text : "");
|
||||||
|
|
||||||
$p[] = PlayerListPacket::add([PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, SkinAdapterSingleton::get()->toSkinData(new Skin("Standard_Custom", str_repeat("\x00", 8192))))]);
|
|
||||||
|
|
||||||
$actorFlags = (
|
$actorFlags = (
|
||||||
1 << EntityMetadataFlags::IMMOBILE
|
1 << EntityMetadataFlags::IMMOBILE
|
||||||
);
|
);
|
||||||
$actorMetadata = [
|
$actorMetadata = [
|
||||||
EntityMetadataProperties::FLAGS => new LongMetadataProperty($actorFlags),
|
EntityMetadataProperties::FLAGS => new LongMetadataProperty($actorFlags),
|
||||||
EntityMetadataProperties::SCALE => new FloatMetadataProperty(0.01) //zero causes problems on debug builds
|
EntityMetadataProperties::SCALE => new FloatMetadataProperty(0.01), //zero causes problems on debug builds
|
||||||
|
EntityMetadataProperties::BOUNDING_BOX_WIDTH => new FloatMetadataProperty(0.0),
|
||||||
|
EntityMetadataProperties::BOUNDING_BOX_HEIGHT => new FloatMetadataProperty(0.0),
|
||||||
|
EntityMetadataProperties::NAMETAG => new StringMetadataProperty($name),
|
||||||
|
EntityMetadataProperties::VARIANT => new IntMetadataProperty(RuntimeBlockMapping::getInstance()->toRuntimeId(VanillaBlocks::AIR()->getFullId())),
|
||||||
|
EntityMetadataProperties::ALWAYS_SHOW_NAMETAG => new ByteMetadataProperty(1),
|
||||||
];
|
];
|
||||||
$p[] = AddPlayerPacket::create(
|
$p[] = AddActorPacket::create(
|
||||||
$uuid,
|
|
||||||
$name,
|
|
||||||
$this->entityId, //TODO: actor unique ID
|
$this->entityId, //TODO: actor unique ID
|
||||||
"",
|
$this->entityId,
|
||||||
$pos, //TODO: check offset
|
EntityIds::FALLING_BLOCK,
|
||||||
|
$pos, //TODO: check offset (0.49?)
|
||||||
null,
|
null,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
ItemStackWrapper::legacy(ItemStack::null()),
|
0,
|
||||||
GameMode::SURVIVAL,
|
|
||||||
$actorMetadata,
|
|
||||||
UpdateAbilitiesPacket::create(0, 0, $this->entityId, []),
|
|
||||||
[],
|
[],
|
||||||
"",
|
$actorMetadata,
|
||||||
DeviceOS::UNKNOWN
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
$p[] = PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($uuid)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $p;
|
return $p;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user