mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-07 12:18:46 +00:00
Extract GeneratorExecutor system from World, v2 (#6682)
- `AsyncGeneratorExecutor` class added that encapsulates the logic of generating chunks using async tasks as previously - `GeneratorExecutor` interface added that can be implemented to provide chunks in other ways - `SyncGeneratorExecutor` which invokes the generator directly on the main thread, useful for simple generators like `Flat` where async tasks are not needed - Some redundant APIs were removed from `World` (these will probably come back as deprecated stubs for the remainder of 5.x, but I was having too much fun deleting code) - Removed internal `World->registerGeneratorToWorker()` (no longer useful) - `World` now invokes generator executor instead of posting AsyncTasks directly - Some internal classes moved to `pocketmine\world\generator\executor` (PopulationTask excluded because plugins use it in lieu of being able to regenerate chunks - Generators can opt into main-thread execution by setting the `$fast` parameter to `true` in `GeneratorManager::register()`
This commit is contained in:
parent
dd17adeaaf
commit
059f4ee7bf
@ -93,9 +93,11 @@ use pocketmine\world\format\io\GlobalBlockStateHandlers;
|
||||
use pocketmine\world\format\io\WritableWorldProvider;
|
||||
use pocketmine\world\format\LightArray;
|
||||
use pocketmine\world\format\SubChunk;
|
||||
use pocketmine\world\generator\executor\AsyncGeneratorExecutor;
|
||||
use pocketmine\world\generator\executor\GeneratorExecutor;
|
||||
use pocketmine\world\generator\executor\GeneratorExecutorSetupParameters;
|
||||
use pocketmine\world\generator\executor\SyncGeneratorExecutor;
|
||||
use pocketmine\world\generator\GeneratorManager;
|
||||
use pocketmine\world\generator\GeneratorRegisterTask;
|
||||
use pocketmine\world\generator\GeneratorUnregisterTask;
|
||||
use pocketmine\world\generator\PopulationTask;
|
||||
use pocketmine\world\light\BlockLightUpdate;
|
||||
use pocketmine\world\light\LightPopulationTask;
|
||||
@ -336,11 +338,7 @@ class World implements ChunkManager{
|
||||
*/
|
||||
private array $chunkPopulationRequestQueueIndex = [];
|
||||
|
||||
/**
|
||||
* @var true[]
|
||||
* @phpstan-var array<int, true>
|
||||
*/
|
||||
private array $generatorRegisteredWorkers = [];
|
||||
private readonly GeneratorExecutor $generatorExecutor;
|
||||
|
||||
private bool $autoSave = true;
|
||||
|
||||
@ -360,9 +358,6 @@ class World implements ChunkManager{
|
||||
|
||||
private bool $doingTick = false;
|
||||
|
||||
/** @phpstan-var class-string<generator\Generator> */
|
||||
private string $generator;
|
||||
|
||||
private bool $unloaded = false;
|
||||
/**
|
||||
* @var \Closure[]
|
||||
@ -498,7 +493,23 @@ class World implements ChunkManager{
|
||||
$generator = GeneratorManager::getInstance()->getGenerator($this->provider->getWorldData()->getGenerator()) ??
|
||||
throw new AssumptionFailedError("WorldManager should already have checked that the generator exists");
|
||||
$generator->validateGeneratorOptions($this->provider->getWorldData()->getGeneratorOptions());
|
||||
$this->generator = $generator->getGeneratorClass();
|
||||
|
||||
$executorSetupParameters = new GeneratorExecutorSetupParameters(
|
||||
worldMinY: $this->minY,
|
||||
worldMaxY: $this->maxY,
|
||||
generatorSeed: $this->getSeed(),
|
||||
generatorClass: $generator->getGeneratorClass(),
|
||||
generatorSettings: $this->provider->getWorldData()->getGeneratorOptions()
|
||||
);
|
||||
$this->generatorExecutor = $generator->isFast() ?
|
||||
new SyncGeneratorExecutor($executorSetupParameters) :
|
||||
new AsyncGeneratorExecutor(
|
||||
$this->logger,
|
||||
$this->workerPool,
|
||||
$executorSetupParameters,
|
||||
$this->worldId
|
||||
);
|
||||
|
||||
$this->chunkPopulationRequestQueue = new \SplQueue();
|
||||
$this->addOnUnloadCallback(function() : void{
|
||||
$this->logger->debug("Cancelling unfulfilled generation requests");
|
||||
@ -534,17 +545,6 @@ class World implements ChunkManager{
|
||||
$this->initRandomTickBlocksFromConfig($cfg);
|
||||
|
||||
$this->timings = new WorldTimings($this);
|
||||
|
||||
$this->workerPool->addWorkerStartHook($workerStartHook = function(int $workerId) : void{
|
||||
if(array_key_exists($workerId, $this->generatorRegisteredWorkers)){
|
||||
$this->logger->debug("Worker $workerId with previously registered generator restarted, flagging as unregistered");
|
||||
unset($this->generatorRegisteredWorkers[$workerId]);
|
||||
}
|
||||
});
|
||||
$workerPool = $this->workerPool;
|
||||
$this->addOnUnloadCallback(static function() use ($workerPool, $workerStartHook) : void{
|
||||
$workerPool->removeWorkerStartHook($workerStartHook);
|
||||
});
|
||||
}
|
||||
|
||||
private function initRandomTickBlocksFromConfig(ServerConfigGroup $cfg) : void{
|
||||
@ -585,21 +585,6 @@ class World implements ChunkManager{
|
||||
return $this->tickRateTime;
|
||||
}
|
||||
|
||||
public function registerGeneratorToWorker(int $worker) : void{
|
||||
$this->logger->debug("Registering generator on worker $worker");
|
||||
$this->workerPool->submitTaskToWorker(new GeneratorRegisterTask($this, $this->generator, $this->provider->getWorldData()->getGeneratorOptions()), $worker);
|
||||
$this->generatorRegisteredWorkers[$worker] = true;
|
||||
}
|
||||
|
||||
public function unregisterGenerator() : void{
|
||||
foreach($this->workerPool->getRunningWorkers() as $i){
|
||||
if(isset($this->generatorRegisteredWorkers[$i])){
|
||||
$this->workerPool->submitTaskToWorker(new GeneratorUnregisterTask($this), $i);
|
||||
}
|
||||
}
|
||||
$this->generatorRegisteredWorkers = [];
|
||||
}
|
||||
|
||||
public function getServer() : Server{
|
||||
return $this->server;
|
||||
}
|
||||
@ -657,7 +642,7 @@ class World implements ChunkManager{
|
||||
|
||||
$this->save();
|
||||
|
||||
$this->unregisterGenerator();
|
||||
$this->generatorExecutor->shutdown();
|
||||
|
||||
$this->provider->close();
|
||||
$this->blockCache = [];
|
||||
@ -3486,8 +3471,8 @@ class World implements ChunkManager{
|
||||
|
||||
$centerChunk = $this->loadChunk($chunkX, $chunkZ);
|
||||
$adjacentChunks = $this->getAdjacentChunks($chunkX, $chunkZ);
|
||||
$task = new PopulationTask(
|
||||
$this->worldId,
|
||||
|
||||
$this->generatorExecutor->populate(
|
||||
$chunkX,
|
||||
$chunkZ,
|
||||
$centerChunk,
|
||||
@ -3500,15 +3485,6 @@ class World implements ChunkManager{
|
||||
$this->generateChunkCallback($chunkPopulationLockId, $chunkX, $chunkZ, $centerChunk, $adjacentChunks, $temporaryChunkLoader);
|
||||
}
|
||||
);
|
||||
$workerId = $this->workerPool->selectWorker();
|
||||
if(!isset($this->workerPool->getRunningWorkers()[$workerId]) && isset($this->generatorRegisteredWorkers[$workerId])){
|
||||
$this->logger->debug("Selected worker $workerId previously had generator registered, but is now offline");
|
||||
unset($this->generatorRegisteredWorkers[$workerId]);
|
||||
}
|
||||
if(!isset($this->generatorRegisteredWorkers[$workerId])){
|
||||
$this->registerGeneratorToWorker($workerId);
|
||||
}
|
||||
$this->workerPool->submitTaskToWorker($task, $workerId);
|
||||
|
||||
return $resolver->getPromise();
|
||||
}finally{
|
||||
|
@ -50,7 +50,7 @@ final class GeneratorManager{
|
||||
}catch(InvalidGeneratorOptionsException $e){
|
||||
return $e;
|
||||
}
|
||||
});
|
||||
}, fast: true);
|
||||
$this->addGenerator(Normal::class, "normal", fn() => null);
|
||||
$this->addAlias("normal", "default");
|
||||
$this->addGenerator(Nether::class, "nether", fn() => null);
|
||||
@ -62,6 +62,7 @@ final class GeneratorManager{
|
||||
* @param string $name Alias for this generator type that can be written in configs
|
||||
* @param \Closure $presetValidator Callback to validate generator options for new worlds
|
||||
* @param bool $overwrite Whether to force overwriting any existing registered generator with the same name
|
||||
* @param bool $fast Whether this generator is fast enough to run without async tasks
|
||||
*
|
||||
* @phpstan-param \Closure(string) : ?InvalidGeneratorOptionsException $presetValidator
|
||||
*
|
||||
@ -69,7 +70,7 @@ final class GeneratorManager{
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function addGenerator(string $class, string $name, \Closure $presetValidator, bool $overwrite = false) : void{
|
||||
public function addGenerator(string $class, string $name, \Closure $presetValidator, bool $overwrite = false, bool $fast = false) : void{
|
||||
Utils::testValidInstance($class, Generator::class);
|
||||
|
||||
$name = strtolower($name);
|
||||
@ -77,7 +78,7 @@ final class GeneratorManager{
|
||||
throw new \InvalidArgumentException("Alias \"$name\" is already assigned");
|
||||
}
|
||||
|
||||
$this->list[$name] = new GeneratorManagerEntry($class, $presetValidator);
|
||||
$this->list[$name] = new GeneratorManagerEntry($class, $presetValidator, $fast);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,12 +31,15 @@ final class GeneratorManagerEntry{
|
||||
*/
|
||||
public function __construct(
|
||||
private string $generatorClass,
|
||||
private \Closure $presetValidator
|
||||
private \Closure $presetValidator,
|
||||
private readonly bool $fast
|
||||
){}
|
||||
|
||||
/** @phpstan-return class-string<Generator> */
|
||||
public function getGeneratorClass() : string{ return $this->generatorClass; }
|
||||
|
||||
public function isFast() : bool{ return $this->fast; }
|
||||
|
||||
/**
|
||||
* @throws InvalidGeneratorOptionsException
|
||||
*/
|
||||
|
@ -27,11 +27,18 @@ use pocketmine\scheduler\AsyncTask;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\format\io\FastChunkSerializer;
|
||||
use pocketmine\world\generator\executor\ThreadLocalGeneratorContext;
|
||||
use function array_map;
|
||||
use function igbinary_serialize;
|
||||
use function igbinary_unserialize;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* TODO: this should be moved to the executor namespace, but plugins have unfortunately used it directly due to the
|
||||
* difficulty of regenerating chunks. This should be addressed in the future.
|
||||
* For the remainder of PM5, we can't relocate this class.
|
||||
*
|
||||
* @phpstan-type OnCompletion \Closure(Chunk $centerChunk, array<int, Chunk> $adjacentChunks) : void
|
||||
*/
|
||||
class PopulationTask extends AsyncTask{
|
||||
|
106
src/world/generator/executor/AsyncGeneratorExecutor.php
Normal file
106
src/world/generator/executor/AsyncGeneratorExecutor.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?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\generator\executor;
|
||||
|
||||
use pocketmine\scheduler\AsyncPool;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\generator\PopulationTask;
|
||||
use function array_key_exists;
|
||||
|
||||
final class AsyncGeneratorExecutor implements GeneratorExecutor{
|
||||
private static int $nextAsyncContextId = 1;
|
||||
|
||||
private readonly \Logger $logger;
|
||||
|
||||
/** @phpstan-var \Closure(int) : void */
|
||||
private readonly \Closure $workerStartHook;
|
||||
|
||||
private readonly int $asyncContextId;
|
||||
|
||||
/**
|
||||
* @var true[]
|
||||
* @phpstan-var array<int, true>
|
||||
*/
|
||||
private array $generatorRegisteredWorkers = [];
|
||||
|
||||
public function __construct(
|
||||
\Logger $logger,
|
||||
private readonly AsyncPool $workerPool,
|
||||
private readonly GeneratorExecutorSetupParameters $setupParameters,
|
||||
int $asyncContextId = null
|
||||
){
|
||||
$this->logger = new \PrefixedLogger($logger, "AsyncGeneratorExecutor");
|
||||
|
||||
//TODO: we only allow setting this for PM5 because of PopulationTask uses in plugins
|
||||
$this->asyncContextId = $asyncContextId ?? self::$nextAsyncContextId++;
|
||||
|
||||
$this->workerStartHook = function(int $workerId) : void{
|
||||
if(array_key_exists($workerId, $this->generatorRegisteredWorkers)){
|
||||
$this->logger->debug("Worker $workerId with previously registered generator restarted, flagging as unregistered");
|
||||
unset($this->generatorRegisteredWorkers[$workerId]);
|
||||
}
|
||||
};
|
||||
$this->workerPool->addWorkerStartHook($this->workerStartHook);
|
||||
}
|
||||
|
||||
private function registerGeneratorToWorker(int $worker) : void{
|
||||
$this->logger->debug("Registering generator on worker $worker");
|
||||
$this->workerPool->submitTaskToWorker(new AsyncGeneratorRegisterTask($this->setupParameters, $this->asyncContextId), $worker);
|
||||
$this->generatorRegisteredWorkers[$worker] = true;
|
||||
}
|
||||
|
||||
private function unregisterGenerator() : void{
|
||||
foreach($this->workerPool->getRunningWorkers() as $i){
|
||||
if(isset($this->generatorRegisteredWorkers[$i])){
|
||||
$this->workerPool->submitTaskToWorker(new AsyncGeneratorUnregisterTask($this->asyncContextId), $i);
|
||||
}
|
||||
}
|
||||
$this->generatorRegisteredWorkers = [];
|
||||
}
|
||||
|
||||
public function populate(int $chunkX, int $chunkZ, ?Chunk $centerChunk, array $adjacentChunks, \Closure $onCompletion) : void{
|
||||
$task = new PopulationTask(
|
||||
$this->asyncContextId,
|
||||
$chunkX,
|
||||
$chunkZ,
|
||||
$centerChunk,
|
||||
$adjacentChunks,
|
||||
$onCompletion
|
||||
);
|
||||
$workerId = $this->workerPool->selectWorker();
|
||||
if(!isset($this->workerPool->getRunningWorkers()[$workerId]) && isset($this->generatorRegisteredWorkers[$workerId])){
|
||||
$this->logger->debug("Selected worker $workerId previously had generator registered, but is now offline");
|
||||
unset($this->generatorRegisteredWorkers[$workerId]);
|
||||
}
|
||||
if(!isset($this->generatorRegisteredWorkers[$workerId])){
|
||||
$this->registerGeneratorToWorker($workerId);
|
||||
}
|
||||
$this->workerPool->submitTaskToWorker($task, $workerId);
|
||||
}
|
||||
|
||||
public function shutdown() : void{
|
||||
$this->unregisterGenerator();
|
||||
$this->workerPool->removeWorkerStartHook($this->workerStartHook);
|
||||
}
|
||||
}
|
@ -21,37 +21,20 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\generator;
|
||||
namespace pocketmine\world\generator\executor;
|
||||
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
use pocketmine\world\World;
|
||||
|
||||
class GeneratorRegisterTask extends AsyncTask{
|
||||
public int $seed;
|
||||
public int $worldId;
|
||||
public int $worldMinY;
|
||||
public int $worldMaxY;
|
||||
class AsyncGeneratorRegisterTask extends AsyncTask{
|
||||
|
||||
/**
|
||||
* @phpstan-param class-string<Generator> $generatorClass
|
||||
*/
|
||||
public function __construct(
|
||||
World $world,
|
||||
public string $generatorClass,
|
||||
public string $generatorSettings
|
||||
){
|
||||
$this->seed = $world->getSeed();
|
||||
$this->worldId = $world->getId();
|
||||
$this->worldMinY = $world->getMinY();
|
||||
$this->worldMaxY = $world->getMaxY();
|
||||
}
|
||||
private readonly GeneratorExecutorSetupParameters $setupParameters,
|
||||
private readonly int $contextId
|
||||
){}
|
||||
|
||||
public function onRun() : void{
|
||||
/**
|
||||
* @var Generator $generator
|
||||
* @see Generator::__construct()
|
||||
*/
|
||||
$generator = new $this->generatorClass($this->seed, $this->generatorSettings);
|
||||
ThreadLocalGeneratorContext::register(new ThreadLocalGeneratorContext($generator, $this->worldMinY, $this->worldMaxY), $this->worldId);
|
||||
$setupParameters = $this->setupParameters;
|
||||
$generator = $setupParameters->createGenerator();
|
||||
ThreadLocalGeneratorContext::register(new ThreadLocalGeneratorContext($generator, $setupParameters->worldMinY, $setupParameters->worldMaxY), $this->contextId);
|
||||
}
|
||||
}
|
@ -21,19 +21,16 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\generator;
|
||||
namespace pocketmine\world\generator\executor;
|
||||
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
use pocketmine\world\World;
|
||||
|
||||
class GeneratorUnregisterTask extends AsyncTask{
|
||||
public int $worldId;
|
||||
|
||||
public function __construct(World $world){
|
||||
$this->worldId = $world->getId();
|
||||
}
|
||||
class AsyncGeneratorUnregisterTask extends AsyncTask{
|
||||
public function __construct(
|
||||
private readonly int $contextId
|
||||
){}
|
||||
|
||||
public function onRun() : void{
|
||||
ThreadLocalGeneratorContext::unregister($this->worldId);
|
||||
ThreadLocalGeneratorContext::unregister($this->contextId);
|
||||
}
|
||||
}
|
38
src/world/generator/executor/GeneratorExecutor.php
Normal file
38
src/world/generator/executor/GeneratorExecutor.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?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\generator\executor;
|
||||
|
||||
use pocketmine\world\format\Chunk;
|
||||
|
||||
interface GeneratorExecutor{
|
||||
/**
|
||||
* @param Chunk[]|null[] $adjacentChunks
|
||||
* @phpstan-param array<int, Chunk|null> $adjacentChunks
|
||||
* @phpstan-param \Closure(Chunk $centerChunk, array<int, Chunk> $adjacentChunks) : void $onCompletion
|
||||
*/
|
||||
public function populate(int $chunkX, int $chunkZ, ?Chunk $centerChunk, array $adjacentChunks, \Closure $onCompletion) : void;
|
||||
|
||||
public function shutdown() : void;
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
<?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\generator\executor;
|
||||
|
||||
use pmmp\thread\ThreadSafe;
|
||||
use pocketmine\world\generator\Generator;
|
||||
|
||||
final class GeneratorExecutorSetupParameters extends ThreadSafe{
|
||||
|
||||
/**
|
||||
* @phpstan-param class-string<covariant \pocketmine\world\generator\Generator> $generatorClass
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly int $worldMinY,
|
||||
public readonly int $worldMaxY,
|
||||
public readonly int $generatorSeed,
|
||||
public readonly string $generatorClass,
|
||||
public readonly string $generatorSettings,
|
||||
){}
|
||||
|
||||
public function createGenerator() : Generator{
|
||||
/**
|
||||
* @var Generator $generator
|
||||
* @see Generator::__construct()
|
||||
*/
|
||||
$generator = new $this->generatorClass($this->generatorSeed, $this->generatorSettings);
|
||||
return $generator;
|
||||
}
|
||||
}
|
61
src/world/generator/executor/SyncGeneratorExecutor.php
Normal file
61
src/world/generator/executor/SyncGeneratorExecutor.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?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\generator\executor;
|
||||
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\generator\Generator;
|
||||
use pocketmine\world\generator\PopulationUtils;
|
||||
|
||||
final class SyncGeneratorExecutor implements GeneratorExecutor{
|
||||
|
||||
private readonly Generator $generator;
|
||||
private readonly int $worldMinY;
|
||||
private readonly int $worldMaxY;
|
||||
|
||||
public function __construct(
|
||||
GeneratorExecutorSetupParameters $setupParameters
|
||||
){
|
||||
$this->generator = $setupParameters->createGenerator();
|
||||
$this->worldMinY = $setupParameters->worldMinY;
|
||||
$this->worldMaxY = $setupParameters->worldMaxY;
|
||||
}
|
||||
|
||||
public function populate(int $chunkX, int $chunkZ, ?Chunk $centerChunk, array $adjacentChunks, \Closure $onCompletion) : void{
|
||||
[$centerChunk, $adjacentChunks] = PopulationUtils::populateChunkWithAdjacents(
|
||||
$this->worldMinY,
|
||||
$this->worldMaxY,
|
||||
$this->generator,
|
||||
$chunkX,
|
||||
$chunkZ,
|
||||
$centerChunk,
|
||||
$adjacentChunks
|
||||
);
|
||||
|
||||
$onCompletion($centerChunk, $adjacentChunks);
|
||||
}
|
||||
|
||||
public function shutdown() : void{
|
||||
//NOOP
|
||||
}
|
||||
}
|
@ -21,7 +21,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\generator;
|
||||
namespace pocketmine\world\generator\executor;
|
||||
|
||||
use pocketmine\world\generator\Generator;
|
||||
|
||||
/**
|
||||
* Manages thread-local caches for generators and the things needed to support them
|
@ -1272,18 +1272,18 @@ parameters:
|
||||
count: 1
|
||||
path: ../../../src/world/format/io/region/RegionLoader.php
|
||||
|
||||
-
|
||||
message: '#^Dynamic new is not allowed\.$#'
|
||||
identifier: pocketmine.new.dynamic
|
||||
count: 1
|
||||
path: ../../../src/world/generator/GeneratorRegisterTask.php
|
||||
|
||||
-
|
||||
message: '#^Method pocketmine\\world\\generator\\biome\\BiomeSelector\:\:pickBiome\(\) should return pocketmine\\world\\biome\\Biome but returns pocketmine\\world\\biome\\Biome\|null\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: ../../../src/world/generator/biome/BiomeSelector.php
|
||||
|
||||
-
|
||||
message: '#^Dynamic new is not allowed\.$#'
|
||||
identifier: pocketmine.new.dynamic
|
||||
count: 1
|
||||
path: ../../../src/world/generator/executor/GeneratorExecutorSetupParameters.php
|
||||
|
||||
-
|
||||
message: '#^Cannot call method getBiomeId\(\) on pocketmine\\world\\format\\Chunk\|null\.$#'
|
||||
identifier: method.nonObject
|
||||
|
Loading…
x
Reference in New Issue
Block a user