diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 1c6feffe5..a331ce80a 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -1240,6 +1240,25 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return $this->gamemode; } + /** + * @internal + * + * Returns a client-friendly gamemode of the specified real gamemode + * This function takes care of handling gamemodes known to MCPE (as of 1.1.0.3, that includes Survival, Creative and Adventure) + * + * TODO: remove this when Spectator Mode gets added properly to MCPE + * + * @param int $gamemode + */ + public static function getClientFriendlyGamemode(int $gamemode) : int{ + $gamemode &= 0x03; + if($gamemode === Player::SPECTATOR){ + return Player::CREATIVE; + } + + return $gamemode; + } + /** * Sets the gamemode, and if needed, kicks the Player. * @@ -1253,13 +1272,10 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return false; } - $this->server->getPluginManager()->callEvent($ev = new PlayerGameModeChangeEvent($this, (int) $gm)); + $this->server->getPluginManager()->callEvent($ev = new PlayerGameModeChangeEvent($this, $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(); + $this->sendGamemode(); } return false; } @@ -1286,9 +1302,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->namedtag->playerGameType = new IntTag("playerGameType", $this->gamemode); if(!$client){ //Gamemode changed by server, do not send for client changes - $pk = new SetPlayerGameTypePacket(); - $pk->gamemode = $this->gamemode & 0x01; - $this->dataPacket($pk); + $this->sendGamemode(); }else{ Command::broadcastCommandMessage($this, new TranslationContainer("commands.gamemode.success.self", [Server::getGamemodeString($gm)])); } @@ -1305,6 +1319,16 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return true; } + /** + * @internal + * Sends the player's gamemode to the client. + */ + public function sendGamemode(){ + $pk = new SetPlayerGameTypePacket(); + $pk->gamemode = Player::getClientFriendlyGamemode($this->gamemode); + $this->dataPacket($pk); + } + /** * Sends all the option flags */ @@ -1816,12 +1840,13 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $pk = new StartGamePacket(); $pk->entityUniqueId = $this->id; $pk->entityRuntimeId = $this->id; + $pk->playerGamemode = Player::getClientFriendlyGamemode($this->gamemode); $pk->x = $this->x; $pk->y = $this->y; $pk->z = $this->z; $pk->seed = -1; $pk->dimension = 0; //TODO: implement this properly - $pk->gamemode = $this->gamemode & 0x01; + $pk->worldGamemode = Player::getClientFriendlyGamemode($this->server->getGamemode()); $pk->difficulty = $this->server->getDifficulty(); $pk->spawnX = $spawnPosition->getFloorX(); $pk->spawnY = $spawnPosition->getFloorY(); @@ -3165,11 +3190,9 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade } public function handleSetPlayerGameType(SetPlayerGameTypePacket $packet) : bool{ - if($packet->gamemode !== ($this->gamemode & 0x01)){ - //GUI gamemode change, set it back to original for now (only possible through client bug or hack with current allowed client permissions) - $pk = new SetPlayerGameTypePacket(); - $pk->gamemode = $this->gamemode & 0x01; - $this->dataPacket($pk); + if($packet->gamemode !== $this->gamemode){ + //Set this back to default. TODO: handle this properly + $this->sendGamemode(); $this->sendSettings(); } return true; diff --git a/src/pocketmine/network/mcpe/protocol/MovePlayerPacket.php b/src/pocketmine/network/mcpe/protocol/MovePlayerPacket.php index 24a5644e6..2a337669f 100644 --- a/src/pocketmine/network/mcpe/protocol/MovePlayerPacket.php +++ b/src/pocketmine/network/mcpe/protocol/MovePlayerPacket.php @@ -42,6 +42,7 @@ class MovePlayerPacket extends DataPacket{ public $pitch; public $mode = self::MODE_NORMAL; public $onGround; + public $eid2; //??? public function decode(){ $this->eid = $this->getEntityRuntimeId(); @@ -51,6 +52,7 @@ class MovePlayerPacket extends DataPacket{ $this->bodyYaw = $this->getLFloat(); $this->mode = $this->getByte(); $this->onGround = $this->getBool(); + $this->eid2 = $this->getEntityRuntimeId(); } public function encode(){ @@ -62,6 +64,7 @@ class MovePlayerPacket extends DataPacket{ $this->putLFloat($this->bodyYaw); //TODO $this->putByte($this->mode); $this->putBool($this->onGround); + $this->putEntityRuntimeId($this->eid2); } public function handle(NetworkSession $session) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/StartGamePacket.php b/src/pocketmine/network/mcpe/protocol/StartGamePacket.php index b9ccb4d7a..1367de51a 100644 --- a/src/pocketmine/network/mcpe/protocol/StartGamePacket.php +++ b/src/pocketmine/network/mcpe/protocol/StartGamePacket.php @@ -31,13 +31,14 @@ class StartGamePacket extends DataPacket{ public $entityUniqueId; public $entityRuntimeId; + public $playerGamemode; public $x; public $y; public $z; public $seed; public $dimension; public $generator = 1; //default infinite - 0 old, 1 infinite, 2 flat - public $gamemode; + public $worldGamemode; public $difficulty; public $spawnX; public $spawnY; @@ -51,6 +52,7 @@ class StartGamePacket extends DataPacket{ public $isTexturePacksRequired = 0; public $levelId = ""; //base64 string, usually the same as world folder name in vanilla public $worldName; + public $premiumWorldTemplateId = ""; public function decode(){ @@ -60,13 +62,14 @@ class StartGamePacket extends DataPacket{ $this->reset(); $this->putEntityUniqueId($this->entityUniqueId); $this->putEntityRuntimeId($this->entityRuntimeId); + $this->putVarInt($this->playerGamemode); //client gamemode, other field is world gamemode $this->putVector3f($this->x, $this->y, $this->z); - $this->putLFloat(0); //TODO: find out what these are (yaw/pitch?) + $this->putLFloat(0); //TODO: yaw/pitch $this->putLFloat(0); $this->putVarInt($this->seed); $this->putVarInt($this->dimension); $this->putVarInt($this->generator); - $this->putVarInt($this->gamemode); + $this->putVarInt($this->worldGamemode); $this->putVarInt($this->difficulty); $this->putBlockPosition($this->spawnX, $this->spawnY, $this->spawnZ); $this->putBool($this->hasAchievementsDisabled); @@ -79,6 +82,7 @@ class StartGamePacket extends DataPacket{ $this->putUnsignedVarInt(0); //TODO: gamerules $this->putString($this->levelId); $this->putString($this->worldName); + $this->putString($this->premiumWorldTemplateId); } public function handle(NetworkSession $session) : bool{