WorldManager::createWorld() now accepts WorldCreationOptions instead of mixed[]

This commit is contained in:
Dylan K. Taylor 2021-04-13 21:03:25 +01:00
parent 6ce15854af
commit 9c1b274499
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
9 changed files with 165 additions and 75 deletions

View File

@ -100,8 +100,8 @@ use pocketmine\world\format\io\WorldProviderManager;
use pocketmine\world\format\io\WritableWorldProvider; use pocketmine\world\format\io\WritableWorldProvider;
use pocketmine\world\generator\Generator; use pocketmine\world\generator\Generator;
use pocketmine\world\generator\GeneratorManager; use pocketmine\world\generator\GeneratorManager;
use pocketmine\world\generator\normal\Normal;
use pocketmine\world\World; use pocketmine\world\World;
use pocketmine\world\WorldCreationOptions;
use pocketmine\world\WorldManager; use pocketmine\world\WorldManager;
use Ramsey\Uuid\UuidInterface; use Ramsey\Uuid\UuidInterface;
use function array_shift; use function array_shift;
@ -1031,17 +1031,30 @@ class Server{
continue; continue;
} }
if(!$this->worldManager->loadWorld($name, true)){ if(!$this->worldManager->loadWorld($name, true)){
$creationOptions = WorldCreationOptions::create();
//TODO: error checking
if(isset($options["generator"])){ if(isset($options["generator"])){
$generatorOptions = explode(":", $options["generator"]); $generatorOptions = explode(":", $options["generator"]);
$generator = GeneratorManager::getInstance()->getGenerator(array_shift($generatorOptions)); $creationOptions->setGeneratorClass(GeneratorManager::getInstance()->getGenerator(array_shift($generatorOptions)));
if(count($generatorOptions) > 0){ if(count($generatorOptions) > 0){
$options["preset"] = implode(":", $generatorOptions); $creationOptions->setGeneratorOptions(implode(":", $generatorOptions));
}
}
if(isset($options["difficulty"]) && is_string($options["difficulty"])){
$creationOptions->setDifficulty(World::getDifficultyFromString($options["difficulty"]));
}
if(isset($options["preset"]) && is_string($options["preset"])){
$creationOptions->setGeneratorOptions($options["preset"]);
}
if(isset($options["seed"])){
$convertedSeed = Generator::convertSeed((string) ($options["seed"] ?? ""));
if($convertedSeed !== null){
$creationOptions->setSeed($convertedSeed);
} }
}else{
$generator = Normal::class;
} }
$this->worldManager->generateWorld($name, Generator::convertSeed((string) ($options["seed"] ?? "")), $generator, $options); $this->worldManager->generateWorld($name, $creationOptions);
} }
} }
@ -1053,12 +1066,14 @@ class Server{
$this->configGroup->setConfigString("level-name", "world"); $this->configGroup->setConfigString("level-name", "world");
} }
if(!$this->worldManager->loadWorld($default, true)){ if(!$this->worldManager->loadWorld($default, true)){
$this->worldManager->generateWorld( $creationOptions = WorldCreationOptions::create()
$default, ->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($this->configGroup->getConfigString("level-type")))
Generator::convertSeed($this->configGroup->getConfigString("level-seed")), ->setGeneratorOptions($this->configGroup->getConfigString("generator-settings"));
GeneratorManager::getInstance()->getGenerator($this->configGroup->getConfigString("level-type")), $convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed"));
["preset" => $this->configGroup->getConfigString("generator-settings")] if($convertedSeed !== null){
); $creationOptions->setSeed($convertedSeed);
}
$this->worldManager->generateWorld($default, $creationOptions);
} }
$world = $this->worldManager->getWorldByName($default); $world = $this->worldManager->getWorldByName($default);

View File

