mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-10-19 23:37:45 +00:00
Merge branch 'next-major' into modern-world-support
This commit is contained in:
@@ -132,6 +132,7 @@ use function get_class;
|
||||
use function ini_set;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
use function is_object;
|
||||
use function is_resource;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
@@ -1617,7 +1618,7 @@ class Server{
|
||||
"reportPaste" => base64_encode($dump->getEncodedData())
|
||||
], 10, [], $postUrlError);
|
||||
|
||||
if($reply !== null && ($data = json_decode($reply->getBody())) !== null){
|
||||
if($reply !== null && is_object($data = json_decode($reply->getBody()))){
|
||||
if(isset($data->crashId) && isset($data->crashUrl)){
|
||||
$reportId = $data->crashId;
|
||||
$reportUrl = $data->crashUrl;
|
||||
|
@@ -82,6 +82,10 @@ class FlowerPot extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isValidPlant($block);
|
||||
}
|
||||
|
||||
private function isValidPlant(Block $block) : bool{
|
||||
return
|
||||
$block instanceof Cactus ||
|
||||
$block instanceof DeadBush ||
|
||||
@@ -115,8 +119,26 @@ class FlowerPot extends Flowable{
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$plant = $item->getBlock();
|
||||
if(!$this->canAddPlant($plant)){
|
||||
return false;
|
||||
if($this->plant !== null){
|
||||
if($this->isValidPlant($plant)){
|
||||
//for some reason, vanilla doesn't remove the contents of the pot if the held item is plantable
|
||||
//and will also cause a new plant to be placed if clicking on the side
|
||||
return false;
|
||||
}
|
||||
|
||||
$removedItems = [$this->plant->asItem()];
|
||||
if($player !== null){
|
||||
//this one just has to be a weirdo :(
|
||||
//this is the only block that directly adds items to the player inventory instead of just dropping items
|
||||
$removedItems = $player->getInventory()->addItem(...$removedItems);
|
||||
}
|
||||
foreach($removedItems as $drops){
|
||||
$this->position->getWorld()->dropItem($this->position->add(0.5, 0.5, 0.5), $drops);
|
||||
}
|
||||
|
||||
$this->setPlant(null);
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->setPlant($plant);
|
||||
|
@@ -37,6 +37,7 @@ use function implode;
|
||||
use function is_numeric;
|
||||
use function ksort;
|
||||
use function min;
|
||||
use function sort;
|
||||
use function strtolower;
|
||||
use const SORT_FLAG_CASE;
|
||||
use const SORT_NATURAL;
|
||||
@@ -105,7 +106,7 @@ class HelpCommand extends VanillaCommand{
|
||||
$lang = $sender->getLanguage();
|
||||
$description = $cmd->getDescription();
|
||||
$descriptionString = $description instanceof Translatable ? $lang->translate($description) : $description;
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_header($commandName)
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_header($cmd->getName())
|
||||
->format(TextFormat::YELLOW . "--------- " . TextFormat::WHITE, TextFormat::YELLOW . " ---------"));
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_description(TextFormat::WHITE . $descriptionString)
|
||||
->prefix(TextFormat::GOLD));
|
||||
@@ -115,6 +116,11 @@ class HelpCommand extends VanillaCommand{
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_usage(TextFormat::WHITE . implode("\n" . TextFormat::WHITE, explode("\n", $usageString)))
|
||||
->prefix(TextFormat::GOLD));
|
||||
|
||||
$aliases = $cmd->getAliases();
|
||||
sort($aliases, SORT_NATURAL);
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_aliases(TextFormat::WHITE . implode(", ", $aliases))
|
||||
->prefix(TextFormat::GOLD));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -768,17 +768,29 @@ abstract class Entity{
|
||||
}
|
||||
|
||||
protected function broadcastMovement(bool $teleport = false) : void{
|
||||
$this->server->broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
|
||||
$this->id,
|
||||
$this->getOffsetPosition($this->location),
|
||||
$this->location->pitch,
|
||||
$this->location->yaw,
|
||||
$this->location->yaw,
|
||||
(
|
||||
($teleport ? MoveActorAbsolutePacket::FLAG_TELEPORT : 0) |
|
||||
($this->onGround ? MoveActorAbsolutePacket::FLAG_GROUND : 0)
|
||||
)
|
||||
)]);
|
||||
if($teleport){
|
||||
//TODO: HACK! workaround for https://github.com/pmmp/PocketMine-MP/issues/4394
|
||||
//this happens because MoveActor*Packet doesn't clear interpolation targets on the client, so the entity
|
||||
//snaps to the teleport position, but then lerps back to the original position if a normal movement for the
|
||||
//entity was recently broadcasted. This can be seen with players throwing ender pearls.
|
||||
//TODO: remove this if the bug ever gets fixed (lol)
|
||||
foreach($this->hasSpawned as $player){
|
||||
$this->despawnFrom($player);
|
||||
$this->spawnTo($player);
|
||||
}
|
||||
}else{
|
||||
$this->server->broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
|
||||
$this->id,
|
||||
$this->getOffsetPosition($this->location),
|
||||
$this->location->pitch,
|
||||
$this->location->yaw,
|
||||
$this->location->yaw,
|
||||
(
|
||||
//TODO: if the above hack for #4394 gets removed, we should be setting FLAG_TELEPORT here
|
||||
($this->onGround ? MoveActorAbsolutePacket::FLAG_GROUND : 0)
|
||||
)
|
||||
)]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function broadcastMotion() : void{
|
||||
|
@@ -31,7 +31,7 @@ use function count;
|
||||
|
||||
/**
|
||||
* Called when a player connects to the server, prior to authentication taking place.
|
||||
* Cancelling this event will cause the player to be disconnected with the kick message set.
|
||||
* Set a kick reason to cancel the event and disconnect the player with the kick message set.
|
||||
*
|
||||
* This event should be used to decide if the player may continue to login to the server. Do things like checking
|
||||
* bans, whitelisting, server-full etc here.
|
||||
|
@@ -1197,6 +1197,12 @@ final class KnownTranslationFactory{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_HELP_DESCRIPTION, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_command_help_specificCommand_aliases(Translatable|string $aliasList) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_ALIASES, [
|
||||
"aliasList" => $aliasList,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function pocketmine_command_help_specificCommand_description(Translatable|string $description) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_DESCRIPTION, [
|
||||
"description" => $description,
|
||||
@@ -1829,6 +1835,10 @@ final class KnownTranslationFactory{
|
||||
]);
|
||||
}
|
||||
|
||||
public static function pocketmine_plugin_mainClassAbstract() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_MAINCLASSABSTRACT, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_plugin_mainClassNotFound() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_MAINCLASSNOTFOUND, []);
|
||||
}
|
||||
|
@@ -262,6 +262,7 @@ final class KnownTranslationKeys{
|
||||
public const POCKETMINE_COMMAND_GIVE_DESCRIPTION = "pocketmine.command.give.description";
|
||||
public const POCKETMINE_COMMAND_GIVE_USAGE = "pocketmine.command.give.usage";
|
||||
public const POCKETMINE_COMMAND_HELP_DESCRIPTION = "pocketmine.command.help.description";
|
||||
public const POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_ALIASES = "pocketmine.command.help.specificCommand.aliases";
|
||||
public const POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_DESCRIPTION = "pocketmine.command.help.specificCommand.description";
|
||||
public const POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_HEADER = "pocketmine.command.help.specificCommand.header";
|
||||
public const POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_USAGE = "pocketmine.command.help.specificCommand.usage";
|
||||
@@ -379,6 +380,7 @@ final class KnownTranslationKeys{
|
||||
public const POCKETMINE_PLUGIN_INVALIDMANIFEST = "pocketmine.plugin.invalidManifest";
|
||||
public const POCKETMINE_PLUGIN_LOAD = "pocketmine.plugin.load";
|
||||
public const POCKETMINE_PLUGIN_LOADERROR = "pocketmine.plugin.loadError";
|
||||
public const POCKETMINE_PLUGIN_MAINCLASSABSTRACT = "pocketmine.plugin.mainClassAbstract";
|
||||
public const POCKETMINE_PLUGIN_MAINCLASSNOTFOUND = "pocketmine.plugin.mainClassNotFound";
|
||||
public const POCKETMINE_PLUGIN_MAINCLASSWRONGTYPE = "pocketmine.plugin.mainClassWrongType";
|
||||
public const POCKETMINE_PLUGIN_RESTRICTEDNAME = "pocketmine.plugin.restrictedName";
|
||||
|
@@ -125,6 +125,7 @@ use function get_class;
|
||||
use function in_array;
|
||||
use function json_encode;
|
||||
use function ksort;
|
||||
use function strcasecmp;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
@@ -635,7 +636,7 @@ class NetworkSession{
|
||||
continue;
|
||||
}
|
||||
$info = $existingSession->getPlayerInfo();
|
||||
if($info !== null && ($info->getUsername() === $this->info->getUsername() || $info->getUuid()->equals($this->info->getUuid()))){
|
||||
if($info !== null && (strcasecmp($info->getUsername(), $this->info->getUsername()) === 0 || $info->getUuid()->equals($this->info->getUuid()))){
|
||||
if($kickForXUIDMismatch($info instanceof XboxLivePlayerInfo ? $info->getXuid() : "")){
|
||||
return;
|
||||
}
|
||||
|
@@ -228,8 +228,10 @@ class InGamePacketHandler extends PacketHandler{
|
||||
$this->player->jump();
|
||||
}
|
||||
|
||||
//TODO: this packet has WAYYYYY more useful information that we're not using
|
||||
$this->player->handleMovement($newPos);
|
||||
if(!$this->forceMoveSync){
|
||||
//TODO: this packet has WAYYYYY more useful information that we're not using
|
||||
$this->player->handleMovement($newPos);
|
||||
}
|
||||
|
||||
$packetHandled = true;
|
||||
|
||||
@@ -457,13 +459,10 @@ class InGamePacketHandler extends PacketHandler{
|
||||
if(!$this->player->consumeHeldItem()){
|
||||
$hungerAttr = $this->player->getAttributeMap()->get(Attribute::HUNGER) ?? throw new AssumptionFailedError();
|
||||
$hungerAttr->markSynchronized(false);
|
||||
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(!$this->player->useHeldItem()){
|
||||
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
|
||||
}
|
||||
$this->player->useHeldItem();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -483,7 +482,6 @@ class InGamePacketHandler extends PacketHandler{
|
||||
* Internal function used to execute rollbacks when an action fails on a block.
|
||||
*/
|
||||
private function onFailedBlockAction(Vector3 $blockPos, ?int $face) : void{
|
||||
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
|
||||
if($blockPos->distanceSquared($this->player->getLocation()) < 10000){
|
||||
$blocks = $blockPos->sidesArray();
|
||||
if($face !== null){
|
||||
@@ -512,14 +510,10 @@ class InGamePacketHandler extends PacketHandler{
|
||||
//TODO: use transactiondata for rollbacks here
|
||||
switch($data->getActionType()){
|
||||
case UseItemOnEntityTransactionData::ACTION_INTERACT:
|
||||
if(!$this->player->interactEntity($target, $data->getClickPosition())){
|
||||
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
|
||||
}
|
||||
$this->player->interactEntity($target, $data->getClickPosition());
|
||||
return true;
|
||||
case UseItemOnEntityTransactionData::ACTION_ATTACK:
|
||||
if(!$this->player->attackEntity($target)){
|
||||
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
|
||||
}
|
||||
$this->player->attackEntity($target);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -166,6 +166,14 @@ class PluginManager{
|
||||
)));
|
||||
return null;
|
||||
}
|
||||
$reflect = new \ReflectionClass($mainClass); //this shouldn't throw; we already checked that it exists
|
||||
if(!$reflect->isInstantiable()){
|
||||
$this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
|
||||
$description->getName(),
|
||||
KnownTranslationFactory::pocketmine_plugin_mainClassAbstract()
|
||||
)));
|
||||
return null;
|
||||
}
|
||||
|
||||
$permManager = PermissionManager::getInstance();
|
||||
foreach($description->getPermissions() as $permsGroup){
|
||||
@@ -463,8 +471,12 @@ class PluginManager{
|
||||
}
|
||||
|
||||
public function tickSchedulers(int $currentTick) : void{
|
||||
foreach($this->enabledPlugins as $p){
|
||||
$p->getScheduler()->mainThreadHeartbeat($currentTick);
|
||||
foreach($this->enabledPlugins as $pluginName => $p){
|
||||
if(isset($this->enabledPlugins[$pluginName])){
|
||||
//the plugin may have been disabled as a result of updating other plugins' schedulers, and therefore
|
||||
//removed from enabledPlugins; however, foreach will still see it due to copy-on-write
|
||||
$p->getScheduler()->mainThreadHeartbeat($currentTick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -64,6 +64,13 @@ class ZippedResourcePack implements ResourcePack{
|
||||
if(!file_exists($zipPath)){
|
||||
throw new ResourcePackException("File not found");
|
||||
}
|
||||
$size = filesize($zipPath);
|
||||
if($size === false){
|
||||
throw new ResourcePackException("Unable to determine size of file");
|
||||
}
|
||||
if($size === 0){
|
||||
throw new ResourcePackException("Empty file, probably corrupted");
|
||||
}
|
||||
|
||||
$archive = new \ZipArchive();
|
||||
if(($openResult = $archive->open($zipPath)) !== true){
|
||||
|
Reference in New Issue
Block a user