mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-15 07:55:31 +00:00
First look at #5512: gameplay permissions
This commit is contained in:
parent
edb8f19a0c
commit
10a962daa2
@ -38,6 +38,7 @@ use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
use function max;
|
||||
|
||||
@ -311,7 +312,7 @@ class ItemEntity extends Entity{
|
||||
};
|
||||
|
||||
$ev = new EntityItemPickupEvent($player, $this, $item, $playerInventory);
|
||||
if($player->hasFiniteResources() && $playerInventory === null){
|
||||
if(($player->hasFiniteResources() && $playerInventory === null) || !$player->hasPermission(DefaultPermissionNames::GAME_ITEM_PICKUP)){
|
||||
$ev->cancel();
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\ArrowHitSound;
|
||||
use function ceil;
|
||||
@ -184,7 +185,7 @@ class Arrow extends Projectile{
|
||||
};
|
||||
|
||||
$ev = new EntityItemPickupEvent($player, $this, $item, $playerInventory);
|
||||
if($player->hasFiniteResources() && $playerInventory === null){
|
||||
if(($player->hasFiniteResources() && $playerInventory === null) || !$player->hasPermission(DefaultPermissionNames::GAME_ITEM_PICKUP)){
|
||||
$ev->cancel();
|
||||
}
|
||||
if($this->pickupMode === self::PICKUP_NONE || ($this->pickupMode === self::PICKUP_CREATIVE && !$player->isCreative())){
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\inventory\CreativeInventory;
|
||||
use pocketmine\inventory\transaction\TransactionValidationException;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
/**
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\event\player\PlayerDropItemEvent;
|
||||
use pocketmine\inventory\transaction\TransactionValidationException;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
/**
|
||||
@ -49,7 +50,7 @@ class DropItemAction extends InventoryAction{
|
||||
|
||||
public function onPreExecute(Player $source) : bool{
|
||||
$ev = new PlayerDropItemEvent($source, $this->targetItem);
|
||||
if($source->isSpectator()){
|
||||
if(!$source->hasPermission(DefaultPermissionNames::GAME_ITEM_DROP)){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
|
@ -854,16 +854,16 @@ class NetworkSession{
|
||||
UpdateAbilitiesPacketLayer::ABILITY_OPERATOR => $isOp,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_TELEPORT => $for->hasPermission(DefaultPermissionNames::COMMAND_TELEPORT_SELF),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_INVULNERABLE => $for->isCreative(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_MUTED => false,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_MUTED => !$for->hasPermission(DefaultPermissionNames::GAME_CHAT),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_WORLD_BUILDER => false,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_INFINITE_RESOURCES => !$for->hasFiniteResources(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_LIGHTNING => false,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_BUILD => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_MINE => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_DOORS_AND_SWITCHES => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_OPEN_CONTAINERS => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ATTACK_PLAYERS => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ATTACK_MOBS => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_BUILD => $for->hasPermission(DefaultPermissionNames::GAME_BLOCK_PLACE),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_MINE => $for->hasPermission(DefaultPermissionNames::GAME_BLOCK_BREAK),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_DOORS_AND_SWITCHES => $for->hasPermission(DefaultPermissionNames::GAME_BLOCK_INTERACT),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_OPEN_CONTAINERS => $for->hasPermission(DefaultPermissionNames::GAME_BLOCK_INTERACT) || $for->hasPermission(DefaultPermissionNames::GAME_ENTITY_INTERACT), //not perfect, but this is a pain to implement right now
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ATTACK_PLAYERS => $for->hasPermission(DefaultPermissionNames::GAME_PLAYER_ATTACK),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ATTACK_MOBS => $for->hasPermission(DefaultPermissionNames::GAME_ENTITY_ATTACK),
|
||||
];
|
||||
|
||||
$this->sendDataPacket(UpdateAbilitiesPacket::create(
|
||||
|
@ -91,7 +91,24 @@ final class DefaultPermissionNames{
|
||||
public const COMMAND_WHITELIST_LIST = "pocketmine.command.whitelist.list";
|
||||
public const COMMAND_WHITELIST_RELOAD = "pocketmine.command.whitelist.reload";
|
||||
public const COMMAND_WHITELIST_REMOVE = "pocketmine.command.whitelist.remove";
|
||||
public const GAME_BLOCK_BREAK = "pocketmine.game.block.break";
|
||||
public const GAME_BLOCK_INTERACT = "pocketmine.game.block.interact";
|
||||
public const GAME_BLOCK_PLACE = "pocketmine.game.block.place";
|
||||
public const GAME_CHAT = "pocketmine.game.chat";
|
||||
public const GAME_ENTITY_ATTACK = "pocketmine.game.entity.attack";
|
||||
public const GAME_ENTITY_INTERACT = "pocketmine.game.entity.interact";
|
||||
public const GAME_FLIGHT = "pocketmine.game.flight";
|
||||
public const GAME_ITEM_CREATE = "pocketmine.game.item.create";
|
||||
public const GAME_ITEM_DROP = "pocketmine.game.item.drop";
|
||||
public const GAME_ITEM_PICKUP = "pocketmine.game.item.pickup";
|
||||
public const GAME_ITEM_USE = "pocketmine.game.item.use";
|
||||
public const GAME_PLAYER_ATTACK = "pocketmine.game.player.attack";
|
||||
public const GAME_PLAYER_INTERACT = "pocketmine.game.player.interact";
|
||||
public const GROUP_CONSOLE = "pocketmine.group.console";
|
||||
public const GROUP_GAMEMODE_ADVENTURE = "pocketmine.group.gamemode.adventure";
|
||||
public const GROUP_GAMEMODE_CREATIVE = "pocketmine.group.gamemode.creative";
|
||||
public const GROUP_GAMEMODE_SPECTATOR = "pocketmine.group.gamemode.spectator";
|
||||
public const GROUP_GAMEMODE_SURVIVAL = "pocketmine.group.gamemode.survival";
|
||||
public const GROUP_OPERATOR = "pocketmine.group.operator";
|
||||
public const GROUP_USER = "pocketmine.group.user";
|
||||
}
|
||||
|
@ -136,5 +136,26 @@ abstract class DefaultPermissions{
|
||||
self::registerPermission(new Permission(Names::COMMAND_WHITELIST_LIST, "Allows the user to list all players on the server whitelist"), [$operatorRoot]);
|
||||
self::registerPermission(new Permission(Names::COMMAND_WHITELIST_RELOAD, "Allows the user to reload the server whitelist"), [$operatorRoot]);
|
||||
self::registerPermission(new Permission(Names::COMMAND_WHITELIST_REMOVE, "Allows the user to remove a player from the server whitelist"), [$operatorRoot]);
|
||||
|
||||
self::registerPermission(new Permission(Names::GAME_CHAT, "Allows the user to chat"), [$everyoneRoot]);
|
||||
|
||||
$survivalRoot = self::registerPermission(new Permission(Names::GROUP_GAMEMODE_SURVIVAL));
|
||||
$creativeRoot = self::registerPermission(new Permission(Names::GROUP_GAMEMODE_CREATIVE));
|
||||
$adventureRoot = self::registerPermission(new Permission(Names::GROUP_GAMEMODE_ADVENTURE));
|
||||
self::registerPermission(new Permission(Names::GROUP_GAMEMODE_SPECTATOR)); //not currently used, but will be in the future
|
||||
|
||||
self::registerPermission(new Permission(Names::GAME_BLOCK_BREAK, "Allows the user to break blocks"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_BLOCK_INTERACT, "Allows the user to interact with blocks"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_BLOCK_PLACE, "Allows the user to place blocks"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_ENTITY_ATTACK, "Allows the user to attack entities"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_ENTITY_INTERACT, "Allows the user to interact with entities"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_ITEM_DROP, "Allows the user to drop items"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_ITEM_PICKUP, "Allows the user to pick up items"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_ITEM_USE, "Allows the user to use items such as snowballs"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_PLAYER_ATTACK, "Allows the user to attack other players"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_PLAYER_INTERACT, "Allows the user to interact with other players"), [$survivalRoot, $creativeRoot, $adventureRoot]);
|
||||
|
||||
self::registerPermission(new Permission(Names::GAME_ITEM_CREATE, "Allows the user to use the creative inventory"), [$creativeRoot]);
|
||||
self::registerPermission(new Permission(Names::GAME_FLIGHT, "Allows the user to toggle flight mode"), [$creativeRoot]);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\player;
|
||||
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\lang\Translatable;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\utils\EnumTrait;
|
||||
use function mb_strtolower;
|
||||
|
||||
@ -50,10 +51,10 @@ final class GameMode{
|
||||
|
||||
protected static function setup() : void{
|
||||
self::registerAll(
|
||||
new self("survival", "Survival", KnownTranslationFactory::gameMode_survival(), ["survival", "s", "0"]),
|
||||
new self("creative", "Creative", KnownTranslationFactory::gameMode_creative(), ["creative", "c", "1"]),
|
||||
new self("adventure", "Adventure", KnownTranslationFactory::gameMode_adventure(), ["adventure", "a", "2"]),
|
||||
new self("spectator", "Spectator", KnownTranslationFactory::gameMode_spectator(), ["spectator", "v", "view", "3"])
|
||||
new self("survival", "Survival", KnownTranslationFactory::gameMode_survival(), DefaultPermissionNames::GROUP_GAMEMODE_SURVIVAL, ["survival", "s", "0"]),
|
||||
new self("creative", "Creative", KnownTranslationFactory::gameMode_creative(), DefaultPermissionNames::GROUP_GAMEMODE_CREATIVE, ["creative", "c", "1"]),
|
||||
new self("adventure", "Adventure", KnownTranslationFactory::gameMode_adventure(), DefaultPermissionNames::GROUP_GAMEMODE_ADVENTURE, ["adventure", "a", "2"]),
|
||||
new self("spectator", "Spectator", KnownTranslationFactory::gameMode_spectator(), DefaultPermissionNames::GROUP_GAMEMODE_SPECTATOR, ["spectator", "v", "view", "3"])
|
||||
);
|
||||
}
|
||||
|
||||
@ -76,6 +77,7 @@ final class GameMode{
|
||||
string $enumName,
|
||||
private string $englishName,
|
||||
private Translatable $translatableName,
|
||||
private string $permissionGroupName,
|
||||
private array $aliases = []
|
||||
){
|
||||
$this->Enum___construct($enumName);
|
||||
@ -87,6 +89,8 @@ final class GameMode{
|
||||
|
||||
public function getTranslatableName() : Translatable{ return $this->translatableName; }
|
||||
|
||||
public function getPermissionGroupName() : string{ return $this->permissionGroupName; }
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
|
@ -261,7 +261,6 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
|
||||
//TODO: Abilities
|
||||
protected bool $autoJump = true;
|
||||
protected bool $allowFlight = false;
|
||||
protected bool $blockCollision = true;
|
||||
protected bool $flying = false;
|
||||
|
||||
@ -436,12 +435,16 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
*
|
||||
* Note: Setting this to false DOES NOT change whether the player is currently flying. Use
|
||||
* {@link Player::setFlying()} for that purpose.
|
||||
*
|
||||
* Note: As of 4.13, this will override any game mode flight restrictions for the duration of the game session.
|
||||
* This differs from previous behaviour, where the flag would get overwritten by game mode changes.
|
||||
*
|
||||
* @deprecated This is now controlled by setting a permission, which allows more fine-tuned control.
|
||||
* @see DefaultPermissionNames::GAME_FLIGHT
|
||||
*/
|
||||
public function setAllowFlight(bool $value) : void{
|
||||
if($this->allowFlight !== $value){
|
||||
$this->allowFlight = $value;
|
||||
$this->getNetworkSession()->syncAbilities($this);
|
||||
}
|
||||
$this->setBasePermission(DefaultPermissionNames::GAME_FLIGHT, $value);
|
||||
$this->getNetworkSession()->syncAbilities($this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -451,7 +454,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
* enter or exit flight mode will be prevented.
|
||||
*/
|
||||
public function getAllowFlight() : bool{
|
||||
return $this->allowFlight;
|
||||
return $this->hasPermission(DefaultPermissionNames::GAME_FLIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1056,9 +1059,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
}
|
||||
|
||||
protected function internalSetGameMode(GameMode $gameMode) : void{
|
||||
if(isset($this->gamemode)){
|
||||
$this->unsetBasePermission($this->gamemode->getPermissionGroupName());
|
||||
}
|
||||
$this->gamemode = $gameMode;
|
||||
|
||||
$this->allowFlight = $this->gamemode->equals(GameMode::CREATIVE());
|
||||
$this->setBasePermission($this->gamemode->getPermissionGroupName(), true);
|
||||
|
||||
$this->hungerManager->setEnabled($this->isSurvival());
|
||||
|
||||
if($this->isSpectator()){
|
||||
@ -1071,7 +1078,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
//this is a yucky hack but we don't have any other options :(
|
||||
$this->sendPosition($this->location, null, null, MovePlayerPacket::MODE_TELEPORT);
|
||||
}else{
|
||||
if($this->isSurvival()){
|
||||
if(!$this->hasPermission(DefaultPermissionNames::GAME_FLIGHT)){
|
||||
$this->setFlying(false);
|
||||
}
|
||||
$this->setHasBlockCollision(true);
|
||||
@ -1140,11 +1147,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
return $this->gamemode->equals(GameMode::SPECTATOR());
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: make this a dynamic ability instead of being hardcoded
|
||||
*/
|
||||
public function hasFiniteResources() : bool{
|
||||
return $this->gamemode->equals(GameMode::SURVIVAL()) || $this->gamemode->equals(GameMode::ADVENTURE());
|
||||
return !$this->hasPermission(DefaultPermissionNames::GAME_ITEM_CREATE);
|
||||
}
|
||||
|
||||
public function isFireProof() : bool{
|
||||
@ -1452,6 +1456,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
Timings::$playerCommand->stopTiming();
|
||||
}else{
|
||||
$ev = new PlayerChatEvent($this, $ev->getMessage(), $this->server->getBroadcastChannelSubscribers(Server::BROADCAST_CHANNEL_USERS));
|
||||
if(!$this->hasPermission(DefaultPermissionNames::GAME_CHAT)){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->server->broadcastMessage($this->getServer()->getLanguage()->translateString($ev->getFormat(), [$ev->getPlayer()->getDisplayName(), $ev->getMessage()]), $ev->getRecipients());
|
||||
@ -1494,7 +1501,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$oldItem = clone $item;
|
||||
|
||||
$ev = new PlayerItemUseEvent($this, $item, $directionVector);
|
||||
if($this->hasItemCooldown($item) || $this->isSpectator()){
|
||||
if($this->hasItemCooldown($item) || !$this->hasPermission(DefaultPermissionNames::GAME_ITEM_USE)){
|
||||
$ev->cancel();
|
||||
}
|
||||
|
||||
@ -1565,7 +1572,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
public function releaseHeldItem() : bool{
|
||||
try{
|
||||
$item = $this->inventory->getItemInHand();
|
||||
if(!$this->isUsingItem() || $this->hasItemCooldown($item)){
|
||||
if(!$this->isUsingItem() || $this->hasItemCooldown($item) || !$this->hasPermission(DefaultPermissionNames::GAME_ITEM_USE)){
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1599,7 +1606,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
|
||||
$ev = new PlayerBlockPickEvent($this, $block, $item);
|
||||
$existingSlot = $this->inventory->first($item);
|
||||
if($existingSlot === -1 && ($this->hasFiniteResources() || $this->isSpectator())){
|
||||
if($existingSlot === -1 && $this->hasFiniteResources()){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
@ -1641,7 +1648,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$target = $this->getWorld()->getBlock($pos);
|
||||
|
||||
$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, null, $face, PlayerInteractEvent::LEFT_CLICK_BLOCK);
|
||||
if($this->isSpectator()){
|
||||
if(!$this->hasPermission(DefaultPermissionNames::GAME_BLOCK_INTERACT)){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
@ -1759,7 +1766,11 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
if(!$this->canInteract($entity->getLocation(), self::MAX_REACH_DISTANCE_ENTITY_INTERACTION)){
|
||||
$this->logger->debug("Cancelled attack of entity " . $entity->getId() . " due to not currently being interactable");
|
||||
$ev->cancel();
|
||||
}elseif($this->isSpectator() || ($entity instanceof Player && !$this->server->getConfigGroup()->getConfigBool("pvp"))){
|
||||
}elseif(!$this->hasPermission($entity instanceof Player ? DefaultPermissionNames::GAME_PLAYER_ATTACK : DefaultPermissionNames::GAME_ENTITY_ATTACK)){
|
||||
$this->logger->debug("Cancelled attack of entity " . $entity->getId() . " due to lack of attack permission");
|
||||
$ev->cancel();
|
||||
}elseif($entity instanceof Player && !$this->server->getConfigGroup()->getConfigBool("pvp")){
|
||||
$this->logger->debug("Cancelled attack of player " . $entity->getId() . " due to PvP being disabled globally");
|
||||
$ev->cancel();
|
||||
}
|
||||
|
||||
@ -1825,6 +1836,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$this->logger->debug("Cancelled interaction with entity " . $entity->getId() . " due to not currently being interactable");
|
||||
$ev->cancel();
|
||||
}
|
||||
if(!$this->hasPermission($entity instanceof Player ? DefaultPermissionNames::GAME_PLAYER_INTERACT : DefaultPermissionNames::GAME_ENTITY_INTERACT)){
|
||||
$this->logger->debug("Cancelled interaction with entity " . $entity->getId() . " due to lack of permission");
|
||||
$ev->cancel();
|
||||
}
|
||||
|
||||
$ev->call();
|
||||
|
||||
@ -1875,7 +1890,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
return true;
|
||||
}
|
||||
$ev = new PlayerToggleFlightEvent($this, $fly);
|
||||
if(!$this->allowFlight){
|
||||
if(!$this->getAllowFlight()){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
@ -2373,7 +2388,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
&& $source->getCause() !== EntityDamageEvent::CAUSE_SUICIDE
|
||||
){
|
||||
$source->cancel();
|
||||
}elseif($this->allowFlight && $source->getCause() === EntityDamageEvent::CAUSE_FALL){
|
||||
}elseif($this->getAllowFlight() && $source->getCause() === EntityDamageEvent::CAUSE_FALL){
|
||||
$source->cancel();
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\ChunkSelector;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\promise\Promise;
|
||||
@ -1869,7 +1870,7 @@ class World implements ChunkManager{
|
||||
if($player !== null){
|
||||
$ev = new BlockBreakEvent($player, $target, $item, $player->isCreative(), $drops, $xpDrop);
|
||||
|
||||
if($target instanceof Air || ($player->isSurvival() && !$target->getBreakInfo()->isBreakable()) || $player->isSpectator()){
|
||||
if($target instanceof Air || ($player->isSurvival() && !$target->getBreakInfo()->isBreakable()) || !$player->hasPermission(DefaultPermissionNames::GAME_BLOCK_BREAK)){
|
||||
$ev->cancel();
|
||||
}
|
||||
|
||||
@ -1966,7 +1967,7 @@ class World implements ChunkManager{
|
||||
|
||||
if($player !== null){
|
||||
$ev = new PlayerInteractEvent($player, $item, $blockClicked, $clickVector, $face, PlayerInteractEvent::RIGHT_CLICK_BLOCK);
|
||||
if($player->isSpectator()){
|
||||
if(!$player->hasPermission(DefaultPermissionNames::GAME_BLOCK_INTERACT)){
|
||||
$ev->cancel(); //set it to cancelled so plugins can bypass this
|
||||
}
|
||||
|
||||
@ -2020,7 +2021,7 @@ class World implements ChunkManager{
|
||||
|
||||
if($player !== null){
|
||||
$ev = new BlockPlaceEvent($player, $hand, $blockReplace, $blockClicked, $item);
|
||||
if($player->isSpectator()){
|
||||
if(!$player->hasPermission(DefaultPermissionNames::GAME_BLOCK_PLACE)){
|
||||
$ev->cancel();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user