@ -0,0 +1,98 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world;
use pocketmine\math\Vector3;
use pocketmine\utils\Limits;
use pocketmine\utils\Utils;
use pocketmine\world\generator\Generator;
use pocketmine\world\generator\normal\Normal;
use function random_int;
/**
* Represents user-customizable settings for world creation
*/
final class WorldCreationOptions{
/** @phpstan-var class-string<Generator> */
private string $generatorClass = Normal::class;
private int $seed;
private int $difficulty = World::DIFFICULTY_NORMAL;
private string $generatorOptions = "";
private Vector3 $spawnPosition;
public function __construct(){
$this->seed = random_int(Limits::INT32_MIN, Limits::INT32_MAX);
$this->spawnPosition = new Vector3(256, 70, 256);
}
public static function create() : self{
return new self;
}
/** @phpstan-return class-string<Generator> */
public function getGeneratorClass() : string{ return $this->generatorClass; }
/**
* @phpstan-param class-string<Generator> $generatorClass
* @return $this
*/
public function setGeneratorClass(string $generatorClass) : self{
Utils::testValidInstance($generatorClass, Generator::class);
$this->generatorClass = $generatorClass;
return $this;
}
public function getSeed() : int{ return $this->seed; }
/** @return $this */
public function setSeed(int $seed) : self{
$this->seed = $seed;
return $this;
}
public function getDifficulty() : int{ return $this->difficulty; }
/** @return $this */
public function setDifficulty(int $difficulty) : self{
$this->difficulty = $difficulty;
return $this;
}
public function getGeneratorOptions() : string{ return $this->generatorOptions; }
/** @return $this */
public function setGeneratorOptions(string $generatorOptions) : self{
$this->generatorOptions = $generatorOptions;
return $this;
}
public function getSpawnPosition() : Vector3{ return $this->spawnPosition; }
/** @return $this */
public function setSpawnPosition(Vector3 $spawnPosition) : self{
$this->spawnPosition = $spawnPosition;
return $this;
}
}

View File

