diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 325b8cb33..b3278627f 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -23,6 +23,7 @@ namespace pocketmine; use pocketmine\block\Air; use pocketmine\block\Block; +use pocketmine\command\Command; use pocketmine\command\CommandSender; use pocketmine\entity\Arrow; use pocketmine\entity\Effect; @@ -1080,13 +1081,19 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade * * @return bool */ - public function setGamemode($gm){ + public function setGamemode($gm, $client = false){ if($gm < 0 or $gm > 3 or $this->gamemode === $gm){ return false; } $this->server->getPluginManager()->callEvent($ev = new PlayerGameModeChangeEvent($this, (int) $gm)); if($ev->isCancelled()){ + if($client){ //gamemode change by client in the GUI + $pk = new SetPlayerGameTypePacket(); + $pk->gamemode = $this->gamemode & 0x01; + $this->dataPacket($pk); + $this->sendSettings(); + } return false; } @@ -1096,6 +1103,11 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade if($this->isSpectator()){ $this->isFlying = true; $this->despawnFromAll(); + + // Client automatically turns off flight controls when on the ground. + // A combination of this hack and a new AdventureSettings flag FINALLY + // fixes spectator flight controls. Thank @robske110 for this hack. + $this->teleport($this->temporalVector->setComponents($this->x, $this->y + 0.1, $this->z)); }else{ if($this->isSurvival()){ $this->isFlying = false; @@ -1106,11 +1118,14 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->resetFallDistance(); $this->namedtag->playerGameType = new IntTag("playerGameType", $this->gamemode); - - $pk = new SetPlayerGameTypePacket(); - $pk->gamemode = $this->gamemode & 0x01; - $this->dataPacket($pk); - $this->sendSettings(); + if(!$client){ //Gamemode changed by server, do not send for client changes + $pk = new SetPlayerGameTypePacket(); + $pk->gamemode = $this->gamemode & 0x01; + $this->dataPacket($pk); + $this->sendSettings(); + }else{ + Command::broadcastCommandMessage($this, new TranslationContainer("commands.gamemode.success.self", [Server::getGamemodeString($gm)])); + } $this->inventory->sendContents($this); $this->inventory->sendContents($this->getViewers()); @@ -2816,6 +2831,18 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $pk->radius = $packet->radius; $this->dataPacket($pk); break; + case ProtocolInfo::SET_PLAYER_GAME_TYPE_PACKET: + if($packet->gamemode !== $this->gamemode){ + if(!$this->hasPermission("pocketmine.command.gamemode")){ + $pk = new SetPlayerGameTypePacket(); + $pk->gamemode = $this->gamemode & 0x01; + $this->dataPacket($pk); + $this->sendSettings(); + break; + } + $this->setGamemode($packet->gamemode, true); + } + break; default: break; } diff --git a/src/pocketmine/network/protocol/SetPlayerGameTypePacket.php b/src/pocketmine/network/protocol/SetPlayerGameTypePacket.php index 39f1a57ec..ecb87a822 100644 --- a/src/pocketmine/network/protocol/SetPlayerGameTypePacket.php +++ b/src/pocketmine/network/protocol/SetPlayerGameTypePacket.php @@ -30,7 +30,7 @@ class SetPlayerGameTypePacket extends DataPacket{ public $gamemode; public function decode(){ - + $this->gamemode = $this->getVarInt(); } public function encode(){