diff --git a/src/Server.php b/src/Server.php index 37feb68abd..aef04a98ed 100644 --- a/src/Server.php +++ b/src/Server.php @@ -34,6 +34,7 @@ use pocketmine\console\ConsoleCommandSender; use pocketmine\console\ConsoleReaderThread; use pocketmine\crafting\CraftingManager; use pocketmine\crafting\CraftingManagerFromDataHelper; +use pocketmine\data\java\GameModeIdMap; use pocketmine\entity\EntityDataHelper; use pocketmine\entity\Location; use pocketmine\event\HandlerListManager; @@ -372,7 +373,7 @@ class Server{ } public function getGamemode() : GameMode{ - return GameMode::fromMagicNumber($this->configGroup->getConfigInt("gamemode", 0) & 0b11); + return GameModeIdMap::getInstance()->fromId($this->configGroup->getConfigInt("gamemode", 0)) ?? GameMode::SURVIVAL(); } public function getForceGamemode() : bool{ diff --git a/src/command/defaults/DefaultGamemodeCommand.php b/src/command/defaults/DefaultGamemodeCommand.php index 308353aee5..8a72fab706 100644 --- a/src/command/defaults/DefaultGamemodeCommand.php +++ b/src/command/defaults/DefaultGamemodeCommand.php @@ -25,6 +25,7 @@ namespace pocketmine\command\defaults; use pocketmine\command\CommandSender; use pocketmine\command\utils\InvalidCommandSyntaxException; +use pocketmine\data\java\GameModeIdMap; use pocketmine\lang\TranslationContainer; use pocketmine\permission\DefaultPermissionNames; use pocketmine\player\GameMode; @@ -57,7 +58,7 @@ class DefaultGamemodeCommand extends VanillaCommand{ return true; } - $sender->getServer()->getConfigGroup()->setConfigInt("gamemode", $gameMode->getMagicNumber()); + $sender->getServer()->getConfigGroup()->setConfigInt("gamemode", GameModeIdMap::getInstance()->toId($gameMode)); $sender->sendMessage(new TranslationContainer("commands.defaultgamemode.success", [$gameMode->getTranslationKey()])); return true; } diff --git a/src/data/java/GameModeIdMap.php b/src/data/java/GameModeIdMap.php new file mode 100644 index 0000000000..5990a72864 --- /dev/null +++ b/src/data/java/GameModeIdMap.php @@ -0,0 +1,67 @@ + + */ + private array $idToEnum = []; + + /** + * @var int[] + * @phpstan-var array + */ + private array $enumToId = []; + + public function __construct(){ + $this->register(0, GameMode::SURVIVAL()); + $this->register(1, GameMode::CREATIVE()); + $this->register(2, GameMode::ADVENTURE()); + $this->register(3, GameMode::SPECTATOR()); + } + + private function register(int $id, GameMode $type) : void{ + $this->idToEnum[$id] = $type; + $this->enumToId[$type->id()] = $id; + } + + public function fromId(int $id) : ?GameMode{ + return $this->idToEnum[$id] ?? null; + } + + public function toId(GameMode $type) : int{ + if(!array_key_exists($type->id(), $this->enumToId)){ + throw new \InvalidArgumentException("Game mode does not have a mapped ID"); //this should never happen + } + return $this->enumToId[$type->id()]; + } +} diff --git a/src/network/query/QueryInfo.php b/src/network/query/QueryInfo.php index 25d07f549d..b6cb199cae 100644 --- a/src/network/query/QueryInfo.php +++ b/src/network/query/QueryInfo.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\query; +use pocketmine\player\GameMode; use pocketmine\player\Player; use pocketmine\plugin\Plugin; use pocketmine\Server; @@ -81,7 +82,7 @@ final class QueryInfo{ $this->plugins = $server->getPluginManager()->getPlugins(); $this->players = $server->getOnlinePlayers(); - $this->gametype = ($server->getGamemode()->getMagicNumber() & 0x01) === 0 ? "SMP" : "CMP"; + $this->gametype = ($server->getGamemode()->equals(GameMode::SURVIVAL()) || $server->getGamemode()->equals(GameMode::ADVENTURE())) ? "SMP" : "CMP"; $this->version = $server->getVersion(); $this->server_engine = $server->getName() . " " . $server->getPocketMineVersion(); $world = $server->getWorldManager()->getDefaultWorld(); diff --git a/src/player/GameMode.php b/src/player/GameMode.php index d8e2d28bfe..3d5c0c7dce 100644 --- a/src/player/GameMode.php +++ b/src/player/GameMode.php @@ -44,21 +44,18 @@ final class GameMode{ /** @var self[] */ protected static $aliasMap = []; - /** @var self[] */ - protected static $magicNumberMap = []; protected static function setup() : void{ self::registerAll( - new self("survival", 0, "Survival", "gameMode.survival", ["s", "0"]), - new self("creative", 1, "Creative", "gameMode.creative", ["c", "1"]), - new self("adventure", 2, "Adventure", "gameMode.adventure", ["a", "2"]), - new self("spectator", 3, "Spectator", "gameMode.spectator", ["v", "view", "3"]) + new self("survival", "Survival", "gameMode.survival", ["s", "0"]), + new self("creative", "Creative", "gameMode.creative", ["c", "1"]), + new self("adventure", "Adventure", "gameMode.adventure", ["a", "2"]), + new self("spectator", "Spectator", "gameMode.spectator", ["v", "view", "3"]) ); } protected static function register(self $member) : void{ self::Enum_register($member); - self::$magicNumberMap[$member->getMagicNumber()] = $member; foreach($member->getAliases() as $alias){ self::$aliasMap[$alias] = $member; } @@ -69,18 +66,6 @@ final class GameMode{ return self::$aliasMap[$str] ?? self::Enum_fromString($str); } - /** - * @return GameMode - * @throws \InvalidArgumentException - */ - public static function fromMagicNumber(int $n) : self{ - self::checkInit(); - if(!isset(self::$magicNumberMap[$n])){ - throw new \InvalidArgumentException("No " . self::class . " enum member matches magic number $n"); - } - return self::$magicNumberMap[$n]; - } - /** @var int */ private $magicNumber; /** @var string */ @@ -93,18 +78,13 @@ final class GameMode{ /** * @param string[] $aliases */ - private function __construct(string $enumName, int $magicNumber, string $englishName, string $translationKey, array $aliases = []){ + private function __construct(string $enumName, string $englishName, string $translationKey, array $aliases = []){ $this->Enum___construct($enumName); - $this->magicNumber = $magicNumber; $this->englishName = $englishName; $this->translationKey = $translationKey; $this->aliases = $aliases; } - public function getMagicNumber() : int{ - return $this->magicNumber; - } - public function getEnglishName() : string{ return $this->englishName; } diff --git a/src/player/Player.php b/src/player/Player.php index 8ede644770..2c4227a172 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -29,6 +29,7 @@ use pocketmine\block\UnknownBlock; use pocketmine\block\VanillaBlocks; use pocketmine\command\CommandSender; use pocketmine\crafting\CraftingGrid; +use pocketmine\data\java\GameModeIdMap; use pocketmine\entity\animation\Animation; use pocketmine\entity\animation\ArmSwingAnimation; use pocketmine\entity\animation\CriticalHitAnimation; @@ -332,7 +333,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->lastPlayed = $nbt->getLong("lastPlayed", $now); if(!$this->server->getForceGamemode() and ($gameModeTag = $nbt->getTag("playerGameType")) instanceof IntTag){ - $this->internalSetGameMode(GameMode::fromMagicNumber($gameModeTag->getValue() & 0x03)); //TODO: bad hack here to avoid crashes on corrupted data + $this->internalSetGameMode(GameModeIdMap::getInstance()->fromId($gameModeTag->getValue()) ?? GameMode::SURVIVAL()); //TODO: bad hack here to avoid crashes on corrupted data }else{ $this->internalSetGameMode($this->server->getGamemode()); } @@ -2069,7 +2070,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $nbt->setInt("SpawnZ", $spawn->getFloorZ()); } - $nbt->setInt("playerGameType", $this->gamemode->getMagicNumber()); + $nbt->setInt("playerGameType", GameModeIdMap::getInstance()->toId($this->gamemode)); $nbt->setLong("firstPlayed", $this->firstPlayed); $nbt->setLong("lastPlayed", (int) floor(microtime(true) * 1000)); diff --git a/src/wizard/SetupWizard.php b/src/wizard/SetupWizard.php index c6040aa469..5491422c62 100644 --- a/src/wizard/SetupWizard.php +++ b/src/wizard/SetupWizard.php @@ -27,6 +27,7 @@ declare(strict_types=1); */ namespace pocketmine\wizard; +use pocketmine\data\java\GameModeIdMap; use pocketmine\lang\Language; use pocketmine\lang\LanguageNotFoundException; use pocketmine\player\GameMode; @@ -158,7 +159,7 @@ LICENSE; $this->message($this->lang->get("gamemode_info")); do{ - $gamemode = (int) $this->getInput($this->lang->get("default_gamemode"), (string) GameMode::SURVIVAL()->getMagicNumber()); + $gamemode = (int) $this->getInput($this->lang->get("default_gamemode"), (string) GameModeIdMap::getInstance()->toId(GameMode::SURVIVAL())); }while($gamemode < 0 or $gamemode > 3); $config->set("gamemode", $gamemode);