@ -30,24 +30,19 @@ use pocketmine\event\world\WorldUnloadEvent;
use pocketmine\player\ChunkSelector; use pocketmine\player\ChunkSelector;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\timings\Timings; use pocketmine\timings\Timings;
use pocketmine\utils\Limits;
use pocketmine\utils\Utils;
use pocketmine\world\format\io\exception\CorruptedWorldException; use pocketmine\world\format\io\exception\CorruptedWorldException;
use pocketmine\world\format\io\exception\UnsupportedWorldFormatException; use pocketmine\world\format\io\exception\UnsupportedWorldFormatException;
use pocketmine\world\format\io\FormatConverter; use pocketmine\world\format\io\FormatConverter;
use pocketmine\world\format\io\WorldProvider; use pocketmine\world\format\io\WorldProvider;
use pocketmine\world\format\io\WorldProviderManager; use pocketmine\world\format\io\WorldProviderManager;
use pocketmine\world\format\io\WritableWorldProvider; use pocketmine\world\format\io\WritableWorldProvider;
use pocketmine\world\generator\Generator;
use pocketmine\world\generator\GeneratorManager; use pocketmine\world\generator\GeneratorManager;
use pocketmine\world\generator\normal\Normal;
use function array_keys; use function array_keys;
use function array_shift; use function array_shift;
use function assert; use function assert;
use function count; use function count;
use function implode; use function implode;
use function microtime; use function microtime;
use function random_int;
use function round; use function round;
use function sprintf; use function sprintf;
use function trim; use function trim;
@ -244,27 +239,18 @@ class WorldManager{
/** /**
* Generates a new world if it does not exist * Generates a new world if it does not exist
* *
* @param string $generator Class name that extends pocketmine\world\generator\Generator
* @param mixed[] $options
* @phpstan-param class-string<Generator> $generator
* @phpstan-param array<string, mixed> $options
*
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function generateWorld(string $name, ?int $seed = null, string $generator = Normal::class, array $options = [], bool $backgroundGeneration = true) : bool{ public function generateWorld(string $name, ?WorldCreationOptions $options = null, bool $backgroundGeneration = true) : bool{
if(trim($name) === "" or $this->isWorldGenerated($name)){ if(trim($name) === "" or $this->isWorldGenerated($name)){
return false; return false;
} }
$seed = $seed ?? random_int(Limits::INT32_MIN, Limits::INT32_MAX);
Utils::testValidInstance($generator, Generator::class);
$providerClass = $this->providerManager->getDefault(); $providerClass = $this->providerManager->getDefault();
$path = $this->getWorldPath($name); $path = $this->getWorldPath($name);
/** @var WritableWorldProvider $providerClass */ /** @var WritableWorldProvider $providerClass */
$providerClass::generate($path, $name, $seed, $generator, $options); $providerClass::generate($path, $name, $options);
/** @see WritableWorldProvider::__construct() */ /** @see WritableWorldProvider::__construct() */
$world = new World($this->server, $name, new $providerClass($path), $this->server->getAsyncPool()); $world = new World($this->server, $name, new $providerClass($path), $this->server->getAsyncPool());

View File

@ -26,6 +26,7 @@ namespace pocketmine\world\format\io;
use pocketmine\utils\Filesystem; use pocketmine\utils\Filesystem;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
use pocketmine\world\generator\GeneratorManager; use pocketmine\world\generator\GeneratorManager;
use pocketmine\world\WorldCreationOptions;
use function basename; use function basename;
use function crc32; use function crc32;
use function file_exists; use function file_exists;
@ -105,7 +106,13 @@ class FormatConverter{
$this->logger->info("Found previous conversion attempt, deleting..."); $this->logger->info("Found previous conversion attempt, deleting...");
Filesystem::recursiveUnlink($convertedOutput); Filesystem::recursiveUnlink($convertedOutput);
} }
$this->newProvider::generate($convertedOutput, $data->getName(), $data->getSeed(), GeneratorManager::getInstance()->getGenerator($data->getGenerator()), ["preset" => $data->getGeneratorOptions()]); $this->newProvider::generate($convertedOutput, $data->getName(), WorldCreationOptions::create()
->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($data->getGenerator()))
->setGeneratorOptions($data->getGeneratorOptions())
->setSeed($data->getSeed())
->setSpawnPosition($data->getSpawn())
->setDifficulty($data->getDifficulty())
);
/** /**
* @see WritableWorldProvider::__construct() * @see WritableWorldProvider::__construct()

View File

@ -24,17 +24,13 @@ declare(strict_types=1);
namespace pocketmine\world\format\io; namespace pocketmine\world\format\io;
use pocketmine\world\format\Chunk; use pocketmine\world\format\Chunk;
use pocketmine\world\generator\Generator; use pocketmine\world\WorldCreationOptions;
interface WritableWorldProvider extends WorldProvider{ interface WritableWorldProvider extends WorldProvider{
/** /**
* Generate the needed files in the path given * Generate the needed files in the path given
*
* @param mixed[] $options
* @phpstan-param class-string<Generator> $generator
* @phpstan-param array<string, mixed> $options
*/ */
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []) : void; public static function generate(string $path, string $name, ?WorldCreationOptions $options = null) : void;
/** /**
* Saves a chunk (usually to disk). * Saves a chunk (usually to disk).

View File

@ -32,13 +32,13 @@ use pocketmine\nbt\TreeRoot;
use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Limits; use pocketmine\utils\Limits;
use pocketmine\utils\Utils;
use pocketmine\world\format\io\exception\CorruptedWorldException; use pocketmine\world\format\io\exception\CorruptedWorldException;
use pocketmine\world\format\io\exception\UnsupportedWorldFormatException; use pocketmine\world\format\io\exception\UnsupportedWorldFormatException;
use pocketmine\world\generator\Flat; use pocketmine\world\generator\Flat;
use pocketmine\world\generator\Generator; use pocketmine\world\generator\Generator;
use pocketmine\world\generator\GeneratorManager; use pocketmine\world\generator\GeneratorManager;
use pocketmine\world\World; use pocketmine\world\World;
use pocketmine\world\WorldCreationOptions;
use function file_get_contents; use function file_get_contents;
use function file_put_contents; use function file_put_contents;
use function strlen; use function strlen;
@ -53,14 +53,9 @@ class BedrockWorldData extends BaseNbtWorldData{
public const GENERATOR_INFINITE = 1; public const GENERATOR_INFINITE = 1;
public const GENERATOR_FLAT = 2; public const GENERATOR_FLAT = 2;
/** public static function generate(string $path, string $name, ?WorldCreationOptions $options = null) : void{
* @param mixed[] $options $options ??= WorldCreationOptions::create();
* @phpstan-param class-string<Generator> $generator switch($options->getGeneratorClass()){
* @phpstan-param array<string, mixed> $options
*/
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []) : void{
Utils::testValidInstance($generator, Generator::class);
switch($generator){
case Flat::class: case Flat::class:
$generatorType = self::GENERATOR_FLAT; $generatorType = self::GENERATOR_FLAT;
break; break;
@ -72,7 +67,7 @@ class BedrockWorldData extends BaseNbtWorldData{
$worldData = CompoundTag::create() $worldData = CompoundTag::create()
//Vanilla fields //Vanilla fields
->setInt("DayCycleStopTime", -1) ->setInt("DayCycleStopTime", -1)
->setInt("Difficulty", World::getDifficultyFromString((string) ($options["difficulty"] ?? "normal"))) ->setInt("Difficulty", $options->getDifficulty())
->setByte("ForceGameType", 0) ->setByte("ForceGameType", 0)
->setInt("GameType", 0) ->setInt("GameType", 0)
->setInt("Generator", $generatorType) ->setInt("Generator", $generatorType)
@ -80,10 +75,10 @@ class BedrockWorldData extends BaseNbtWorldData{
->setString("LevelName", $name) ->setString("LevelName", $name)
->setInt("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL) ->setInt("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL)
//->setInt("Platform", 2) //TODO: find out what the possible values are for //->setInt("Platform", 2) //TODO: find out what the possible values are for
->setLong("RandomSeed", $seed) ->setLong("RandomSeed", $options->getSeed())
->setInt("SpawnX", 0) ->setInt("SpawnX", $options->getSpawnPosition()->getFloorX())
->setInt("SpawnY", 32767) ->setInt("SpawnY", $options->getSpawnPosition()->getFloorY())
->setInt("SpawnZ", 0) ->setInt("SpawnZ", $options->getSpawnPosition()->getFloorZ())
->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION) ->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION)
->setLong("Time", 0) ->setLong("Time", 0)
->setByte("eduLevel", 0) ->setByte("eduLevel", 0)
@ -101,9 +96,9 @@ class BedrockWorldData extends BaseNbtWorldData{
//Additional PocketMine-MP fields //Additional PocketMine-MP fields
->setTag("GameRules", new CompoundTag()) ->setTag("GameRules", new CompoundTag())
->setByte("hardcore", ($options["hardcore"] ?? false) === true ? 1 : 0) ->setByte("hardcore", 0)
->setString("generatorName", GeneratorManager::getInstance()->getGeneratorName($generator)) ->setString("generatorName", GeneratorManager::getInstance()->getGeneratorName($options->getGeneratorClass()))
->setString("generatorOptions", $options["preset"] ?? ""); ->setString("generatorOptions", $options->getGeneratorOptions());
$nbt = new LittleEndianNbtSerializer(); $nbt = new LittleEndianNbtSerializer();
$buffer = $nbt->write(new TreeRoot($worldData)); $buffer = $nbt->write(new TreeRoot($worldData));

View File

@ -29,11 +29,10 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\nbt\TreeRoot; use pocketmine\nbt\TreeRoot;
use pocketmine\utils\Utils;
use pocketmine\world\format\io\exception\CorruptedWorldException; use pocketmine\world\format\io\exception\CorruptedWorldException;
use pocketmine\world\generator\Generator;
use pocketmine\world\generator\GeneratorManager; use pocketmine\world\generator\GeneratorManager;
use pocketmine\world\World; use pocketmine\world\World;
use pocketmine\world\WorldCreationOptions;
use function ceil; use function ceil;
use function file_get_contents; use function file_get_contents;
use function file_put_contents; use function file_put_contents;
@ -44,31 +43,27 @@ use const ZLIB_ENCODING_GZIP;
class JavaWorldData extends BaseNbtWorldData{ class JavaWorldData extends BaseNbtWorldData{
/** public static function generate(string $path, string $name, ?WorldCreationOptions $options = null, int $version = 19133) : void{
* @param mixed[] $options
* @phpstan-param class-string<Generator> $generator
* @phpstan-param array<string, mixed> $options
*/
public static function generate(string $path, string $name, int $seed, string $generator, array $options = [], int $version = 19133) : void{
Utils::testValidInstance($generator, Generator::class);
//TODO, add extra details //TODO, add extra details
$options ??= WorldCreationOptions::create();
$worldData = CompoundTag::create() $worldData = CompoundTag::create()
->setByte("hardcore", ($options["hardcore"] ?? false) === true ? 1 : 0) ->setByte("hardcore", 0)
->setByte("Difficulty", World::getDifficultyFromString((string) ($options["difficulty"] ?? "normal"))) ->setByte("Difficulty", $options->getDifficulty())
->setByte("initialized", 1) ->setByte("initialized", 1)
->setInt("GameType", 0) ->setInt("GameType", 0)
->setInt("generatorVersion", 1) //2 in MCPE ->setInt("generatorVersion", 1) //2 in MCPE
->setInt("SpawnX", 256) ->setInt("SpawnX", $options->getSpawnPosition()->getFloorX())
->setInt("SpawnY", 70) ->setInt("SpawnY", $options->getSpawnPosition()->getFloorY())
->setInt("SpawnZ", 256) ->setInt("SpawnZ", $options->getSpawnPosition()->getFloorZ())
->setInt("version", $version) ->setInt("version", $version)
->setInt("DayTime", 0) ->setInt("DayTime", 0)
->setLong("LastPlayed", (int) (microtime(true) * 1000)) ->setLong("LastPlayed", (int) (microtime(true) * 1000))
->setLong("RandomSeed", $seed) ->setLong("RandomSeed", $options->getSeed())
->setLong("SizeOnDisk", 0) ->setLong("SizeOnDisk", 0)
->setLong("Time", 0) ->setLong("Time", 0)
->setString("generatorName", GeneratorManager::getInstance()->getGeneratorName($generator)) ->setString("generatorName", GeneratorManager::getInstance()->getGeneratorName($options->getGeneratorClass()))
->setString("generatorOptions", $options["preset"] ?? "") ->setString("generatorOptions", $options->getGeneratorOptions())
->setString("LevelName", $name) ->setString("LevelName", $name)
->setTag("GameRules", new CompoundTag()); ->setTag("GameRules", new CompoundTag());

View File

@ -32,7 +32,6 @@ use pocketmine\nbt\TreeRoot;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\BinaryDataException; use pocketmine\utils\BinaryDataException;
use pocketmine\utils\BinaryStream; use pocketmine\utils\BinaryStream;
use pocketmine\utils\Utils;
use pocketmine\world\format\BiomeArray; use pocketmine\world\format\BiomeArray;
use pocketmine\world\format\Chunk; use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\BaseWorldProvider; use pocketmine\world\format\io\BaseWorldProvider;
@ -46,7 +45,7 @@ use pocketmine\world\format\io\WorldData;
use pocketmine\world\format\io\WritableWorldProvider; use pocketmine\world\format\io\WritableWorldProvider;
use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\format\PalettedBlockArray;
use pocketmine\world\format\SubChunk; use pocketmine\world\format\SubChunk;
use pocketmine\world\generator\Generator; use pocketmine\world\WorldCreationOptions;
use function array_map; use function array_map;
use function array_values; use function array_values;
use function chr; use function chr;
@ -144,15 +143,14 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
return file_exists($path . "/level.dat") and is_dir($path . "/db/"); return file_exists($path . "/level.dat") and is_dir($path . "/db/");
} }
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []) : void{ public static function generate(string $path, string $name, ?WorldCreationOptions $options = null) : void{
Utils::testValidInstance($generator, Generator::class);
self::checkForLevelDBExtension(); self::checkForLevelDBExtension();
if(!file_exists($path . "/db")){ if(!file_exists($path . "/db")){
mkdir($path . "/db", 0777, true); mkdir($path . "/db", 0777, true);
} }
BedrockWorldData::generate($path, $name, $seed, $generator, $options); BedrockWorldData::generate($path, $name, $options);
} }
protected function deserializePaletted(BinaryStream $stream) : PalettedBlockArray{ protected function deserializePaletted(BinaryStream $stream) : PalettedBlockArray{

View File

@ -90,7 +90,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
mkdir($path . "/region", 0777); mkdir($path . "/region", 0777);
} }
JavaWorldData::generate($path, $name, $seed, $generator, $options, static::getPcWorldFormatVersion()); JavaWorldData::generate($path, $name, null, static::getPcWorldFormatVersion());
} }
/** @var RegionLoader[] */ /** @var RegionLoader[] */