mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-10-16 19:59:11 +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:
@@ -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{
|
||||
|
Reference in New Issue
Block a user