path, strtolower($username) . '.dat'); } private function handleCorruptedPlayerData(string $name) : void{ $path = $this->getPlayerDataPath($name); rename($path, $path . '.bak'); } public function hasData(string $name) : bool{ return file_exists($this->getPlayerDataPath($name)); } public function loadData(string $name) : ?CompoundTag{ $name = strtolower($name); $path = $this->getPlayerDataPath($name); if(!file_exists($path)){ return null; } try{ $contents = Filesystem::fileGetContents($path); }catch(\RuntimeException $e){ throw new PlayerDataLoadException("Failed to read player data file \"$path\": " . $e->getMessage(), 0, $e); } try{ $decompressed = ErrorToExceptionHandler::trapAndRemoveFalse(fn() => zlib_decode($contents)); }catch(\ErrorException $e){ $this->handleCorruptedPlayerData($name); throw new PlayerDataLoadException("Failed to decompress raw player data for \"$name\": " . $e->getMessage(), 0, $e); } try{ return (new BigEndianNbtSerializer())->read($decompressed)->mustGetCompoundTag(); }catch(NbtDataException $e){ //corrupt data $this->handleCorruptedPlayerData($name); throw new PlayerDataLoadException("Failed to decode NBT data for \"$name\": " . $e->getMessage(), 0, $e); } } public function saveData(string $name, CompoundTag $data) : void{ $nbt = new BigEndianNbtSerializer(); $contents = Utils::assumeNotFalse(zlib_encode($nbt->write(new TreeRoot($data)), ZLIB_ENCODING_GZIP), "zlib_encode() failed unexpectedly"); try{ Filesystem::safeFilePutContents($this->getPlayerDataPath($name), $contents); }catch(\RuntimeException $e){ throw new PlayerDataSaveException("Failed to write player data file: " . $e->getMessage(), 0, $e); } } }