PocketMine-MP 5.15.1 git-5ef247620a7c6301a849b54e5ef1009217729fc8
PopulationTask.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
25
32use function array_map;
33use function igbinary_serialize;
34use function igbinary_unserialize;
35
40 private const TLS_KEY_ON_COMPLETION = "onCompletion";
41
42 private ?string $chunk;
43
44 private string $adjacentChunks;
45
51 public function __construct(
52 private int $worldId,
53 private int $chunkX,
54 private int $chunkZ,
55 ?Chunk $chunk,
56 array $adjacentChunks,
57 \Closure $onCompletion
58 ){
59 $this->chunk = $chunk !== null ? FastChunkSerializer::serializeTerrain($chunk) : null;
60
61 $this->adjacentChunks = igbinary_serialize(array_map(
62 fn(?Chunk $c) => $c !== null ? FastChunkSerializer::serializeTerrain($c) : null,
63 $adjacentChunks
64 )) ?? throw new AssumptionFailedError("igbinary_serialize() returned null");
65
66 $this->storeLocal(self::TLS_KEY_ON_COMPLETION, $onCompletion);
67 }
68
69 public function onRun() : void{
70 $context = ThreadLocalGeneratorContext::fetch($this->worldId);
71 if($context === null){
72 throw new AssumptionFailedError("Generator context should have been initialized before any PopulationTask execution");
73 }
74 $generator = $context->getGenerator();
75 $manager = new SimpleChunkManager($context->getWorldMinY(), $context->getWorldMaxY());
76
77 $chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : null;
78
80 $serialChunks = igbinary_unserialize($this->adjacentChunks);
81 $chunks = array_map(
82 function(?string $serialized) : ?Chunk{
83 if($serialized === null){
84 return null;
85 }
86 $chunk = FastChunkSerializer::deserializeTerrain($serialized);
87 $chunk->clearTerrainDirtyFlags(); //this allows us to avoid sending existing chunks back to the main thread if they haven't changed during generation
88 return $chunk;
89 },
90 $serialChunks
91 );
92
93 self::setOrGenerateChunk($manager, $generator, $this->chunkX, $this->chunkZ, $chunk);
94
96 $resultChunks = []; //this is just to keep phpstan's type inference happy
97 foreach($chunks as $relativeChunkHash => $c){
98 World::getXZ($relativeChunkHash, $relativeX, $relativeZ);
99 $resultChunks[$relativeChunkHash] = self::setOrGenerateChunk($manager, $generator, $this->chunkX + $relativeX, $this->chunkZ + $relativeZ, $c);
100 }
101 $chunks = $resultChunks;
102
103 $generator->populateChunk($manager, $this->chunkX, $this->chunkZ);
104 $chunk = $manager->getChunk($this->chunkX, $this->chunkZ);
105 if($chunk === null){
106 throw new AssumptionFailedError("We just generated this chunk, so it must exist");
107 }
108 $chunk->setPopulated();
109
110 $this->chunk = FastChunkSerializer::serializeTerrain($chunk);
111
112 $serialChunks = [];
113 foreach($chunks as $relativeChunkHash => $c){
114 $serialChunks[$relativeChunkHash] = $c->isTerrainDirty() ? FastChunkSerializer::serializeTerrain($c) : null;
115 }
116 $this->adjacentChunks = igbinary_serialize($serialChunks) ?? throw new AssumptionFailedError("igbinary_serialize() returned null");
117 }
118
119 private static function setOrGenerateChunk(SimpleChunkManager $manager, Generator $generator, int $chunkX, int $chunkZ, ?Chunk $chunk) : Chunk{
120 $manager->setChunk($chunkX, $chunkZ, $chunk ?? new Chunk([], false));
121 if($chunk === null){
122 $generator->generateChunk($manager, $chunkX, $chunkZ);
123 $chunk = $manager->getChunk($chunkX, $chunkZ);
124 if($chunk === null){
125 throw new AssumptionFailedError("We just set this chunk, so it must exist");
126 }
127 }
128 return $chunk;
129 }
130
131 public function onCompletion() : void{
136 $onCompletion = $this->fetchLocal(self::TLS_KEY_ON_COMPLETION);
137
138 $chunk = $this->chunk !== null ?
139 FastChunkSerializer::deserializeTerrain($this->chunk) :
140 throw new AssumptionFailedError("Center chunk should never be null");
141
146 $serialAdjacentChunks = igbinary_unserialize($this->adjacentChunks);
147 $adjacentChunks = [];
148 foreach($serialAdjacentChunks as $relativeChunkHash => $c){
149 if($c !== null){
150 $adjacentChunks[$relativeChunkHash] = FastChunkSerializer::deserializeTerrain($c);
151 }
152 }
153
154 $onCompletion($chunk, $adjacentChunks);
155 }
156}
storeLocal(string $key, mixed $complexData)
Definition: AsyncTask.php:214
static getXZ(int $hash, ?int &$x, ?int &$z)
Definition: World.php:441
__construct(private int $worldId, private int $chunkX, private int $chunkZ, ?Chunk $chunk, array $adjacentChunks, \Closure $onCompletion)